diff options
Diffstat (limited to 'src/crypto/rsa/rsa.go')
-rw-r--r-- | src/crypto/rsa/rsa.go | 79 |
1 files changed, 75 insertions, 4 deletions
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index 1de4fcb473..8e63185ec6 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -24,6 +24,7 @@ package rsa import ( "crypto" + "crypto/internal/boring" "crypto/rand" "crypto/subtle" "errors" @@ -31,6 +32,7 @@ import ( "io" "math" "math/big" + "unsafe" ) var bigZero = big.NewInt(0) @@ -40,6 +42,8 @@ var bigOne = big.NewInt(1) type PublicKey struct { N *big.Int // modulus E int // public exponent + + boring unsafe.Pointer } // OAEPOptions is an interface for passing options to OAEP decryption using the @@ -85,6 +89,8 @@ type PrivateKey struct { // Precomputed contains precomputed values that speed up private // operations, if available. Precomputed PrecomputedValues + + boring unsafe.Pointer } // Public returns the public key corresponding to priv. @@ -210,6 +216,32 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { // [1] US patent 4405829 (1972, expired) // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) { + if boring.Enabled && random == boring.RandReader && nprimes == 2 && (bits == 2048 || bits == 3072) { + N, E, D, P, Q, Dp, Dq, Qinv, err := boring.GenerateKeyRSA(bits) + if err != nil { + return nil, err + } + e64 := E.Int64() + if !E.IsInt64() || int64(int(e64)) != e64 { + return nil, errors.New("crypto/rsa: generated key exponent too large") + } + key := &PrivateKey{ + PublicKey: PublicKey{ + N: N, + E: int(e64), + }, + D: D, + Primes: []*big.Int{P, Q}, + Precomputed: PrecomputedValues{ + Dp: Dp, + Dq: Dq, + Qinv: Qinv, + CRTValues: make([]CRTValue, 0), // non-nil, to match Precompute + }, + } + return key, nil + } + priv := new(PrivateKey) priv.E = 65537 @@ -344,6 +376,7 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size") func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { + boring.Unreachable() e := big.NewInt(int64(pub.E)) c.Exp(m, e, pub.N) return c @@ -376,6 +409,15 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l return nil, ErrMessageTooLong } + if boring.Enabled && random == boring.RandReader { + bkey, err := boringPublicKey(pub) + if err != nil { + return nil, err + } + return boring.EncryptRSAOAEP(hash, bkey, msg, label) + } + boring.UnreachableExceptTests() + hash.Write(label) lHash := hash.Sum(nil) hash.Reset() @@ -396,10 +438,24 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l mgf1XOR(db, hash, seed) mgf1XOR(seed, hash, db) - m := new(big.Int) - m.SetBytes(em) - c := encrypt(new(big.Int), pub, m) - out := c.Bytes() + var out []byte + if boring.Enabled { + var bkey *boring.PublicKeyRSA + bkey, err = boringPublicKey(pub) + if err != nil { + return nil, err + } + c, err := boring.EncryptRSANoPadding(bkey, em) + if err != nil { + return nil, err + } + out = c + } else { + m := new(big.Int) + m.SetBytes(em) + c := encrypt(new(big.Int), pub, m) + out = c.Bytes() + } if len(out) < k { // If the output is too small, we need to left-pad with zeros. @@ -477,6 +533,9 @@ func (priv *PrivateKey) Precompute() { // decrypt performs an RSA decryption, resulting in a plaintext integer. If a // random source is given, RSA blinding is used. func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { + if len(priv.Primes) <= 2 { + boring.Unreachable() + } // TODO(agl): can we get away with reusing blinds? if c.Cmp(priv.N) > 0 { err = ErrDecryption @@ -592,6 +651,18 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext return nil, ErrDecryption } + if boring.Enabled { + boringFakeRandomBlind(random, priv) + bkey, err := boringPrivateKey(priv) + if err != nil { + return nil, err + } + out, err := boring.DecryptRSAOAEP(hash, bkey, ciphertext, label) + if err != nil { + return nil, ErrDecryption + } + return out, nil + } c := new(big.Int).SetBytes(ciphertext) m, err := decrypt(random, priv, c) |