Source File
pkcs1v15.go
Belonging Package
crypto/rsa
// 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.type PKCS1v15DecryptOptions struct {// 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.SessionKeyLen int}// 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) {if fips140only.Enabled {return nil, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")}if := checkPublicKeySize(); != nil {return nil,}randutil.MaybeReadByte():= .Size()if len() > -11 {return nil, ErrMessageTooLong}if boring.Enabled && == boring.RandReader {, := boringPublicKey()if != nil {return nil,}return boring.EncryptRSAPKCS1(, )}boring.UnreachableExceptTests()// EM = 0x00 || 0x02 || PS || 0x00 || M:= make([]byte, )[1] = 2, := [2:len()-len()-1], [len()-len():]:= nonZeroRandomBytes(, )if != nil {return nil,}[len()-len()-1] = 0copy(, )if boring.Enabled {var *boring.PublicKeyRSA, = boringPublicKey()if != nil {return nil,}return boring.EncryptRSANoPadding(, )}, := fipsPublicKey()if != nil {return nil,}return rsa.Encrypt(, )}// 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 := checkPublicKeySize(&.PublicKey); != nil {return nil,}if boring.Enabled {, := boringPrivateKey()if != nil {return nil,}, := boring.DecryptRSAPKCS1(, )if != nil {return nil, ErrDecryption}return , nil}, , , := decryptPKCS1v15(, )if != nil {return nil,}if == 0 {return nil, 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 := checkPublicKeySize(&.PublicKey); != nil {return}:= .Size()if -(len()+3+8) < 0 {return ErrDecryption}, , , := decryptPKCS1v15(, )if != nil {return}if len() != {// This should be impossible because decryptPKCS1v15 always// returns the full slice.return ErrDecryption}&= subtle.ConstantTimeEq(int32(len()-), int32(len()))subtle.ConstantTimeCopy(, , [len()-len():])return nil}// 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) {if fips140only.Enabled {return 0, nil, 0, errors.New("crypto/rsa: use of PKCS#1 v1.5 encryption is not allowed in FIPS 140-only mode")}:= .Size()if < 11 {= ErrDecryptionreturn 0, nil, 0,}if boring.Enabled {var *boring.PrivateKeyRSA, = boringPrivateKey()if != nil {return 0, nil, 0,}, = boring.DecryptRSANoPadding(, )if != nil {return 0, nil, 0, ErrDecryption}} else {, := fipsPrivateKey()if != nil {return 0, nil, 0,}, = rsa.DecryptWithoutCheck(, )if != nil {return 0, nil, 0, ErrDecryption}}:= 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}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)