// Copyright 2009 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 rsaimport ()// This file implements encryption and decryption using PKCS #1 v1.5 padding.// PKCS1v15DecryptOptions is for passing options to PKCS #1 v1.5 decryption using// the crypto.Decrypter interface.typePKCS1v15DecryptOptionsstruct {// SessionKeyLen is the length of the session key that is being // decrypted. If not zero, then a padding error during decryption will // cause a random plaintext of this length to be returned rather than // an error. These alternatives happen in constant time.SessionKeyLenint}// EncryptPKCS1v15 encrypts the given message with RSA and the padding// scheme from PKCS #1 v1.5. The message must be no longer than the// length of the public modulus minus 11 bytes.//// The random parameter is used as a source of entropy to ensure that// encrypting the same message twice doesn't result in the same// ciphertext. Most applications should use [crypto/rand.Reader]// as random. Note that the returned ciphertext does not depend// deterministically on the bytes read from random, and may change// between calls and/or between versions.//// WARNING: use of this function to encrypt plaintexts other than// session keys is dangerous. Use RSA OAEP in new protocols.func ( io.Reader, *PublicKey, []byte) ([]byte, error) {randutil.MaybeReadByte()if := checkPub(); != nil {returnnil, } := .Size()iflen() > -11 {returnnil, ErrMessageTooLong }ifboring.Enabled && == boring.RandReader { , := boringPublicKey()if != nil {returnnil, }returnboring.EncryptRSAPKCS1(, ) }boring.UnreachableExceptTests()// EM = 0x00 || 0x02 || PS || 0x00 || M := make([]byte, ) [1] = 2 , := [2:len()-len()-1], [len()-len():] := nonZeroRandomBytes(, )if != nil {returnnil, } [len()-len()-1] = 0copy(, )ifboring.Enabled {var *boring.PublicKeyRSA , = boringPublicKey()if != nil {returnnil, }returnboring.EncryptRSANoPadding(, ) }returnencrypt(, )}// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS #1 v1.5.// The random parameter is legacy and ignored, and it can be nil.//// Note that whether this function returns an error or not discloses secret// information. If an attacker can cause this function to run repeatedly and// learn whether each instance returned an error then they can decrypt and// forge signatures as if they had the private key. See// DecryptPKCS1v15SessionKey for a way of solving this problem.func ( io.Reader, *PrivateKey, []byte) ([]byte, error) {if := checkPub(&.PublicKey); != nil {returnnil, }ifboring.Enabled { , := boringPrivateKey()if != nil {returnnil, } , := boring.DecryptRSAPKCS1(, )if != nil {returnnil, ErrDecryption }return , nil } , , , := decryptPKCS1v15(, )if != nil {returnnil, }if == 0 {returnnil, ErrDecryption }return [:], nil}// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding// scheme from PKCS #1 v1.5. The random parameter is legacy and ignored, and it// can be nil.//// DecryptPKCS1v15SessionKey returns an error if the ciphertext is the wrong// length or if the ciphertext is greater than the public modulus. Otherwise, no// error is returned. If the padding is valid, the resulting plaintext message// is copied into key. Otherwise, key is unchanged. These alternatives occur in// constant time. It is intended that the user of this function generate a// random session key beforehand and continue the protocol with the resulting// value.//// Note that if the session key is too small then it may be possible for an// attacker to brute-force it. If they can do that then they can learn whether a// random value was used (because it'll be different for the same ciphertext)// and thus whether the padding was correct. This also defeats the point of this// function. Using at least a 16-byte key will protect against this attack.//// This method implements protections against Bleichenbacher chosen ciphertext// attacks [0] described in RFC 3218 Section 2.3.2 [1]. While these protections// make a Bleichenbacher attack significantly more difficult, the protections// are only effective if the rest of the protocol which uses// DecryptPKCS1v15SessionKey is designed with these considerations in mind. In// particular, if any subsequent operations which use the decrypted session key// leak any information about the key (e.g. whether it is a static or random// key) then the mitigations are defeated. This method must be used extremely// carefully, and typically should only be used when absolutely necessary for// compatibility with an existing protocol (such as TLS) that is designed with// these properties in mind.//// - [0] “Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption// Standard PKCS #1”, Daniel Bleichenbacher, Advances in Cryptology (Crypto '98)// - [1] RFC 3218, Preventing the Million Message Attack on CMS,// https://www.rfc-editor.org/rfc/rfc3218.htmlfunc ( io.Reader, *PrivateKey, []byte, []byte) error {if := checkPub(&.PublicKey); != nil {return } := .Size()if -(len()+3+8) < 0 {returnErrDecryption } , , , := decryptPKCS1v15(, )if != nil {return }iflen() != {// This should be impossible because decryptPKCS1v15 always // returns the full slice.returnErrDecryption } &= subtle.ConstantTimeEq(int32(len()-), int32(len()))subtle.ConstantTimeCopy(, , [len()-len():])returnnil}// decryptPKCS1v15 decrypts ciphertext using priv. It returns one or zero in// valid that indicates whether the plaintext was correctly structured.// In either case, the plaintext is returned in em so that it may be read// independently of whether it was valid in order to maintain constant memory// access patterns. If the plaintext was valid then index contains the index of// the original message in em, to allow constant time padding removal.func ( *PrivateKey, []byte) ( int, []byte, int, error) { := .Size()if < 11 { = ErrDecryptionreturn }ifboring.Enabled {var *boring.PrivateKeyRSA , = boringPrivateKey()if != nil {return } , = boring.DecryptRSANoPadding(, )if != nil {return } } else { , = decrypt(, , noCheck)if != nil {return } } := subtle.ConstantTimeByteEq([0], 0) := subtle.ConstantTimeByteEq([1], 2)// The remainder of the plaintext must be a string of non-zero random // octets, followed by a 0, followed by the message. // lookingForIndex: 1 iff we are still looking for the zero. // index: the offset of the first zero byte. := 1for := 2; < len(); ++ { := subtle.ConstantTimeByteEq([], 0) = subtle.ConstantTimeSelect(&, , ) = subtle.ConstantTimeSelect(, 0, ) }// The PS padding must be at least 8 bytes long, and it starts two // bytes into em. := subtle.ConstantTimeLessOrEq(2+8, ) = & & (^ & 1) & = subtle.ConstantTimeSelect(, +1, 0)return , , , nil}// nonZeroRandomBytes fills the given slice with non-zero random octets.func ( []byte, io.Reader) ( error) { _, = io.ReadFull(, )if != nil {return }for := 0; < len(); ++ {for [] == 0 { _, = io.ReadFull(, [:+1])if != nil {return }// In tests, the PRNG may return all zeros so we do // this to break the loop. [] ^= 0x42 } }return}// These are ASN1 DER structures://// DigestInfo ::= SEQUENCE {// digestAlgorithm AlgorithmIdentifier,// digest OCTET STRING// }//// For performance, we don't use the generic ASN1 encoder. Rather, we// precompute a prefix of the digest value that makes a valid ASN1 DER string// with the correct contents.varhashPrefixes = map[crypto.Hash][]byte{crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix.crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},}// SignPKCS1v15 calculates the signature of hashed using// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS #1 v1.5. Note that hashed must// be the result of hashing the input message using the given hash// function. If hash is zero, hashed is signed directly. This isn't// advisable except for interoperability.//// The random parameter is legacy and ignored, and it can be nil.//// This function is deterministic. Thus, if the set of possible// messages is small, an attacker may be able to build a map from// messages to signatures and identify the signed messages. As ever,// signatures provide authenticity, not confidentiality.func ( io.Reader, *PrivateKey, crypto.Hash, []byte) ([]byte, error) { , , := pkcs1v15HashInfo(, len())if != nil {returnnil, } := len() + := .Size()if < +11 {returnnil, ErrMessageTooLong }ifboring.Enabled { , := boringPrivateKey()if != nil {returnnil, }returnboring.SignRSAPKCS1v15(, , ) }// EM = 0x00 || 0x01 || PS || 0x00 || T := make([]byte, ) [1] = 1for := 2; < --1; ++ { [] = 0xff }copy([-:-], )copy([-:], )returndecrypt(, , withCheck)}// VerifyPKCS1v15 verifies an RSA PKCS #1 v1.5 signature.// hashed is the result of hashing the input message using the given hash// function and sig is the signature. A valid signature is indicated by// returning a nil error. If hash is zero then hashed is used directly. This// isn't advisable except for interoperability.func ( *PublicKey, crypto.Hash, []byte, []byte) error {ifboring.Enabled { , := boringPublicKey()if != nil {return }if := boring.VerifyRSAPKCS1v15(, , , ); != nil {returnErrVerification }returnnil } , , := pkcs1v15HashInfo(, len())if != nil {return } := len() + := .Size()if < +11 {returnErrVerification }// RFC 8017 Section 8.2.2: If the length of the signature S is not k // octets (where k is the length in octets of the RSA modulus n), output // "invalid signature" and stop.if != len() {returnErrVerification } , := encrypt(, )if != nil {returnErrVerification }// EM = 0x00 || 0x01 || PS || 0x00 || T := subtle.ConstantTimeByteEq([0], 0) &= subtle.ConstantTimeByteEq([1], 1) &= subtle.ConstantTimeCompare([-:], ) &= subtle.ConstantTimeCompare([-:-], ) &= subtle.ConstantTimeByteEq([--1], 0)for := 2; < --1; ++ { &= subtle.ConstantTimeByteEq([], 0xff) }if != 1 {returnErrVerification }returnnil}func ( crypto.Hash, int) ( int, []byte, error) {// Special case: crypto.Hash(0) is used to indicate that the data is // signed directly.if == 0 {return , nil, nil } = .Size()if != {return0, nil, errors.New("crypto/rsa: input must be hashed message") } , := hashPrefixes[]if ! {return0, nil, errors.New("crypto/rsa: unsupported hash function") }return}
The pages are generated with Goldsv0.6.7. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.