aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/rsa/rsa.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/rsa/rsa.go')
-rw-r--r--src/crypto/rsa/rsa.go79
1 files changed, 75 insertions, 4 deletions
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 0faca43e43..9af5cbb165 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.
@@ -212,6 +218,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
@@ -346,6 +378,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
@@ -378,6 +411,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()
@@ -398,10 +440,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.
@@ -478,6 +534,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
@@ -593,6 +652,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)