golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.33k stars 17.58k forks source link

proposal: x/crypto/ssh: make the number of rounds for Passphrase encrypted keys configurable #68700

Open DarkPhily opened 2 months ago

DarkPhily commented 2 months ago

Proposal Details

Hey,

Currently, someone can create a private ssh-key with ssh.MarshalPrivateKeyWithPassphrase(). This API doesn't expose the configured rounds. The rounds are currently hard-coded in:

func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncryptFunc {
    return func(privKeyBlock []byte) ([]byte, string, string, string, error) {
        salt := make([]byte, 16)
        if _, err := rand.Read(salt); err != nil {
            return nil, "", "", "", err
        }

        opts := struct {
            Salt   []byte
            Rounds uint32
        }{salt, 16} 

        // Derive key to encrypt the private key block.
        k, err := bcrypt_pbkdf.Key(passphrase, salt, int(opts.Rounds), 32+aes.BlockSize)
        if err != nil {
            return nil, "", "", "", err
        }

        // Add padding matching the block size of AES.
        keyBlock := generateOpenSSHPadding(privKeyBlock, aes.BlockSize)

        // Encrypt the private key using the derived secret.

        dst := make([]byte, len(keyBlock))
        key, iv := k[:32], k[32:]
        block, err := aes.NewCipher(key)
        if err != nil {
            return nil, "", "", "", err
        }

        stream := cipher.NewCTR(block, iv)
        stream.XORKeyStream(dst, keyBlock)

        return dst, "aes256-ctr", "bcrypt", string(Marshal(opts)), nil
    }
}

It would be nice if this is configurable as it is in ssh-keygen -a

ianlancetaylor commented 2 months ago

CC @golang/security

gopherbot commented 3 weeks ago

Change https://go.dev/cl/613036 mentions this issue: design/68723-crypto-ssh-v2.md: PrivateKeySigner and MarshalPrivateKey Options