Skip to content

Commit 78c16c9

Browse files
committed
crypto/rsa: support unpadded signatures.
Usually when a message is signed it's first hashed because RSA has low limits on the size of messages that it can sign. However, some protocols sign short messages directly. This isn't a great idea because the messages that can be signed suddenly depend on the size of the RSA key, but several people on golang-nuts have requested support for this and it's very easy to do. R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/44400043
1 parent 90e9669 commit 78c16c9

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

src/pkg/crypto/rsa/pkcs1v15.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ var hashPrefixes = map[crypto.Hash][]byte{
176176

177177
// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
178178
// Note that hashed must be the result of hashing the input message using the
179-
// given hash function.
179+
// given hash function. If hash is zero, hashed is signed directly. This isn't
180+
// advisable except for interoperability.
180181
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
181182
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
182183
if err != nil {
@@ -212,7 +213,8 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
212213
// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
213214
// hashed is the result of hashing the input message using the given hash
214215
// function and sig is the signature. A valid signature is indicated by
215-
// returning a nil error.
216+
// returning a nil error. If hash is zero then hashed is used directly. This
217+
// isn't advisable except for interopability.
216218
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
217219
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
218220
if err != nil {
@@ -249,6 +251,12 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
249251
}
250252

251253
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
254+
// Special case: crypto.Hash(0) is used to indicate that the data is
255+
// signed directly.
256+
if hash == 0 {
257+
return inLen, nil, nil
258+
}
259+
252260
hashLen = hash.Size()
253261
if inLen != hashLen {
254262
return 0, nil, errors.New("crypto/rsa: input must be hashed message")

src/pkg/crypto/rsa/pkcs1v15_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,28 @@ func TestOverlongMessagePKCS1v15(t *testing.T) {
205205
}
206206
}
207207

208+
func TestUnpaddedSignature(t *testing.T) {
209+
msg := []byte("Thu Dec 19 18:06:16 EST 2013\n")
210+
// This base64 value was generated with:
211+
// % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg
212+
// % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg
213+
//
214+
// Where "key" contains the RSA private key given at the bottom of this
215+
// file.
216+
expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==")
217+
218+
sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg)
219+
if err != nil {
220+
t.Fatalf("SignPKCS1v15 failed: %s", err)
221+
}
222+
if !bytes.Equal(sig, expectedSig) {
223+
t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig)
224+
}
225+
if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil {
226+
t.Fatalf("signature failed to verify: %s", err)
227+
}
228+
}
229+
208230
// In order to generate new test vectors you'll need the PEM form of this key:
209231
// -----BEGIN RSA PRIVATE KEY-----
210232
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0

0 commit comments

Comments
 (0)