mirror of
https://github.com/golang/go
synced 2024-11-20 03:04:40 -07:00
crypto/rsa: add 3-prime support.
R=golang-dev, rsc1 CC=golang-dev https://golang.org/cl/4365041
This commit is contained in:
parent
057bdfe39d
commit
41971434d1
@ -92,19 +92,21 @@ type PublicKey struct {
|
|||||||
type PrivateKey struct {
|
type PrivateKey struct {
|
||||||
PublicKey // public part.
|
PublicKey // public part.
|
||||||
D *big.Int // private exponent
|
D *big.Int // private exponent
|
||||||
P, Q *big.Int // prime factors of N
|
P, Q, R *big.Int // prime factors of N (R may be nil)
|
||||||
|
|
||||||
rwMutex sync.RWMutex // protects the following
|
rwMutex sync.RWMutex // protects the following
|
||||||
dP, dQ *big.Int // D mod (P-1) (or mod Q-1)
|
dP, dQ, dR *big.Int // D mod (P-1) (or mod Q-1 etc)
|
||||||
qInv *big.Int // q^-1 mod p
|
qInv *big.Int // q^-1 mod p
|
||||||
|
pq *big.Int // P*Q
|
||||||
|
tr *big.Int // pq·tr ≡ 1 mod r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate performs basic sanity checks on the key.
|
// Validate performs basic sanity checks on the key.
|
||||||
// It returns nil if the key is valid, or else an os.Error describing a problem.
|
// It returns nil if the key is valid, or else an os.Error describing a problem.
|
||||||
|
|
||||||
func (priv *PrivateKey) Validate() os.Error {
|
func (priv *PrivateKey) Validate() os.Error {
|
||||||
// Check that p and q are prime. Note that this is just a sanity
|
// Check that p, q and, maybe, r are prime. Note that this is just a
|
||||||
// check. Since the random witnesses chosen by ProbablyPrime are
|
// sanity check. Since the random witnesses chosen by ProbablyPrime are
|
||||||
// deterministic, given the candidate number, it's easy for an attack
|
// deterministic, given the candidate number, it's easy for an attack
|
||||||
// to generate composites that pass this test.
|
// to generate composites that pass this test.
|
||||||
if !big.ProbablyPrime(priv.P, 20) {
|
if !big.ProbablyPrime(priv.P, 20) {
|
||||||
@ -113,16 +115,26 @@ func (priv *PrivateKey) Validate() os.Error {
|
|||||||
if !big.ProbablyPrime(priv.Q, 20) {
|
if !big.ProbablyPrime(priv.Q, 20) {
|
||||||
return os.ErrorString("Q is composite")
|
return os.ErrorString("Q is composite")
|
||||||
}
|
}
|
||||||
|
if priv.R != nil && !big.ProbablyPrime(priv.R, 20) {
|
||||||
|
return os.ErrorString("R is composite")
|
||||||
|
}
|
||||||
|
|
||||||
// Check that p*q == n.
|
// Check that p*q*r == n.
|
||||||
modulus := new(big.Int).Mul(priv.P, priv.Q)
|
modulus := new(big.Int).Mul(priv.P, priv.Q)
|
||||||
|
if priv.R != nil {
|
||||||
|
modulus.Mul(modulus, priv.R)
|
||||||
|
}
|
||||||
if modulus.Cmp(priv.N) != 0 {
|
if modulus.Cmp(priv.N) != 0 {
|
||||||
return os.ErrorString("invalid modulus")
|
return os.ErrorString("invalid modulus")
|
||||||
}
|
}
|
||||||
// Check that e and totient(p, q) are coprime.
|
// Check that e and totient(p, q, r) are coprime.
|
||||||
pminus1 := new(big.Int).Sub(priv.P, bigOne)
|
pminus1 := new(big.Int).Sub(priv.P, bigOne)
|
||||||
qminus1 := new(big.Int).Sub(priv.Q, bigOne)
|
qminus1 := new(big.Int).Sub(priv.Q, bigOne)
|
||||||
totient := new(big.Int).Mul(pminus1, qminus1)
|
totient := new(big.Int).Mul(pminus1, qminus1)
|
||||||
|
if priv.R != nil {
|
||||||
|
rminus1 := new(big.Int).Sub(priv.R, bigOne)
|
||||||
|
totient.Mul(totient, rminus1)
|
||||||
|
}
|
||||||
e := big.NewInt(int64(priv.E))
|
e := big.NewInt(int64(priv.E))
|
||||||
gcd := new(big.Int)
|
gcd := new(big.Int)
|
||||||
x := new(big.Int)
|
x := new(big.Int)
|
||||||
@ -131,7 +143,7 @@ func (priv *PrivateKey) Validate() os.Error {
|
|||||||
if gcd.Cmp(bigOne) != 0 {
|
if gcd.Cmp(bigOne) != 0 {
|
||||||
return os.ErrorString("invalid public exponent E")
|
return os.ErrorString("invalid public exponent E")
|
||||||
}
|
}
|
||||||
// Check that de ≡ 1 (mod totient(p, q))
|
// Check that de ≡ 1 (mod totient(p, q, r))
|
||||||
de := new(big.Int).Mul(priv.D, e)
|
de := new(big.Int).Mul(priv.D, e)
|
||||||
de.Mod(de, totient)
|
de.Mod(de, totient)
|
||||||
if de.Cmp(bigOne) != 0 {
|
if de.Cmp(bigOne) != 0 {
|
||||||
@ -140,7 +152,7 @@ func (priv *PrivateKey) Validate() os.Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateKeyPair generates an RSA keypair of the given bit size.
|
// GenerateKey generates an RSA keypair of the given bit size.
|
||||||
func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
|
func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
|
||||||
priv = new(PrivateKey)
|
priv = new(PrivateKey)
|
||||||
// Smaller public exponents lead to faster public key
|
// Smaller public exponents lead to faster public key
|
||||||
@ -196,6 +208,77 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate3PrimeKey generates a 3-prime RSA keypair of the given bit size, 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 3-prime private keys in certain formats or to
|
||||||
|
// subsequently import them into other code.
|
||||||
|
//
|
||||||
|
// Table 1 in [2] suggests that size should be >= 1024 when using 3 primes.
|
||||||
|
//
|
||||||
|
// [1] US patent 4405829 (1972, expired)
|
||||||
|
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
|
||||||
|
func Generate3PrimeKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
|
||||||
|
priv = new(PrivateKey)
|
||||||
|
priv.E = 3
|
||||||
|
|
||||||
|
pminus1 := new(big.Int)
|
||||||
|
qminus1 := new(big.Int)
|
||||||
|
rminus1 := new(big.Int)
|
||||||
|
totient := new(big.Int)
|
||||||
|
|
||||||
|
for {
|
||||||
|
p, err := randomPrime(rand, bits/3)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
todo := bits - p.BitLen()
|
||||||
|
q, err := randomPrime(rand, todo/2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
todo -= q.BitLen()
|
||||||
|
r, err := randomPrime(rand, todo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Cmp(q) == 0 ||
|
||||||
|
q.Cmp(r) == 0 ||
|
||||||
|
r.Cmp(p) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
n := new(big.Int).Mul(p, q)
|
||||||
|
n.Mul(n, r)
|
||||||
|
pminus1.Sub(p, bigOne)
|
||||||
|
qminus1.Sub(q, bigOne)
|
||||||
|
rminus1.Sub(r, bigOne)
|
||||||
|
totient.Mul(pminus1, qminus1)
|
||||||
|
totient.Mul(totient, rminus1)
|
||||||
|
|
||||||
|
g := new(big.Int)
|
||||||
|
priv.D = new(big.Int)
|
||||||
|
y := new(big.Int)
|
||||||
|
e := big.NewInt(int64(priv.E))
|
||||||
|
big.GcdInt(g, priv.D, y, e, totient)
|
||||||
|
|
||||||
|
if g.Cmp(bigOne) == 0 {
|
||||||
|
priv.D.Add(priv.D, totient)
|
||||||
|
priv.P = p
|
||||||
|
priv.Q = q
|
||||||
|
priv.R = r
|
||||||
|
priv.N = n
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// incCounter increments a four byte, big-endian counter.
|
// incCounter increments a four byte, big-endian counter.
|
||||||
func incCounter(c *[4]byte) {
|
func incCounter(c *[4]byte) {
|
||||||
if c[3]++; c[3] != 0 {
|
if c[3]++; c[3] != 0 {
|
||||||
@ -336,6 +419,14 @@ func (priv *PrivateKey) precompute() {
|
|||||||
priv.dQ.Mod(priv.D, priv.dQ)
|
priv.dQ.Mod(priv.D, priv.dQ)
|
||||||
|
|
||||||
priv.qInv = new(big.Int).ModInverse(priv.Q, priv.P)
|
priv.qInv = new(big.Int).ModInverse(priv.Q, priv.P)
|
||||||
|
|
||||||
|
if priv.R != nil {
|
||||||
|
priv.dR = new(big.Int).Sub(priv.R, bigOne)
|
||||||
|
priv.dR.Mod(priv.D, priv.dR)
|
||||||
|
|
||||||
|
priv.pq = new(big.Int).Mul(priv.P, priv.Q)
|
||||||
|
priv.tr = new(big.Int).ModInverse(priv.pq, priv.R)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
|
// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
|
||||||
@ -402,6 +493,19 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
|
|||||||
m.Mod(m, priv.P)
|
m.Mod(m, priv.P)
|
||||||
m.Mul(m, priv.Q)
|
m.Mul(m, priv.Q)
|
||||||
m.Add(m, m2)
|
m.Add(m, m2)
|
||||||
|
|
||||||
|
if priv.dR != nil {
|
||||||
|
// 3-prime CRT.
|
||||||
|
m2.Exp(c, priv.dR, priv.R)
|
||||||
|
m2.Sub(m2, m)
|
||||||
|
m2.Mul(m2, priv.tr)
|
||||||
|
m2.Mod(m2, priv.R)
|
||||||
|
if m2.Sign() < 0 {
|
||||||
|
m2.Add(m2, priv.R)
|
||||||
|
}
|
||||||
|
m2.Mul(m2, priv.pq)
|
||||||
|
m.Add(m, m2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
priv.rwMutex.RUnlock()
|
priv.rwMutex.RUnlock()
|
||||||
|
@ -21,15 +21,37 @@ func TestKeyGeneration(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to generate key")
|
t.Errorf("failed to generate key")
|
||||||
}
|
}
|
||||||
|
testKeyBasics(t, priv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test3PrimeKeyGeneration(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
size := 768
|
||||||
|
priv, err := Generate3PrimeKey(rand.Reader, size)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to generate key")
|
||||||
|
}
|
||||||
|
testKeyBasics(t, priv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testKeyBasics(t *testing.T, priv *PrivateKey) {
|
||||||
|
if err := priv.Validate(); err != nil {
|
||||||
|
t.Errorf("Validate() failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
pub := &priv.PublicKey
|
pub := &priv.PublicKey
|
||||||
m := big.NewInt(42)
|
m := big.NewInt(42)
|
||||||
c := encrypt(new(big.Int), pub, m)
|
c := encrypt(new(big.Int), pub, m)
|
||||||
m2, err := decrypt(nil, priv, c)
|
m2, err := decrypt(nil, priv, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error while decrypting: %s", err)
|
t.Errorf("error while decrypting: %s", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if m.Cmp(m2) != 0 {
|
if m.Cmp(m2) != 0 {
|
||||||
t.Errorf("got:%v, want:%v (%s)", m2, m, priv)
|
t.Errorf("got:%v, want:%v (%+v)", m2, m, priv)
|
||||||
}
|
}
|
||||||
|
|
||||||
m3, err := decrypt(rand.Reader, priv, c)
|
m3, err := decrypt(rand.Reader, priv, c)
|
||||||
@ -69,6 +91,29 @@ func BenchmarkRSA2048Decrypt(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
priv := &PrivateKey{
|
||||||
|
PublicKey: PublicKey{
|
||||||
|
N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
|
||||||
|
E: 3,
|
||||||
|
},
|
||||||
|
D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
|
||||||
|
P: fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
|
||||||
|
Q: fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
|
||||||
|
R: fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
|
||||||
|
}
|
||||||
|
priv.precompute()
|
||||||
|
|
||||||
|
c := fromBase10("1000")
|
||||||
|
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
decrypt(nil, priv, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type testEncryptOAEPMessage struct {
|
type testEncryptOAEPMessage struct {
|
||||||
in []byte
|
in []byte
|
||||||
seed []byte
|
seed []byte
|
||||||
|
Loading…
Reference in New Issue
Block a user