From 40ac3690efe420ff7665c6fe1eec0933c41d1413 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Tue, 15 Dec 2015 19:07:47 -0500 Subject: [PATCH] crypto/rsa: check CRT result. This change adds a check after computing an RSA signature that the signature is correct. This prevents an error in the CRT computation from leaking the private key. See references in the linked bug. benchmark old ns/op new ns/op delta BenchmarkRSA2048Sign-3 5713305 6225215 +8.96% Fixes #12453 Change-Id: I1f24e0b542f7c9a3f7e7ad4e971db3dc440ed3c1 Reviewed-on: https://go-review.googlesource.com/17862 Reviewed-by: Brad Fitzpatrick Reviewed-by: Robert Griesemer Reviewed-by: Russ Cox --- src/crypto/rsa/pkcs1v15.go | 2 +- src/crypto/rsa/pss.go | 2 +- src/crypto/rsa/rsa.go | 15 +++++++++++++++ src/crypto/rsa/rsa_test.go | 27 ++++++++++++++++++++++----- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go index 34037b0d67..37eaf1ab3e 100644 --- a/src/crypto/rsa/pkcs1v15.go +++ b/src/crypto/rsa/pkcs1v15.go @@ -223,7 +223,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b copy(em[k-hashLen:k], hashed) m := new(big.Int).SetBytes(em) - c, err := decrypt(rand, priv, m) + c, err := decryptAndCheck(rand, priv, m) if err != nil { return } diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go index 0a41814a4b..8a94589b1c 100644 --- a/src/crypto/rsa/pss.go +++ b/src/crypto/rsa/pss.go @@ -198,7 +198,7 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, return } m := new(big.Int).SetBytes(em) - c, err := decrypt(rand, priv, m) + c, err := decryptAndCheck(rand, priv, m) if err != nil { return } diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index 1293b78367..0a3e6acee9 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -506,6 +506,21 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er return } +func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { + m, err = decrypt(random, priv, c) + if err != nil { + return nil, err + } + + // In order to defend against errors in the CRT computation, m^e is + // calculated, which should match the original ciphertext. + check := encrypt(new(big.Int), &priv.PublicKey, m) + if c.Cmp(check) != 0 { + return nil, errors.New("rsa: internal error") + } + return m, nil +} + // DecryptOAEP decrypts ciphertext using RSA-OAEP. // 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) { diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 4ee1c3a8b2..6902f9a867 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -6,8 +6,10 @@ package rsa import ( "bytes" + "crypto" "crypto/rand" "crypto/sha1" + "crypto/sha256" "math/big" "testing" ) @@ -127,9 +129,10 @@ func fromBase10(base10 string) *big.Int { return i } -func BenchmarkRSA2048Decrypt(b *testing.B) { - b.StopTimer() - priv := &PrivateKey{ +var test2048Key *PrivateKey + +func init() { + test2048Key = &PrivateKey{ PublicKey: PublicKey{ N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"), E: 3, @@ -140,14 +143,28 @@ func BenchmarkRSA2048Decrypt(b *testing.B) { fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"), }, } - priv.Precompute() + test2048Key.Precompute() +} + +func BenchmarkRSA2048Decrypt(b *testing.B) { + b.StopTimer() c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313") b.StartTimer() for i := 0; i < b.N; i++ { - decrypt(nil, priv, c) + decrypt(nil, test2048Key, c) + } +} + +func BenchmarkRSA2048Sign(b *testing.B) { + b.StopTimer() + hashed := sha256.Sum256([]byte("testing")) + b.StartTimer() + + for i := 0; i < b.N; i++ { + SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:]) } }