// Copyright 2012 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package x509// RFC 1423 describes the encryption of PEM blocks. The algorithm used to// generate a key from the password was derived by looking at the OpenSSL// implementation.import ()typePEMCipherint// Possible values for the EncryptPEMBlock encryption algorithm.const ( _ PEMCipher = iotaPEMCipherDESPEMCipher3DESPEMCipherAES128PEMCipherAES192PEMCipherAES256)// rfc1423Algo holds a method for enciphering a PEM block.type rfc1423Algo struct { cipher PEMCipher name string cipherFunc func(key []byte) (cipher.Block, error) keySize int blockSize int}// rfc1423Algos holds a slice of the possible ways to encrypt a PEM// block. The ivSize numbers were taken from the OpenSSL source.var rfc1423Algos = []rfc1423Algo{{cipher: PEMCipherDES,name: "DES-CBC",cipherFunc: des.NewCipher,keySize: 8,blockSize: des.BlockSize,}, {cipher: PEMCipher3DES,name: "DES-EDE3-CBC",cipherFunc: des.NewTripleDESCipher,keySize: 24,blockSize: des.BlockSize,}, {cipher: PEMCipherAES128,name: "AES-128-CBC",cipherFunc: aes.NewCipher,keySize: 16,blockSize: aes.BlockSize,}, {cipher: PEMCipherAES192,name: "AES-192-CBC",cipherFunc: aes.NewCipher,keySize: 24,blockSize: aes.BlockSize,}, {cipher: PEMCipherAES256,name: "AES-256-CBC",cipherFunc: aes.NewCipher,keySize: 32,blockSize: aes.BlockSize,},}// deriveKey uses a key derivation function to stretch the password into a key// with the number of bits our cipher requires. This algorithm was derived from// the OpenSSL source.func ( rfc1423Algo) (, []byte) []byte { := md5.New() := make([]byte, .keySize)var []bytefor := 0; < len(); += len() { .Reset() .Write() .Write() .Write() = .Sum([:0])copy([:], ) }return}// IsEncryptedPEMBlock returns whether the PEM block is password encrypted// according to RFC 1423.//// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by// design. Since it does not authenticate the ciphertext, it is vulnerable to// padding oracle attacks that can let an attacker recover the plaintext.func ( *pem.Block) bool { , := .Headers["DEK-Info"]return}// IncorrectPasswordError is returned when an incorrect password is detected.varIncorrectPasswordError = errors.New("x509: decryption password incorrect")// DecryptPEMBlock takes a PEM block encrypted according to RFC 1423 and the// password used to encrypt it and returns a slice of decrypted DER encoded// bytes. It inspects the DEK-Info header to determine the algorithm used for// decryption. If no DEK-Info header is present, an error is returned. If an// incorrect password is detected an [IncorrectPasswordError] is returned. Because// of deficiencies in the format, it's not always possible to detect an// incorrect password. In these cases no error will be returned but the// decrypted DER bytes will be random noise.//// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by// design. Since it does not authenticate the ciphertext, it is vulnerable to// padding oracle attacks that can let an attacker recover the plaintext.func ( *pem.Block, []byte) ([]byte, error) { , := .Headers["DEK-Info"]if ! {returnnil, errors.New("x509: no DEK-Info header in block") } , , := strings.Cut(, ",")if ! {returnnil, errors.New("x509: malformed DEK-Info header") } := cipherByName()if == nil {returnnil, errors.New("x509: unknown encryption mode") } , := hex.DecodeString()if != nil {returnnil, }iflen() != .blockSize {returnnil, errors.New("x509: incorrect IV size") }// Based on the OpenSSL implementation. The salt is the first 8 bytes // of the initialization vector. := .deriveKey(, [:8]) , := .cipherFunc()if != nil {returnnil, }iflen(.Bytes)%.BlockSize() != 0 {returnnil, errors.New("x509: encrypted PEM data is not a multiple of the block size") } := make([]byte, len(.Bytes)) := cipher.NewCBCDecrypter(, ) .CryptBlocks(, .Bytes)// Blocks are padded using a scheme where the last n bytes of padding are all // equal to n. It can pad from 1 to blocksize bytes inclusive. See RFC 1423. // For example: // [x y z 2 2] // [x y 7 7 7 7 7 7 7] // If we detect a bad padding, we assume it is an invalid password. := len()if == 0 || %.blockSize != 0 {returnnil, errors.New("x509: invalid padding") } := int([-1])if < {returnnil, IncorrectPasswordError }if == 0 || > .blockSize {returnnil, IncorrectPasswordError }for , := range [-:] {ifint() != {returnnil, IncorrectPasswordError } }return [:-], nil}// EncryptPEMBlock returns a PEM block of the specified type holding the// given DER encoded data encrypted with the specified algorithm and// password according to RFC 1423.//// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by// design. Since it does not authenticate the ciphertext, it is vulnerable to// padding oracle attacks that can let an attacker recover the plaintext.func ( io.Reader, string, , []byte, PEMCipher) (*pem.Block, error) { := cipherByKey()if == nil {returnnil, errors.New("x509: unknown encryption mode") } := make([]byte, .blockSize)if , := io.ReadFull(, ); != nil {returnnil, errors.New("x509: cannot generate IV: " + .Error()) }// The salt is the first 8 bytes of the initialization vector, // matching the key derivation in DecryptPEMBlock. := .deriveKey(, [:8]) , := .cipherFunc()if != nil {returnnil, } := cipher.NewCBCEncrypter(, ) := .blockSize - len()%.blockSize := make([]byte, len(), len()+)// We could save this copy by encrypting all the whole blocks in // the data separately, but it doesn't seem worth the additional // code.copy(, )// See RFC 1423, Section 1.1.for := 0; < ; ++ { = append(, byte()) } .CryptBlocks(, )return &pem.Block{Type: ,Headers: map[string]string{"Proc-Type": "4,ENCRYPTED","DEK-Info": .name + "," + hex.EncodeToString(), },Bytes: , }, nil}func cipherByName( string) *rfc1423Algo {for := rangerfc1423Algos { := &rfc1423Algos[]if .name == {return } }returnnil}func cipherByKey( PEMCipher) *rfc1423Algo {for := rangerfc1423Algos { := &rfc1423Algos[]if .cipher == {return } }returnnil}
The pages are generated with Goldsv0.7.3-preview. (GOOS=linux 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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds.