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
a8ba4082
Commit
a8ba4082
authored
Nov 18, 2009
by
Adam Langley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypto/rsa: add PKCS#1 v1.5 signature support.
R=rsc CC=golang-dev
https://golang.org/cl/156051
parent
80b7f6a8
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
179 additions
and
0 deletions
+179
-0
pkcs1v15.go
src/pkg/crypto/rsa/pkcs1v15.go
+128
-0
pkcs1v15_test.go
src/pkg/crypto/rsa/pkcs1v15_test.go
+45
-0
rsa.go
src/pkg/crypto/rsa/rsa.go
+6
-0
No files found.
src/pkg/crypto/rsa/pkcs1v15.go
View file @
a8ba4082
...
@@ -136,3 +136,131 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
...
@@ -136,3 +136,131 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
return
;
return
;
}
}
// Due to the design of PKCS#1 v1.5, we need to know the exact hash function in
// use. A generic hash.Hash will not do.
type
PKCS1v15Hash
int
const
(
HashMD5
PKCS1v15Hash
=
iota
;
HashSHA1
;
HashSHA256
;
HashSHA384
;
HashSHA512
;
)
// These are ASN1 DER structures:
// DigestInfo ::= SEQUENCE {
// digestAlgorithm AlgorithmIdentifier,
// digest OCTET STRING
// }
// For performance, we don't use the generic ASN1 encoding. Rather, we
// precompute a prefix of the digest value that makes a valid ASN1 DER string
// with the correct contents.
var
hashPrefixes
=
[][]
byte
{
// HashMD5
[]
byte
{
0x30
,
0x20
,
0x30
,
0x0c
,
0x06
,
0x08
,
0x2a
,
0x86
,
0x48
,
0x86
,
0xf7
,
0x0d
,
0x02
,
0x05
,
0x05
,
0x00
,
0x04
,
0x10
},
// HashSHA1
[]
byte
{
0x30
,
0x21
,
0x30
,
0x09
,
0x06
,
0x05
,
0x2b
,
0x0e
,
0x03
,
0x02
,
0x1a
,
0x05
,
0x00
,
0x04
,
0x14
},
// HashSHA256
[]
byte
{
0x30
,
0x31
,
0x30
,
0x0d
,
0x06
,
0x09
,
0x60
,
0x86
,
0x48
,
0x01
,
0x65
,
0x03
,
0x04
,
0x02
,
0x01
,
0x05
,
0x00
,
0x04
,
0x20
},
// HashSHA384
[]
byte
{
0x30
,
0x41
,
0x30
,
0x0d
,
0x06
,
0x09
,
0x60
,
0x86
,
0x48
,
0x01
,
0x65
,
0x03
,
0x04
,
0x02
,
0x02
,
0x05
,
0x00
,
0x04
,
0x30
},
// HashSHA512
[]
byte
{
0x30
,
0x51
,
0x30
,
0x0d
,
0x06
,
0x09
,
0x60
,
0x86
,
0x48
,
0x01
,
0x65
,
0x03
,
0x04
,
0x02
,
0x03
,
0x05
,
0x00
,
0x04
,
0x40
},
}
// SignPKCS1v15 calcuates the signature of hashed using RSASSA-PSS-SIGN from RSA PKCS#1 v1.5.
// Note that hashed must be the result of hashing the input message using the
// given hash function.
func
SignPKCS1v15
(
rand
io
.
Reader
,
priv
*
PrivateKey
,
hash
PKCS1v15Hash
,
hashed
[]
byte
)
(
s
[]
byte
,
err
os
.
Error
)
{
hashLen
,
prefix
,
err
:=
pkcs1v15HashInfo
(
hash
,
len
(
hashed
));
if
err
!=
nil
{
return
}
tLen
:=
len
(
prefix
)
+
hashLen
;
k
:=
(
priv
.
N
.
Len
()
+
7
)
/
8
;
if
k
<
tLen
+
11
{
return
nil
,
MessageTooLongError
{}
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
em
:=
make
([]
byte
,
k
);
em
[
1
]
=
1
;
for
i
:=
2
;
i
<
k
-
tLen
-
1
;
i
++
{
em
[
i
]
=
0xff
}
bytes
.
Copy
(
em
[
k
-
tLen
:
k
-
hashLen
],
prefix
);
bytes
.
Copy
(
em
[
k
-
hashLen
:
k
],
hashed
);
m
:=
new
(
big
.
Int
)
.
SetBytes
(
em
);
c
,
err
:=
decrypt
(
rand
,
priv
,
m
);
if
err
==
nil
{
s
=
c
.
Bytes
()
}
return
;
}
// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
// hashed is the result of hashing the input message using the given hash
// function and sig is the signature. A valid signature is indicated by
// returning a nil error.
func
VerifyPKCS1v15
(
pub
*
PublicKey
,
hash
PKCS1v15Hash
,
hashed
[]
byte
,
sig
[]
byte
)
(
err
os
.
Error
)
{
hashLen
,
prefix
,
err
:=
pkcs1v15HashInfo
(
hash
,
len
(
hashed
));
if
err
!=
nil
{
return
}
tLen
:=
len
(
prefix
)
+
hashLen
;
k
:=
(
pub
.
N
.
Len
()
+
7
)
/
8
;
if
k
<
tLen
+
11
{
err
=
VerificationError
{};
return
;
}
c
:=
new
(
big
.
Int
)
.
SetBytes
(
sig
);
m
:=
encrypt
(
new
(
big
.
Int
),
pub
,
c
);
em
:=
leftPad
(
m
.
Bytes
(),
k
);
// EM = 0x00 || 0x01 || PS || 0x00 || T
ok
:=
subtle
.
ConstantTimeByteEq
(
em
[
0
],
0
);
ok
&=
subtle
.
ConstantTimeByteEq
(
em
[
1
],
1
);
ok
&=
subtle
.
ConstantTimeCompare
(
em
[
k
-
hashLen
:
k
],
hashed
);
ok
&=
subtle
.
ConstantTimeCompare
(
em
[
k
-
tLen
:
k
-
hashLen
],
prefix
);
ok
&=
subtle
.
ConstantTimeByteEq
(
em
[
k
-
tLen
-
1
],
0
);
for
i
:=
2
;
i
<
k
-
tLen
-
1
;
i
++
{
ok
&=
subtle
.
ConstantTimeByteEq
(
em
[
i
],
0xff
)
}
if
ok
!=
1
{
return
VerificationError
{}
}
return
nil
;
}
func
pkcs1v15HashInfo
(
hash
PKCS1v15Hash
,
inLen
int
)
(
hashLen
int
,
prefix
[]
byte
,
err
os
.
Error
)
{
switch
hash
{
case
HashMD5
:
hashLen
=
16
case
HashSHA1
:
hashLen
=
20
case
HashSHA256
:
hashLen
=
32
case
HashSHA384
:
hashLen
=
48
case
HashSHA512
:
hashLen
=
64
default
:
return
0
,
nil
,
os
.
ErrorString
(
"unknown hash function"
)
}
if
inLen
!=
hashLen
{
return
0
,
nil
,
os
.
ErrorString
(
"input must be hashed message"
)
}
prefix
=
hashPrefixes
[
int
(
hash
)];
return
;
}
src/pkg/crypto/rsa/pkcs1v15_test.go
View file @
a8ba4082
...
@@ -7,7 +7,9 @@ package rsa
...
@@ -7,7 +7,9 @@ package rsa
import
(
import
(
"big"
;
"big"
;
"bytes"
;
"bytes"
;
"crypto/sha1"
;
"encoding/base64"
;
"encoding/base64"
;
"encoding/hex"
;
"os"
;
"os"
;
"io"
;
"io"
;
"strings"
;
"strings"
;
...
@@ -154,6 +156,49 @@ func TestNonZeroRandomBytes(t *testing.T) {
...
@@ -154,6 +156,49 @@ func TestNonZeroRandomBytes(t *testing.T) {
}
}
}
}
type
signPKCS1v15Test
struct
{
in
,
out
string
;
}
// These vectors have been tested with
// `openssl rsautl -verify -inkey pk -in signature | hexdump -C`
var
signPKCS1v15Tests
=
[]
signPKCS1v15Test
{
signPKCS1v15Test
{
"Test.
\n
"
,
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
},
}
func
TestSignPKCS1v15
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
signPKCS1v15Tests
{
h
:=
sha1
.
New
();
h
.
Write
(
strings
.
Bytes
(
test
.
in
));
digest
:=
h
.
Sum
();
s
,
err
:=
SignPKCS1v15
(
nil
,
rsaPrivateKey
,
HashSHA1
,
digest
);
if
err
!=
nil
{
t
.
Errorf
(
"#%d %s"
,
i
,
err
)
}
expected
,
_
:=
hex
.
DecodeString
(
test
.
out
);
if
bytes
.
Compare
(
s
,
expected
)
!=
0
{
t
.
Errorf
(
"#%d got: %x want: %x"
,
i
,
s
,
expected
)
}
}
}
func
TestVerifyPKCS1v15
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
signPKCS1v15Tests
{
h
:=
sha1
.
New
();
h
.
Write
(
strings
.
Bytes
(
test
.
in
));
digest
:=
h
.
Sum
();
sig
,
_
:=
hex
.
DecodeString
(
test
.
out
);
err
:=
VerifyPKCS1v15
(
&
rsaPrivateKey
.
PublicKey
,
HashSHA1
,
digest
,
sig
);
if
err
!=
nil
{
t
.
Errorf
(
"#%d %s"
,
i
,
err
)
}
}
}
func
bigFromString
(
s
string
)
*
big
.
Int
{
func
bigFromString
(
s
string
)
*
big
.
Int
{
ret
:=
new
(
big
.
Int
);
ret
:=
new
(
big
.
Int
);
ret
.
SetString
(
s
,
10
);
ret
.
SetString
(
s
,
10
);
...
...
src/pkg/crypto/rsa/rsa.go
View file @
a8ba4082
...
@@ -288,6 +288,12 @@ type DecryptionError struct{}
...
@@ -288,6 +288,12 @@ type DecryptionError struct{}
func
(
DecryptionError
)
String
()
string
{
return
"RSA decryption error"
}
func
(
DecryptionError
)
String
()
string
{
return
"RSA decryption error"
}
// A VerificationError represents a failure to verify a signature.
// It is deliberately vague to avoid adaptive attacks.
type
VerificationError
struct
{}
func
(
VerificationError
)
String
()
string
{
return
"RSA verification error"
}
// modInverse returns ia, the inverse of a in the multiplicative group of prime
// modInverse returns ia, the inverse of a in the multiplicative group of prime
// order n. It requires that a be a member of the group (i.e. less than n).
// order n. It requires that a be a member of the group (i.e. less than n).
func
modInverse
(
a
,
n
*
big
.
Int
)
(
ia
*
big
.
Int
,
ok
bool
)
{
func
modInverse
(
a
,
n
*
big
.
Int
)
(
ia
*
big
.
Int
,
ok
bool
)
{
...
...
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