Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
41971434
Commit
41971434
authored
Apr 06, 2011
by
Adam Langley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypto/rsa: add 3-prime support.
R=golang-dev, rsc1 CC=golang-dev
https://golang.org/cl/4365041
parent
057bdfe3
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
160 additions
and
11 deletions
+160
-11
rsa.go
src/pkg/crypto/rsa/rsa.go
+114
-10
rsa_test.go
src/pkg/crypto/rsa/rsa_test.go
+46
-1
No files found.
src/pkg/crypto/rsa/rsa.go
View file @
41971434
...
...
@@ -92,19 +92,21 @@ type PublicKey struct {
type
PrivateKey
struct
{
PublicKey
// public part.
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
dP
,
dQ
*
big
.
Int
// D mod (P-1) (or mod Q-1)
qInv
*
big
.
Int
// q^-1 mod p
rwMutex
sync
.
RWMutex
// protects the following
dP
,
dQ
,
dR
*
big
.
Int
// D mod (P-1) (or mod Q-1 etc)
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.
// It returns nil if the key is valid, or else an os.Error describing a problem.
func
(
priv
*
PrivateKey
)
Validate
()
os
.
Error
{
// Check that p
and q are prime. Note that this is just a sanity
// check. Since the random witnesses chosen by ProbablyPrime are
// Check that p
, q and, maybe, r are prime. Note that this is just a
//
sanity
check. Since the random witnesses chosen by ProbablyPrime are
// deterministic, given the candidate number, it's easy for an attack
// to generate composites that pass this test.
if
!
big
.
ProbablyPrime
(
priv
.
P
,
20
)
{
...
...
@@ -113,16 +115,26 @@ func (priv *PrivateKey) Validate() os.Error {
if
!
big
.
ProbablyPrime
(
priv
.
Q
,
20
)
{
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
)
if
priv
.
R
!=
nil
{
modulus
.
Mul
(
modulus
,
priv
.
R
)
}
if
modulus
.
Cmp
(
priv
.
N
)
!=
0
{
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
)
qminus1
:=
new
(
big
.
Int
)
.
Sub
(
priv
.
Q
,
bigOne
)
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
))
gcd
:=
new
(
big
.
Int
)
x
:=
new
(
big
.
Int
)
...
...
@@ -131,7 +143,7 @@ func (priv *PrivateKey) Validate() os.Error {
if
gcd
.
Cmp
(
bigOne
)
!=
0
{
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
.
Mod
(
de
,
totient
)
if
de
.
Cmp
(
bigOne
)
!=
0
{
...
...
@@ -140,7 +152,7 @@ func (priv *PrivateKey) Validate() os.Error {
return
nil
}
// GenerateKey
Pair
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
)
{
priv
=
new
(
PrivateKey
)
// 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
}
// 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.
func
incCounter
(
c
*
[
4
]
byte
)
{
if
c
[
3
]
++
;
c
[
3
]
!=
0
{
...
...
@@ -336,6 +419,14 @@ func (priv *PrivateKey) precompute() {
priv
.
dQ
.
Mod
(
priv
.
D
,
priv
.
dQ
)
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
...
...
@@ -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
.
Mul
(
m
,
priv
.
Q
)
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
()
...
...
src/pkg/crypto/rsa/rsa_test.go
View file @
41971434
...
...
@@ -21,15 +21,37 @@ func TestKeyGeneration(t *testing.T) {
if
err
!=
nil
{
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
m
:=
big
.
NewInt
(
42
)
c
:=
encrypt
(
new
(
big
.
Int
),
pub
,
m
)
m2
,
err
:=
decrypt
(
nil
,
priv
,
c
)
if
err
!=
nil
{
t
.
Errorf
(
"error while decrypting: %s"
,
err
)
return
}
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
)
...
...
@@ -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
{
in
[]
byte
seed
[]
byte
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment