aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2017-09-12 16:19:24 -0400
committerRuss Cox <rsc@golang.org>2017-09-22 20:08:11 +0000
commit86b7b52729c2ab898f34bad6df3826ec6c0f61b7 (patch)
tree07be051157cf70f27ee6f5d3876bcfd24ce7aff8
parent0bc83d7aaa7165f256210358fdfcf3bccd6d2f8f (diff)
downloadgo-86b7b52729c2ab898f34bad6df3826ec6c0f61b7.tar.gz
go-86b7b52729c2ab898f34bad6df3826ec6c0f61b7.zip
[dev.boringcrypto.go1.8] crypto/rsa: add test for, fix observable reads from custom randomness
In routines like GenerateKey, where bits from the randomness source have a visible effect on the output, we bypass BoringCrypto if given a non-standard randomness source (and also assert that this happens only during tests). In the decryption paths, the randomness source is only for blinding and has no effect on the output, so we unconditionally invoke BoringCrypto, letting it use its own randomness source as it sees fit. This in turn lets us verify that the non-BoringCrypto decryption function is never called, not even in tests. Unfortunately, while the randomness source has no visible effect on the decrypt operation, the decrypt operation does have a visible effect on the randomness source. If decryption doesn't use the randomness source, and it's a synthetic stream, then a future operation will read a different position in the stream and may produce different output. This happens in tests more often than you'd hope. To keep behavior of those future operations unchanged while still ensuring that the original decrypt is never called, this CL adds a simulation of the blinding preparation, to discard the right amount from the random source before invoking BoringCrypto. Change-Id: If2f87b856c811b59b536187c93efa99a97721419 Reviewed-on: https://go-review.googlesource.com/63912 Reviewed-by: Adam Langley <agl@golang.org> Reviewed-on: https://go-review.googlesource.com/65483 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
-rw-r--r--src/crypto/rsa/boring.go39
-rw-r--r--src/crypto/rsa/boring_test.go219
-rw-r--r--src/crypto/rsa/pkcs1v15.go4
-rw-r--r--src/crypto/rsa/pss.go18
-rw-r--r--src/crypto/rsa/rsa.go33
5 files changed, 295 insertions, 18 deletions
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go
index 0f362a2f16..f25f4a5274 100644
--- a/src/crypto/rsa/boring.go
+++ b/src/crypto/rsa/boring.go
@@ -6,6 +6,8 @@ package rsa
import (
"crypto/internal/boring"
+ "crypto/rand"
+ "io"
"math/big"
"sync/atomic"
"unsafe"
@@ -122,3 +124,40 @@ func copyPrivateKey(k *PrivateKey) PrivateKey {
}
return dst
}
+
+// boringFakeRandomBlind consumes from random to mimic the
+// blinding operation done in the standard Go func decrypt.
+// When we are using BoringCrypto, we always let it handle decrypt
+// regardless of random source, because the blind doesn't affect
+// the visible output of decryption, but if the random source is not
+// true randomness then the caller might still observe the side effect
+// of consuming from the source. We consume from the source
+// to give the same side effect. This should only happen during tests
+// (verified by the UnreachableExceptTests call below).
+//
+// We go to the trouble of doing this so that we can verify that
+// func decrypt (standard RSA decryption) is dropped from
+// BoringCrypto-linked binaries entirely; otherwise we'd have to
+// keep it in the binary just in case a call happened with a
+// non-standard randomness source.
+func boringFakeRandomBlind(random io.Reader, priv *PrivateKey) {
+ if random == nil || random == boring.RandReader {
+ return
+ }
+ boring.UnreachableExceptTests()
+
+ // Copied from func decrypt.
+ for {
+ r, err := rand.Int(random, priv.N)
+ if err != nil {
+ return
+ }
+ if r.Cmp(bigZero) == 0 {
+ r = bigOne
+ }
+ _, ok := modInverse(r, priv.N)
+ if ok {
+ break
+ }
+ }
+}
diff --git a/src/crypto/rsa/boring_test.go b/src/crypto/rsa/boring_test.go
index 290fe10a79..b2395ee3ee 100644
--- a/src/crypto/rsa/boring_test.go
+++ b/src/crypto/rsa/boring_test.go
@@ -2,13 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Note: Can run these tests against the non-BoringCrypto
+// version of the code by using "CGO_ENABLED=0 go test".
+
package rsa
import (
+ "bytes"
"crypto"
"crypto/rand"
+ "crypto/sha1"
+ "crypto/sha256"
"encoding/asn1"
+ "encoding/hex"
"reflect"
+ "sync"
"testing"
"unsafe"
)
@@ -65,3 +73,214 @@ func TestBoringVerify(t *testing.T) {
t.Errorf("sha1: %v", err)
}
}
+
+// The goal for BoringCrypto is to be indistinguishable from standard Go crypto.
+// Test that when routines are passed a not-actually-random reader, they
+// consume and potentially expose the expected bits from that reader.
+// This is awful but it makes sure that golden tests based on deterministic
+// "randomness" sources are unchanged by BoringCrypto.
+//
+// For decryption and signing, r is only used for blinding,
+// so we can and do still use BoringCrypto with its own true
+// randomness source, but we must be careful to consume
+// from r as if we'd used it for blinding.
+
+type testRandReader struct {
+ t *testing.T
+ offset int64
+ seq [8]byte
+ data []byte
+ buf [32]byte
+}
+
+func (r *testRandReader) Read(b []byte) (int, error) {
+ if len(r.data) == 0 && len(b) > 0 {
+ for i := range r.seq {
+ r.seq[i]++
+ if r.seq[i] != 0 {
+ break
+ }
+ }
+ r.buf = sha256.Sum256(r.seq[:])
+ r.data = r.buf[:]
+ }
+ n := copy(b, r.data)
+ r.data = r.data[n:]
+ r.offset += int64(n)
+ return n, nil
+}
+
+func (r *testRandReader) checkOffset(offset int64) {
+ if r.offset != offset {
+ r.t.Fatalf("r.offset = %d, expected %d", r.offset, offset)
+ }
+}
+
+func testRand(t *testing.T) *testRandReader {
+ return &testRandReader{t: t}
+}
+
+var testKeyCache struct {
+ once sync.Once
+ k *PrivateKey
+}
+
+func testKey(t *testing.T) *PrivateKey {
+ testKeyCache.once.Do(func() {
+ // Note: Key must be 2048 bits in order to trigger
+ // BoringCrypto code paths.
+ k, err := GenerateKey(testRand(t), 2048)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testKeyCache.k = k
+ })
+ return testKeyCache.k
+}
+
+func bytesFromHex(t *testing.T, x string) []byte {
+ b, err := hex.DecodeString(x)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return b
+}
+
+func TestBoringRandGenerateKey(t *testing.T) {
+ r := testRand(t)
+ k, err := GenerateKey(r, 2048) // 2048 is smallest size BoringCrypto might kick in for
+ if err != nil {
+ t.Fatal(err)
+ }
+ n := bigFromHex("b2e9c4c8b1c0f03ba6994fe1e715a3e598f0571f4676da420615b7b997d431ea7535ceb98e6b52172fe0d2fccfc5f696d1b34144f7d19d85633fcbf56daff805a66457b360b1b0f40ec18fb83f4c9b86f1b5fe26b209cdfff26911a95047df797210969693226423915c9be53ff1c06f86fe2d228273ef25970b90a3c70979f9d68458d5dd38f6700436f7cd5939c04be3e1f2ff52272513171540a685c9e8c8e20694e529cc3e0cc13d2fb91ac499d44b920a03e42be89a15e7ca73c29f2e2a1a8a7d9be57516ccb95e878db6ce6096e386a793cccc19eba15a37cc0f1234b7a25ee7c87569bc74c7ef3d6ad8d84a5ddb1e8901ae593f945523fe5e0ed451a5")
+ if k.N.Cmp(n) != 0 {
+ t.Fatalf("GenerateKey: wrong N\nhave %x\nwant %x", k.N, n)
+ }
+ r.checkOffset(35200)
+}
+
+func TestBoringRandGenerateMultiPrimeKey(t *testing.T) {
+ r := testRand(t)
+ k, err := GenerateMultiPrimeKey(r, 2, 2048)
+ if err != nil {
+ t.Fatal(err)
+ }
+ n := bigFromHex("b2e9c4c8b1c0f03ba6994fe1e715a3e598f0571f4676da420615b7b997d431ea7535ceb98e6b52172fe0d2fccfc5f696d1b34144f7d19d85633fcbf56daff805a66457b360b1b0f40ec18fb83f4c9b86f1b5fe26b209cdfff26911a95047df797210969693226423915c9be53ff1c06f86fe2d228273ef25970b90a3c70979f9d68458d5dd38f6700436f7cd5939c04be3e1f2ff52272513171540a685c9e8c8e20694e529cc3e0cc13d2fb91ac499d44b920a03e42be89a15e7ca73c29f2e2a1a8a7d9be57516ccb95e878db6ce6096e386a793cccc19eba15a37cc0f1234b7a25ee7c87569bc74c7ef3d6ad8d84a5ddb1e8901ae593f945523fe5e0ed451a5")
+ if k.N.Cmp(n) != 0 {
+ t.Fatalf("GenerateKey: wrong N\nhave %x\nwant %x", k.N, n)
+ }
+ r.checkOffset(35200)
+}
+
+func TestBoringRandEncryptPKCS1v15(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ enc, err := EncryptPKCS1v15(r, &k.PublicKey, []byte("hello world"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := bytesFromHex(t, "a8c8c0d248e669942a140c1184e1112afbf794b7427d9ac966bd2dbb4c05a2fee76f311f7feec743b8a8715e34bf741b0d0c4226559daf4de258ff712178e3f25fecb7d3eee90251e8ae4b4b7b907cd2763948cc9da34ce83c69934b523830545a536c1ba4d3740f4687e877acee9c768bcd8e88d472ba5d905493121f4830d95dcea36ef0f1223ffb0a9008eddfc53aca36877328924a2c631dce4b67e745564301fe51ab2c768b39e525bda1e1a08e029b58c53a0b92285f734592d2deebda957bcfd29c697aee263fce5c5023c7d3495b6a9114a8ac691aa661721cf45973b68678bb1e15d6605b9040951163d5b6df0d7f0b20dcefa251a7a8947a090f4b")
+ if !bytes.Equal(enc, want) {
+ t.Fatalf("EncryptPKCS1v15: wrong enc\nhave %x\nwant %x", enc, want)
+ }
+ r.checkOffset(242)
+}
+
+func TestBoringRandDecryptPKCS1v15(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ enc := bytesFromHex(t, "a8c8c0d248e669942a140c1184e1112afbf794b7427d9ac966bd2dbb4c05a2fee76f311f7feec743b8a8715e34bf741b0d0c4226559daf4de258ff712178e3f25fecb7d3eee90251e8ae4b4b7b907cd2763948cc9da34ce83c69934b523830545a536c1ba4d3740f4687e877acee9c768bcd8e88d472ba5d905493121f4830d95dcea36ef0f1223ffb0a9008eddfc53aca36877328924a2c631dce4b67e745564301fe51ab2c768b39e525bda1e1a08e029b58c53a0b92285f734592d2deebda957bcfd29c697aee263fce5c5023c7d3495b6a9114a8ac691aa661721cf45973b68678bb1e15d6605b9040951163d5b6df0d7f0b20dcefa251a7a8947a090f4b")
+ dec, err := DecryptPKCS1v15(r, k, enc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := []byte("hello world")
+ if !bytes.Equal(dec, want) {
+ t.Fatalf("DecryptPKCS1v15: wrong dec\nhave %x\nwant %x", dec, want)
+ }
+ r.checkOffset(256)
+}
+
+func TestBoringRandDecryptPKCS1v15SessionKey(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ enc := bytesFromHex(t, "a8c8c0d248e669942a140c1184e1112afbf794b7427d9ac966bd2dbb4c05a2fee76f311f7feec743b8a8715e34bf741b0d0c4226559daf4de258ff712178e3f25fecb7d3eee90251e8ae4b4b7b907cd2763948cc9da34ce83c69934b523830545a536c1ba4d3740f4687e877acee9c768bcd8e88d472ba5d905493121f4830d95dcea36ef0f1223ffb0a9008eddfc53aca36877328924a2c631dce4b67e745564301fe51ab2c768b39e525bda1e1a08e029b58c53a0b92285f734592d2deebda957bcfd29c697aee263fce5c5023c7d3495b6a9114a8ac691aa661721cf45973b68678bb1e15d6605b9040951163d5b6df0d7f0b20dcefa251a7a8947a090f4b")
+ dec := make([]byte, 11)
+ err := DecryptPKCS1v15SessionKey(r, k, enc, dec)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := []byte("hello world")
+ if !bytes.Equal(dec, want) {
+ t.Fatalf("DecryptPKCS1v15SessionKey: wrong dec\nhave %x\nwant %x", dec, want)
+ }
+ r.checkOffset(256)
+}
+
+func TestBoringRandSignPKCS1v15(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ sum := sha1.Sum([]byte("hello"))
+ sig, err := SignPKCS1v15(r, k, crypto.SHA1, sum[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := bytesFromHex(t, "4a8da3c0c41af2b8a93d011d4e11f4da9b2d52641c6c3d78d863987e857295adcedfae0e0d3ec00352bd134dc3fbb93b23a1fbe3718775762d78165bbbd37c6ef8e07bfa44e16ed2f1b05ebc04ba7bd60162d8689edb8709349e06bc281d34c2a3ee75d3454bfd95053cbb27c10515fb9132290a6ecc858e0c003201a9e100aac7f66af967364a1176e4ed9ef672d41481c59580f98bb82f205f712153fd5e3035a811da9d6e56e50609d1d604857f6d8e958bb84f354cfa28e0b8bcbb1261f929382d431454f07cbf60c18ff1243b11c6b552f3a0aa7e936f45cded40688ee53b1b630f944139f4f51baae49cd039b57b2b82f58f5589335137f4b09bd315f5")
+ if !bytes.Equal(sig, want) {
+ t.Fatalf("SignPKCS1v15(hash=SHA1): wrong sig\nhave %x\nwant %x", sig, want)
+ }
+
+ sig, err = SignPKCS1v15(r, k, 0, sum[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ want = bytesFromHex(t, "5d3d34495ffade926adab2de0545aaf1f22a03def949b69e1c91d34a2f0c7f2d682af46034151a1b67aa22cb9c1a8cc24c1358fce9ac6a2141879bbe107371b14faa97b12494260d9602ed1355f22ab3495b0bb7c137bc6801c1113fc2bdc00d4c250bbd8fa17e4ff86f71544b30a78e9d62c0b949afd1159760282c2700ec8be24cd884efd585ec55b45506d90e66cc3c5911baaea961e6c4e8018c4b4feb04afdd71880e3d8eff120288e53289a1bfb9fe7a3b9aca1d4549f133063647bfd4c6f4c0f4038f1bbcb4d112aa601f1b15402595076adfdbefb1bb64d3193bafb0305145bb536cd949a03ebe0470c6a155369f784afab2e25e9d5c03d8e13dcf1a")
+ if !bytes.Equal(sig, want) {
+ t.Fatalf("SignPKCS1v15(hash=0): wrong sig\nhave %x\nwant %x", sig, want)
+ }
+ r.checkOffset(768)
+}
+
+func TestBoringRandSignPSS(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ sum := sha1.Sum([]byte("hello"))
+ sig, err := SignPSS(r, k, crypto.SHA1, sum[:], nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := bytesFromHex(t, "a0de84c9654c2e78e33c899090f8dc0590046fda4ee29d133340800596401ae0df61bf8aa5689df3f873ad13cf55df5209c3a8c6450918b74c2017f87c2d588809740622c7752e3153a26d04bd3e9d9f6daa676e8e5e65a8a11d4fbd271d4693ab6a303652328dc1c923b484fa179fd6d9e8b523da74f3a307531c0dd75f243a041f7df22414dfdb83b3a241fe73e7af0f95cb6b60831bdd46dc05618e5cb3653476eb7d5405fa5ca98dad8f787ca86179055f305daa87eb424671878a93965e47d3002e2774be311d696b42e5691eddb2f788cd35246b408eb5d045c891ba1d57ce4c6fc935ceec90f7999406252f6266957cce4e7f12cf0ec94af358aeefa7")
+ if !bytes.Equal(sig, want) {
+ t.Fatalf("SignPSS: wrong sig\nhave %x\nwant %x", sig, want)
+ }
+ r.checkOffset(490)
+}
+
+func TestBoringRandEncryptOAEP(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ enc, err := EncryptOAEP(sha256.New(), r, &k.PublicKey, []byte("hello"), []byte("label"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := bytesFromHex(t, "55dc7b590a511c2d249232ecbb70040e8e0ec03206caae5ec0a401a0ad8013209ef546870f93d0946b9845ace092d456d092403f76f12ee65c2b8759731a25589d8a7e857407d09cfbe36ae36fc4daeb514ac597b1de2f7dc8450ab78a9e420c9b5dbbae3e402c8f378bd35505a47d556b705ab8985707a22e3583c172ef5730f05fd0845880d67c1ddd3c1525aa4c2c4e162bd6435a485609f6bd76c8ff73a7b5d043e4724458594703245fabdb479ef2786c757b35932a645399f2703647785b59b971970e6bccef3e6cd6fae39f9f135203eb104f0db20cf48e461cb7d824889c0d5d6a47cd0bf213c2f7acb3ddbd3effefebb4f60458ffc8b6ff1e4cc447")
+ if !bytes.Equal(enc, want) {
+ t.Fatalf("EncryptOAEP: wrong enc\nhave %x\nwant %x", enc, want)
+ }
+ r.checkOffset(32)
+}
+
+func TestBoringRandDecryptOAEP(t *testing.T) {
+ r := testRand(t)
+ k := testKey(t)
+ enc := bytesFromHex(t, "55dc7b590a511c2d249232ecbb70040e8e0ec03206caae5ec0a401a0ad8013209ef546870f93d0946b9845ace092d456d092403f76f12ee65c2b8759731a25589d8a7e857407d09cfbe36ae36fc4daeb514ac597b1de2f7dc8450ab78a9e420c9b5dbbae3e402c8f378bd35505a47d556b705ab8985707a22e3583c172ef5730f05fd0845880d67c1ddd3c1525aa4c2c4e162bd6435a485609f6bd76c8ff73a7b5d043e4724458594703245fabdb479ef2786c757b35932a645399f2703647785b59b971970e6bccef3e6cd6fae39f9f135203eb104f0db20cf48e461cb7d824889c0d5d6a47cd0bf213c2f7acb3ddbd3effefebb4f60458ffc8b6ff1e4cc447")
+ dec, err := DecryptOAEP(sha256.New(), r, k, enc, []byte("label"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := []byte("hello")
+ if !bytes.Equal(dec, want) {
+ t.Fatalf("DecryptOAEP: wrong dec\nhave %x\nwant %x", dec, want)
+ }
+ r.checkOffset(256)
+}
diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go
index 22475d7569..da51410b81 100644
--- a/src/crypto/rsa/pkcs1v15.go
+++ b/src/crypto/rsa/pkcs1v15.go
@@ -93,6 +93,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byt
}
if boring.Enabled {
+ boringFakeRandomBlind(rand, priv)
bkey, err := boringPrivateKey(priv)
if err != nil {
return nil, err
@@ -172,6 +173,7 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid
}
if boring.Enabled {
+ boringFakeRandomBlind(rand, priv)
var bkey *boring.PrivateKeyRSA
bkey, err = boringPrivateKey(priv)
if err != nil {
@@ -282,9 +284,9 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [
}
if boring.Enabled {
+ boringFakeRandomBlind(random, priv)
bkey, err := boringPrivateKey(priv)
if err != nil {
- println("X0")
return nil, err
}
return boring.SignRSAPKCS1v15(bkey, hash, hashed)
diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go
index 393ef16325..84b44d7540 100644
--- a/src/crypto/rsa/pss.go
+++ b/src/crypto/rsa/pss.go
@@ -198,6 +198,22 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed,
if err != nil {
return
}
+
+ if boring.Enabled {
+ boringFakeRandomBlind(rand, priv)
+ bkey, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ // Note: BoringCrypto takes care of the "AndCheck" part of "decryptAndCheck".
+ // (It's not just decrypt.)
+ s, err := boring.DecryptRSANoPadding(bkey, em)
+ if err != nil {
+ return nil, err
+ }
+ return s, nil
+ }
+
m := new(big.Int).SetBytes(em)
c, err := decryptAndCheck(rand, priv, m)
if err != nil {
@@ -260,7 +276,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
hash = opts.Hash
}
- if boring.Enabled {
+ if boring.Enabled && rand == boring.RandReader {
bkey, err := boringPrivateKey(priv)
if err != nil {
return nil, err
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index bac745ebb3..2fd25dddcc 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -201,7 +201,22 @@ func (priv *PrivateKey) Validate() error {
// GenerateKey generates an RSA keypair of the given bit size using the
// random source random (for example, crypto/rand.Reader).
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
- if boring.Enabled && (bits == 2048 || bits == 3072) {
+ return GenerateMultiPrimeKey(random, 2, bits)
+}
+
+// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
+// size and the given random source, as suggested in [1]. Although the public
+// keys are compatible (actually, indistinguishable) from the 2-prime case,
+// the private keys are not. Thus it may not be possible to export multi-prime
+// private keys in certain formats or to subsequently import them into other
+// code.
+//
+// Table 1 in [2] suggests maximum numbers of primes for a given size.
+//
+// [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
@@ -226,21 +241,6 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
return key, nil
}
- return GenerateMultiPrimeKey(random, 2, bits)
-}
-
-// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
-// size and the given random source, as suggested in [1]. Although the public
-// keys are compatible (actually, indistinguishable) from the 2-prime case,
-// the private keys are not. Thus it may not be possible to export multi-prime
-// private keys in certain formats or to subsequently import them into other
-// code.
-//
-// Table 1 in [2] suggests maximum numbers of primes for a given size.
-//
-// [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) {
priv := new(PrivateKey)
priv.E = 65537
@@ -651,6 +651,7 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
}
if boring.Enabled {
+ boringFakeRandomBlind(random, priv)
bkey, err := boringPrivateKey(priv)
if err != nil {
return nil, err