1
0
mirror of https://github.com/golang/go synced 2024-11-22 01:14:40 -07:00

crypto/rsa: reject PublicKey.E if it won't fit in a 32-bit int

Right now we only have 32-bit ints so that's a no-op.
Took the opportunity to check for some other invalid values too.
Suggestions for additions or modifications welcome.

R=agl
CC=golang-dev
https://golang.org/cl/6493112
This commit is contained in:
Russ Cox 2012-09-13 10:47:01 -04:00
parent 6ee91ced92
commit ef87c0edae
2 changed files with 43 additions and 0 deletions

View File

@ -19,6 +19,9 @@ import (
// WARNING: use of this function to encrypt plaintexts other than session keys // WARNING: use of this function to encrypt plaintexts other than session keys
// is dangerous. Use RSA OAEP in new protocols. // is dangerous. Use RSA OAEP in new protocols.
func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) { func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) {
if err := checkPub(pub); err != nil {
return nil, err
}
k := (pub.N.BitLen() + 7) / 8 k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-11 { if len(msg) > k-11 {
err = ErrMessageTooLong err = ErrMessageTooLong
@ -47,6 +50,9 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) { func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) {
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
valid, out, err := decryptPKCS1v15(rand, priv, ciphertext) valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
if err == nil && valid == 0 { if err == nil && valid == 0 {
err = ErrDecryption err = ErrDecryption
@ -69,6 +75,9 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
// Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology // Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
// (Crypto '98). // (Crypto '98).
func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) { func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
if err := checkPub(&priv.PublicKey); err != nil {
return err
}
k := (priv.N.BitLen() + 7) / 8 k := (priv.N.BitLen() + 7) / 8
if k-(len(key)+3+8) < 0 { if k-(len(key)+3+8) < 0 {
err = ErrDecryption err = ErrDecryption

View File

@ -25,6 +25,30 @@ type PublicKey struct {
E int // public exponent E int // public exponent
} }
var (
errPublicModulus = errors.New("crypto/rsa: missing public modulus")
errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large")
)
// checkPub sanity checks the public key before we use it.
// We require pub.E to fit into a 32-bit integer so that we
// do not have different behavior depending on whether
// int is 32 or 64 bits. See also
// http://www.imperialviolet.org/2012/03/16/rsae.html.
func checkPub(pub *PublicKey) error {
if pub.N == nil {
return errPublicModulus
}
if pub.E < 2 {
return errPublicExponentSmall
}
if pub.E > 1<<31-1 {
return errPublicExponentLarge
}
return nil
}
// A PrivateKey represents an RSA key // A PrivateKey represents an RSA key
type PrivateKey struct { type PrivateKey struct {
PublicKey // public part. PublicKey // public part.
@ -57,6 +81,10 @@ type CRTValue struct {
// Validate performs basic sanity checks on the key. // Validate performs basic sanity checks on the key.
// It returns nil if the key is valid, or else an error describing a problem. // It returns nil if the key is valid, or else an error describing a problem.
func (priv *PrivateKey) Validate() error { func (priv *PrivateKey) Validate() error {
if err := checkPub(&priv.PublicKey); err != nil {
return err
}
// Check that the prime factors are actually prime. Note that this is // Check that the prime factors are actually prime. Note that this is
// just a sanity check. Since the random witnesses chosen by // just a sanity check. Since the random witnesses chosen by
// ProbablyPrime are deterministic, given the candidate number, it's // ProbablyPrime are deterministic, given the candidate number, it's
@ -216,6 +244,9 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
// The message must be no longer than the length of the public modulus less // The message must be no longer than the length of the public modulus less
// twice the hash length plus 2. // twice the hash length plus 2.
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) { func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) {
if err := checkPub(pub); err != nil {
return nil, err
}
hash.Reset() hash.Reset()
k := (pub.N.BitLen() + 7) / 8 k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-2*hash.Size()-2 { if len(msg) > k-2*hash.Size()-2 {
@ -402,6 +433,9 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er
// DecryptOAEP decrypts ciphertext using RSA-OAEP. // DecryptOAEP decrypts ciphertext using RSA-OAEP.
// If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks. // If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
k := (priv.N.BitLen() + 7) / 8 k := (priv.N.BitLen() + 7) / 8
if len(ciphertext) > k || if len(ciphertext) > k ||
k < hash.Size()*2+2 { k < hash.Size()*2+2 {