diff options
author | Filippo Valsorda <filippo@golang.org> | 2018-06-08 18:58:30 -0400 |
---|---|---|
committer | Filippo Valsorda <filippo@golang.org> | 2018-06-13 21:59:09 +0000 |
commit | b77f5e4c8530279d40eb29dc86a320a8fb4f909e (patch) | |
tree | 65c6ecc533bf5d99ed7b60fd326757003c48da67 | |
parent | a4b7722ffaa031d1ae7b95a0565c02889de22520 (diff) | |
download | go-b77f5e4c8530279d40eb29dc86a320a8fb4f909e.tar.gz go-b77f5e4c8530279d40eb29dc86a320a8fb4f909e.zip |
[dev.boringcrypto] crypto/rsa: drop random source reading emulation
Now that the standard library behavior in reading from the randomness
source is not reliable thanks to randutil.MaybeReadByte, we don't need
to emulate its behavior.
Also, since boring.RandReader is never deterministic, add an early exit
to randutil.MaybeReadByte.
Change-Id: Ie53e45ee64af635595181f71abd3c4340c600907
Reviewed-on: https://go-review.googlesource.com/117555
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
-rw-r--r-- | src/crypto/rsa/boring.go | 40 | ||||
-rw-r--r-- | src/crypto/rsa/boring_test.go | 218 | ||||
-rw-r--r-- | src/crypto/rsa/pkcs1v15.go | 3 | ||||
-rw-r--r-- | src/crypto/rsa/pss.go | 1 | ||||
-rw-r--r-- | src/crypto/rsa/rsa.go | 1 |
5 files changed, 6 insertions, 257 deletions
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go index 0ddff014e6..0f362a2f16 100644 --- a/src/crypto/rsa/boring.go +++ b/src/crypto/rsa/boring.go @@ -6,8 +6,6 @@ package rsa import ( "crypto/internal/boring" - "crypto/rand" - "io" "math/big" "sync/atomic" "unsafe" @@ -124,41 +122,3 @@ 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. - ir := new(big.Int) - for { - r, err := rand.Int(random, priv.N) - if err != nil { - return - } - if r.Cmp(bigZero) == 0 { - r = bigOne - } - ok := ir.ModInverse(r, priv.N) - if ok != nil { - break - } - } -} diff --git a/src/crypto/rsa/boring_test.go b/src/crypto/rsa/boring_test.go index dfec83805f..f68dfc9999 100644 --- a/src/crypto/rsa/boring_test.go +++ b/src/crypto/rsa/boring_test.go @@ -8,13 +8,9 @@ package rsa import ( - "bytes" "crypto" "crypto/rand" - "crypto/sha1" - "crypto/sha256" "encoding/asn1" - "encoding/hex" "reflect" "runtime" "runtime/debug" @@ -77,90 +73,11 @@ func TestBoringVerify(t *testing.T) { } } -// 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) { - r.t.Helper() - 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 +func TestBoringGenerateKey(t *testing.T) { + k, err := GenerateKey(rand.Reader, 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) // Non-Boring GenerateKey always sets CRTValues to a non-nil (possibly empty) slice. if k.Precomputed.CRTValues == nil { @@ -168,132 +85,6 @@ func TestBoringRandGenerateKey(t *testing.T) { } } -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) -} - func TestBoringFinalizers(t *testing.T) { if runtime.GOOS == "nacl" { // Times out on nacl (without BoringCrypto) @@ -302,7 +93,10 @@ func TestBoringFinalizers(t *testing.T) { t.Skip("skipping on nacl") } - k := testKey(t) + k, err := GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } // Run test with GOGC=10, to make bug more likely. // Without the KeepAlives, the loop usually dies after diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go index b617840c79..5a0e9e2fb5 100644 --- a/src/crypto/rsa/pkcs1v15.go +++ b/src/crypto/rsa/pkcs1v15.go @@ -97,7 +97,6 @@ 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 @@ -177,7 +176,6 @@ 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 { @@ -288,7 +286,6 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ } if boring.Enabled { - boringFakeRandomBlind(random, priv) bkey, err := boringPrivateKey(priv) if err != nil { return nil, err diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go index 67ab964657..89f850ed0f 100644 --- a/src/crypto/rsa/pss.go +++ b/src/crypto/rsa/pss.go @@ -200,7 +200,6 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, } if boring.Enabled { - boringFakeRandomBlind(rand, priv) 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 6cbcfe5449..755bd6d5dc 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -636,7 +636,6 @@ 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 |