mirror of
https://github.com/golang/go
synced 2024-11-20 04:44:40 -07:00
crypto/rsa: add PKCS#1 v1.5 signature support.
R=rsc CC=golang-dev https://golang.org/cl/156051
This commit is contained in:
parent
80b7f6a8d4
commit
a8ba40823c
@ -136,3 +136,131 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ package rsa
|
||||
import (
|
||||
"big";
|
||||
"bytes";
|
||||
"crypto/sha1";
|
||||
"encoding/base64";
|
||||
"encoding/hex";
|
||||
"os";
|
||||
"io";
|
||||
"strings";
|
||||
@ -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 {
|
||||
ret := new(big.Int);
|
||||
ret.SetString(s, 10);
|
||||
|
@ -288,6 +288,12 @@ type DecryptionError struct{}
|
||||
|
||||
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
|
||||
// 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) {
|
||||
|
Loading…
Reference in New Issue
Block a user