aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/crypto/rsa/pkcs1v15.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/rsa/pkcs1v15.go')
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 96a8c6912d..f60d2b3970 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -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;
+}