Source File
keys.go
Belonging Package
golang.org/x/crypto/ssh
package ssh
import (
)
const (
KeyAlgoRSA = "ssh-rsa"
KeyAlgoDSA = "ssh-dss"
KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
)
const (
SigAlgoRSA = "ssh-rsa"
SigAlgoRSASHA2256 = "rsa-sha2-256"
SigAlgoRSASHA2512 = "rsa-sha2-512"
)
func ( []byte, string) ( PublicKey, []byte, error) {
switch {
case KeyAlgoRSA:
return parseRSA()
case KeyAlgoDSA:
return parseDSA()
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
return parseECDSA()
case KeyAlgoSKECDSA256:
return parseSKECDSA()
case KeyAlgoED25519:
return parseED25519()
case KeyAlgoSKED25519:
return parseSKEd25519()
case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
, := parseCert(, certToPrivAlgo())
if != nil {
return nil, nil,
}
return , nil, nil
}
return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", )
}
func ( []byte) ( PublicKey, string, error) {
= bytes.TrimSpace()
:= bytes.IndexAny(, " \t")
if == -1 {
= len()
}
:= [:]
:= make([]byte, base64.StdEncoding.DecodedLen(len()))
, := base64.StdEncoding.Decode(, )
if != nil {
return nil, "",
}
= [:]
, = ParsePublicKey()
if != nil {
return nil, "",
}
= string(bytes.TrimSpace([:]))
return , , nil
}
func ( []byte) ( string, []string, PublicKey, string, []byte, error) {
for len() > 0 {
:= bytes.IndexByte(, '\n')
if != -1 {
= [+1:]
= [:]
} else {
= nil
}
= bytes.IndexByte(, '\r')
if != -1 {
= [:]
}
= bytes.TrimSpace()
if len() == 0 || [0] == '#' {
=
continue
}
:= bytes.IndexAny(, " \t")
if == -1 {
=
continue
}
:= ""
if [0][0] == '@' {
= string([0][1:])
= [1:]
}
func ( []byte) ( PublicKey, string, []string, []byte, error) {
for len() > 0 {
:= bytes.IndexByte(, '\n')
if != -1 {
= [+1:]
= [:]
} else {
= nil
}
= bytes.IndexByte(, '\r')
if != -1 {
= [:]
}
= bytes.TrimSpace()
if len() == 0 || [0] == '#' {
=
continue
}
:= bytes.IndexAny(, " \t")
if == -1 {
=
continue
}
if , , = parseAuthorizedKey([:]); == nil {
return , , , , nil
}
func ( []byte) ( PublicKey, error) {
, , := parseString()
if ! {
return nil, errShortRead
}
var []byte
, , = parsePubKey(, string())
if len() > 0 {
return nil, errors.New("ssh: trailing junk in public key")
}
return ,
}
Type() string
Marshal() []byte
type CryptoPublicKey interface {
CryptoPublicKey() crypto.PublicKey
}
PublicKey() PublicKey
type AlgorithmSigner interface {
Signer
func ( []byte) ( PublicKey, []byte, error) {
var struct {
*big.Int
*big.Int
[]byte `ssh:"rest"`
}
if := Unmarshal(, &); != nil {
return nil, nil,
}
if ..BitLen() > 24 {
return nil, nil, errors.New("ssh: exponent too large")
}
:= ..Int64()
if < 3 || &1 == 0 {
return nil, nil, errors.New("ssh: incorrect exponent")
}
var rsa.PublicKey
.E = int()
.N = .
return (*rsaPublicKey)(&), ., nil
}
func ( *rsaPublicKey) () []byte {
:= struct {
string
*big.Int
*big.Int
}{
KeyAlgoRSA,
,
.N,
}
return Marshal(&)
}
func ( *rsaPublicKey) ( []byte, *Signature) error {
var crypto.Hash
switch .Format {
case SigAlgoRSA:
= crypto.SHA1
case SigAlgoRSASHA2256:
= crypto.SHA256
case SigAlgoRSASHA2512:
= crypto.SHA512
default:
return fmt.Errorf("ssh: signature type %s for key type %s", .Format, .Type())
}
:= .New()
.Write()
:= .Sum(nil)
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(), , , .Blob)
}
func ( *rsaPublicKey) () crypto.PublicKey {
return (*rsa.PublicKey)()
}
type dsaPublicKey dsa.PublicKey
func ( *dsaPublicKey) () string {
return "ssh-dss"
}
if len(.Blob) != 40 {
return errors.New("ssh: DSA signature parse error")
}
:= new(big.Int).SetBytes(.Blob[:20])
:= new(big.Int).SetBytes(.Blob[20:])
if dsa.Verify((*dsa.PublicKey)(), , , ) {
return nil
}
return errors.New("ssh: signature did not verify")
}
func ( *dsaPublicKey) () crypto.PublicKey {
return (*dsa.PublicKey)()
}
type dsaPrivateKey struct {
*dsa.PrivateKey
}
func ( *dsaPrivateKey) () PublicKey {
return (*dsaPublicKey)(&.PrivateKey.PublicKey)
}
func ( *dsaPrivateKey) ( io.Reader, []byte) (*Signature, error) {
return .SignWithAlgorithm(, , "")
}
func ( *dsaPrivateKey) ( io.Reader, []byte, string) (*Signature, error) {
if != "" && != .PublicKey().Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", )
}
:= crypto.SHA1.New()
.Write()
:= .Sum(nil)
, , := dsa.Sign(, .PrivateKey, )
if != nil {
return nil,
}
:= make([]byte, 40)
:= .Bytes()
:= .Bytes()
copy([20-len():20], )
copy([40-len():], )
return &Signature{
Format: .PublicKey().Type(),
Blob: ,
}, nil
}
type ecdsaPublicKey ecdsa.PublicKey
func ( *ecdsaPublicKey) () string {
return "ecdsa-sha2-" + .nistID()
}
func ( *ecdsaPublicKey) () string {
switch .Params().BitSize {
case 256:
return "nistp256"
case 384:
return "nistp384"
case 521:
return "nistp521"
}
panic("ssh: unsupported ecdsa key size")
}
type ed25519PublicKey ed25519.PublicKey
func ( ed25519PublicKey) () string {
return KeyAlgoED25519
}
func ( []byte) ( PublicKey, []byte, error) {
var struct {
[]byte
[]byte `ssh:"rest"`
}
if := Unmarshal(, &); != nil {
return nil, nil,
}
if := len(.); != ed25519.PublicKeySize {
return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", )
}
return ed25519PublicKey(.), ., nil
}
func ( ed25519PublicKey) () []byte {
:= struct {
string
[]byte
}{
KeyAlgoED25519,
[]byte(),
}
return Marshal(&)
}
func ( ed25519PublicKey) ( []byte, *Signature) error {
if .Format != .Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", .Format, .Type())
}
if := len(); != ed25519.PublicKeySize {
return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", )
}
if := ed25519.Verify(ed25519.PublicKey(), , .Blob); ! {
return errors.New("ssh: signature did not verify")
}
return nil
}
func ( ed25519PublicKey) () crypto.PublicKey {
return ed25519.PublicKey()
}
func ( elliptic.Curve) bool {
return == elliptic.P256() || == elliptic.P384() || == elliptic.P521()
}
func ( []byte) ( PublicKey, []byte, error) {
var struct {
string
[]byte
[]byte `ssh:"rest"`
}
if := Unmarshal(, &); != nil {
return nil, nil,
}
:= new(ecdsa.PublicKey)
switch . {
case "nistp256":
.Curve = elliptic.P256()
case "nistp384":
.Curve = elliptic.P384()
case "nistp521":
.Curve = elliptic.P521()
default:
return nil, nil, errors.New("ssh: unsupported curve")
}
.X, .Y = elliptic.Unmarshal(.Curve, .)
if .X == nil || .Y == nil {
return nil, nil, errors.New("ssh: invalid curve point")
}
return (*ecdsaPublicKey)(), ., nil
}
application string
ecdsa.PublicKey
}
func ( *skECDSAPublicKey) () string {
return KeyAlgoSKECDSA256
}
func ( *skECDSAPublicKey) () string {
return "nistp256"
}
func ( []byte) ( PublicKey, []byte, error) {
var struct {
string
[]byte
string
[]byte `ssh:"rest"`
}
if := Unmarshal(, &); != nil {
return nil, nil,
}
:= new(skECDSAPublicKey)
.application = .
if . != "nistp256" {
return nil, nil, errors.New("ssh: unsupported curve")
}
.Curve = elliptic.P256()
.X, .Y = elliptic.Unmarshal(.Curve, .)
if .X == nil || .Y == nil {
return nil, nil, errors.New("ssh: invalid curve point")
}
return , ., nil
}
:= elliptic.Marshal(.Curve, .X, .Y)
:= struct {
string
string
[]byte
string
}{
.Type(),
.nistID(),
,
.application,
}
return Marshal(&)
}
func ( *skECDSAPublicKey) ( []byte, *Signature) error {
if .Format != .Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", .Format, .Type())
}
:= ecHash(.Curve).New()
.Write([]byte(.application))
:= .Sum(nil)
.Reset()
.Write()
:= .Sum(nil)
var struct {
*big.Int
*big.Int
}
if := Unmarshal(.Blob, &); != nil {
return
}
var skFields
if := Unmarshal(.Rest, &); != nil {
return
}
:= struct {
[]byte `ssh:"rest"`
byte
uint32
[]byte `ssh:"rest"`
}{
,
.Flags,
.Counter,
,
}
:= Marshal()
.Reset()
.Write()
:= .Sum(nil)
if ecdsa.Verify((*ecdsa.PublicKey)(&.PublicKey), , ., .) {
return nil
}
return errors.New("ssh: signature did not verify")
}
application string
ed25519.PublicKey
}
func ( *skEd25519PublicKey) () string {
return KeyAlgoSKED25519
}
func ( []byte) ( PublicKey, []byte, error) {
var struct {
[]byte
string
[]byte `ssh:"rest"`
}
if := Unmarshal(, &); != nil {
return nil, nil,
}
if := len(.); != ed25519.PublicKeySize {
return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", )
}
:= new(skEd25519PublicKey)
.application = .
.PublicKey = ed25519.PublicKey(.)
return , ., nil
}
func ( *skEd25519PublicKey) () []byte {
:= struct {
string
[]byte
string
}{
KeyAlgoSKED25519,
[]byte(.PublicKey),
.application,
}
return Marshal(&)
}
func ( *skEd25519PublicKey) ( []byte, *Signature) error {
if .Format != .Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", .Format, .Type())
}
if := len(.PublicKey); != ed25519.PublicKeySize {
return fmt.Errorf("invalid size %d for Ed25519 public key", )
}
:= sha256.New()
.Write([]byte(.application))
:= .Sum(nil)
.Reset()
.Write()
:= .Sum(nil)
var struct {
[]byte `ssh:"rest"`
}
if := Unmarshal(.Blob, &); != nil {
return
}
var skFields
if := Unmarshal(.Rest, &); != nil {
return
}
:= struct {
[]byte `ssh:"rest"`
byte
uint32
[]byte `ssh:"rest"`
}{
,
.Flags,
.Counter,
,
}
:= Marshal()
if := ed25519.Verify(.PublicKey, , .); ! {
return errors.New("ssh: signature did not verify")
}
return nil
}
func ( interface{}) (Signer, error) {
switch key := .(type) {
case crypto.Signer:
return NewSignerFromSigner()
case *dsa.PrivateKey:
return newDSAPrivateKey()
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", )
}
}
func ( *dsa.PrivateKey) (Signer, error) {
if := checkDSAParams(&.PublicKey.Parameters); != nil {
return nil,
}
return &dsaPrivateKey{}, nil
}
type wrappedSigner struct {
signer crypto.Signer
pubKey PublicKey
}
func ( crypto.Signer) (Signer, error) {
, := NewPublicKey(.Public())
if != nil {
return nil,
}
return &wrappedSigner{, }, nil
}
func ( *wrappedSigner) () PublicKey {
return .pubKey
}
func ( *wrappedSigner) ( io.Reader, []byte) (*Signature, error) {
return .SignWithAlgorithm(, , "")
}
func ( *wrappedSigner) ( io.Reader, []byte, string) (*Signature, error) {
var crypto.Hash
switch {
case "", SigAlgoRSA:
= SigAlgoRSA
= crypto.SHA1
case SigAlgoRSASHA2256:
= crypto.SHA256
case SigAlgoRSASHA2512:
= crypto.SHA512
default:
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", )
}
if == "" {
= .pubKey.Type()
} else if != .pubKey.Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", )
}
switch key := .pubKey.(type) {
case *dsaPublicKey:
= crypto.SHA1
case *ecdsaPublicKey:
= ecHash(.Curve)
case ed25519PublicKey:
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", )
}
}
var []byte
if != 0 {
:= .New()
.Write()
= .Sum(nil)
} else {
=
}
, := .signer.Sign(, , )
if != nil {
return nil,
}
switch .pubKey.(type) {
case *ecdsaPublicKey, *dsaPublicKey:
type struct {
, *big.Int
}
:= new()
, := asn1.Unmarshal(, )
if != nil {
return nil,
}
switch .pubKey.(type) {
case *ecdsaPublicKey:
= Marshal()
case *dsaPublicKey:
= make([]byte, 40)
:= ..Bytes()
:= ..Bytes()
copy([20-len():20], )
copy([40-len():40], )
}
}
return &Signature{
Format: ,
Blob: ,
}, nil
}
func ( interface{}) (PublicKey, error) {
switch key := .(type) {
case *rsa.PublicKey:
return (*rsaPublicKey)(), nil
case *ecdsa.PublicKey:
if !supportedEllipticCurve(.Curve) {
return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported")
}
return (*ecdsaPublicKey)(), nil
case *dsa.PublicKey:
return (*dsaPublicKey)(), nil
case ed25519.PublicKey:
if := len(); != ed25519.PublicKeySize {
return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", )
}
return ed25519PublicKey(), nil
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", )
}
}
func ( []byte) (Signer, error) {
, := ParseRawPrivateKey()
if != nil {
return nil,
}
return NewSignerFromKey()
}
func (, []byte) (Signer, error) {
, := ParseRawPrivateKeyWithPassphrase(, )
if != nil {
return nil,
}
return NewSignerFromKey()
}
PublicKey PublicKey
}
func (*PassphraseMissingError) () string {
return "ssh: this private key is passphrase protected"
}
case "PRIVATE KEY":
return x509.ParsePKCS8PrivateKey(.Bytes)
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(.Bytes)
case "DSA PRIVATE KEY":
return ParseDSAPrivateKey(.Bytes)
case "OPENSSH PRIVATE KEY":
return parseOpenSSHPrivateKey(.Bytes, unencryptedOpenSSHKey)
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", .Type)
}
}
func (, []byte) (interface{}, error) {
, := pem.Decode()
if == nil {
return nil, errors.New("ssh: no key found")
}
if .Type == "OPENSSH PRIVATE KEY" {
return parseOpenSSHPrivateKey(.Bytes, passphraseProtectedOpenSSHKey())
}
if !encryptedBlock() || !x509.IsEncryptedPEMBlock() {
return nil, errors.New("ssh: not an encrypted key")
}
, := x509.DecryptPEMBlock(, )
if != nil {
if == x509.IncorrectPasswordError {
return nil,
}
return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", )
}
switch .Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey()
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey()
case "DSA PRIVATE KEY":
return ParseDSAPrivateKey()
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", .Type)
}
}
func ( []byte) (*dsa.PrivateKey, error) {
var struct {
int
*big.Int
*big.Int
*big.Int
*big.Int
*big.Int
}
, := asn1.Unmarshal(, &)
if != nil {
return nil, errors.New("ssh: failed to parse DSA key: " + .Error())
}
if len() > 0 {
return nil, errors.New("ssh: garbage after DSA key")
}
return &dsa.PrivateKey{
PublicKey: dsa.PublicKey{
Parameters: dsa.Parameters{
P: .,
Q: .,
G: .,
},
Y: .,
},
X: .,
}, nil
}
func (, , string, []byte) ([]byte, error) {
if != "none" || != "none" {
return nil, &PassphraseMissingError{}
}
if != "" {
return nil, errors.New("ssh: invalid openssh private key")
}
return , nil
}
func ( []byte) openSSHDecryptFunc {
return func(, , string, []byte) ([]byte, error) {
if == "none" || == "none" {
return nil, errors.New("ssh: key is not password protected")
}
if != "bcrypt" {
return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", , "bcrypt")
}
var struct {
string
uint32
}
if := Unmarshal([]byte(), &); != nil {
return nil,
}
, := bcrypt_pbkdf.Key(, []byte(.), int(.), 32+16)
if != nil {
return nil,
}
, := [:32], [32:]
, := aes.NewCipher()
if != nil {
return nil,
}
switch {
case "aes256-ctr":
:= cipher.NewCTR(, )
.XORKeyStream(, )
case "aes256-cbc":
if len()%.BlockSize() != 0 {
return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size")
}
:= cipher.NewCBCDecrypter(, )
.CryptBlocks(, )
default:
return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", , "aes256-ctr", "aes256-cbc")
}
return , nil
}
}
type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error)
func ( []byte, openSSHDecryptFunc) (crypto.PrivateKey, error) {
const = "openssh-key-v1\x00"
if len() < len() || string([:len()]) != {
return nil, errors.New("ssh: invalid openssh private key format")
}
:= [len():]
var struct {
string
string
string
uint32
[]byte
[]byte
}
if := Unmarshal(, &); != nil {
return nil,
}
return nil, errors.New("ssh: multi-key files are not supported")
}
, := (., ., ., .)
if != nil {
if , := .(*PassphraseMissingError); {
, := ParsePublicKey(.)
if != nil {
return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", )
}
.PublicKey =
}
return nil,
}
:= struct {
uint32
uint32
string
[]byte `ssh:"rest"`
}{}
if := Unmarshal(, &); != nil || . != . {
if . != "none" {
return nil, x509.IncorrectPasswordError
}
return nil, errors.New("ssh: malformed OpenSSH key")
}
switch . {
:= struct {
*big.Int
*big.Int
*big.Int
*big.Int
*big.Int
*big.Int
string
[]byte `ssh:"rest"`
}{}
if := Unmarshal(., &); != nil {
return nil,
}
if := checkOpenSSHKeyPadding(.); != nil {
return nil,
}
:= &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: .,
E: int(..Int64()),
},
D: .,
Primes: []*big.Int{., .},
}
if := .Validate(); != nil {
return nil,
}
.Precompute()
return , nil
case KeyAlgoED25519:
:= struct {
[]byte
[]byte
string
[]byte `ssh:"rest"`
}{}
if := Unmarshal(., &); != nil {
return nil,
}
if len(.) != ed25519.PrivateKeySize {
return nil, errors.New("ssh: private key unexpected length")
}
if := checkOpenSSHKeyPadding(.); != nil {
return nil,
}
:= ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
copy(, .)
return &, nil
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
:= struct {
string
[]byte
*big.Int
string
[]byte `ssh:"rest"`
}{}
if := Unmarshal(., &); != nil {
return nil,
}
if := checkOpenSSHKeyPadding(.); != nil {
return nil,
}
var elliptic.Curve
switch . {
case "nistp256":
= elliptic.P256()
case "nistp384":
= elliptic.P384()
case "nistp521":
= elliptic.P521()
default:
return nil, errors.New("ssh: unhandled elliptic curve: " + .)
}
, := elliptic.Unmarshal(, .)
if == nil || == nil {
return nil, errors.New("ssh: failed to unmarshal public key")
}
if ..Cmp(.Params().N) >= 0 {
return nil, errors.New("ssh: scalar is out of range")
}
, := .ScalarBaseMult(..Bytes())
if .Cmp() != 0 || .Cmp() != 0 {
return nil, errors.New("ssh: public key does not match private key")
}
return &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: ,
X: ,
Y: ,
},
D: .,
}, nil
default:
return nil, errors.New("ssh: unhandled key type")
}
}
func ( []byte) error {
for , := range {
if int() != +1 {
return errors.New("ssh: padding not as expected")
}
}
return nil
}
func ( PublicKey) string {
:= sha256.Sum256(.Marshal())
:= base64.RawStdEncoding.EncodeToString([:])
return "SHA256:" +
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |