package sshkey import ( "crypto/sha256" "encoding/base64" "encoding/binary" "errors" "slices" ) const ( MaxPerAccount = 10 MinRSABits = 3072 MaxLineBytes = 16 << 10 ) var ( ErrNotOneLine = errors.New("sshkey: more than one line") ErrNotAKey = errors.New("sshkey: not an OpenSSH public key") ErrOptions = errors.New("sshkey: the line carries authorized_keys options") ErrCertificate = errors.New("sshkey: a certificate, not a key") ErrKeyType = errors.New("sshkey: the key type is not accepted") ErrShortRSA = errors.New("sshkey: the RSA key is shorter than 3072 bits") ErrLabel = errors.New("sshkey: the label is not valid") ErrOwned = errors.New("sshkey: the key is on this account already") ErrTaken = errors.New("sshkey: the key is on another account") ErrLimit = errors.New("sshkey: the account holds as many keys as it may") ) var Types = []string{ "ssh-ed25519", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "ssh-rsa", "sk-ssh-ed25519@openssh.com", "sk-ecdsa-sha2-nistp256@openssh.com", } type Key struct { Type string Data []byte Fingerprint string Comment string } func (k Key) Authorized() string { return Authorized(k.Type, k.Data) } func Authorized(keyType string, data []byte) string { return keyType + " " + base64.StdEncoding.EncodeToString(data) } func Fingerprint(data []byte) string { sum := sha256.Sum256(data) return "SHA256:" + base64.RawStdEncoding.EncodeToString(sum[:]) } func Check(keyType string, data []byte) error { if !slices.Contains(Types, keyType) { return ErrKeyType } n := len(keyType) if len(data) <= 4+n || binary.BigEndian.Uint32(data) != uint32(n) || string(data[4:4+n]) != keyType { return ErrNotAKey } return nil }