Skip to content

Commit

Permalink
crypto/rsa: check CRT result.
Browse files Browse the repository at this point in the history
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 golang#12453

Change-Id: I1f24e0b542f7c9a3f7e7ad4e971db3dc440ed3c1
Reviewed-on: https://go-review.googlesource.com/17862
Reviewed-by: Brad Fitzpatrick <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
Reviewed-by: Russ Cox <[email protected]>
  • Loading branch information
agl committed Dec 17, 2015
1 parent f33f9b2 commit 40ac369
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/crypto/rsa/pkcs1v15.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/rsa/pss.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
15 changes: 15 additions & 0 deletions src/crypto/rsa/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
27 changes: 22 additions & 5 deletions src/crypto/rsa/rsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ package rsa

import (
"bytes"
"crypto"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"math/big"
"testing"
)
Expand Down Expand Up @@ -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,
Expand All @@ -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[:])
}
}

Expand Down

0 comments on commit 40ac369

Please sign in to comment.