| // Copyright 2013 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package rsa | |
| // This file implements the PSS signature scheme [1]. | |
| // | |
| // [1] https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf | |
| import ( | |
| "bytes" | |
| "crypto" | |
| "errors" | |
| "hash" | |
| "io" | |
| "math/big" | |
| ) | |
| func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { | |
| // See [1], section 9.1.1 | |
| hLen := hash.Size() | |
| sLen := len(salt) | |
| emLen := (emBits + 7) / 8 | |
| // 1. If the length of M is greater than the input limitation for the | |
| // hash function (2^61 - 1 octets for SHA-1), output "message too | |
| // long" and stop. | |
| // | |
| // 2. Let mHash = Hash(M), an octet string of length hLen. | |
| if len(mHash) != hLen { | |
| return nil, errors.New("crypto/rsa: input must be hashed message") | |
| } | |
| // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. | |
| if emLen < hLen+sLen+2 { | |
| return nil, errors.New("crypto/rsa: key size too small for PSS signature") | |
| } | |
| em := make([]byte, emLen) | |
| db := em[:emLen-sLen-hLen-2+1+sLen] | |
| h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] | |
| // 4. Generate a random octet string salt of length sLen; if sLen = 0, | |
| // then salt is the empty string. | |
| // | |
| // 5. Let | |
| // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; | |
| // | |
| // M' is an octet string of length 8 + hLen + sLen with eight | |
| // initial zero octets. | |
| // | |
| // 6. Let H = Hash(M'), an octet string of length hLen. | |
| var prefix [8]byte | |
| hash.Write(prefix[:]) | |
| hash.Write(mHash) | |
| hash.Write(salt) | |
| h = hash.Sum(h[:0]) | |
| hash.Reset() | |
| // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 | |
| // zero octets. The length of PS may be 0. | |
| // | |
| // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length | |
| // emLen - hLen - 1. | |
| db[emLen-sLen-hLen-2] = 0x01 | |
| copy(db[emLen-sLen-hLen-1:], salt) | |
| // 9. Let dbMask = MGF(H, emLen - hLen - 1). | |
| // | |
| // 10. Let maskedDB = DB \xor dbMask. | |
| mgf1XOR(db, hash, h) | |
| // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in | |
| // maskedDB to zero. | |
| db[0] &= (0xFF >> uint(8*emLen-emBits)) | |
| // 12. Let EM = maskedDB || H || 0xbc. | |
| em[emLen-1] = 0xBC | |
| // 13. Output EM. | |
| return em, nil | |
| } | |
| func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { | |
| // 1. If the length of M is greater than the input limitation for the | |
| // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" | |
| // and stop. | |
| // | |
| // 2. Let mHash = Hash(M), an octet string of length hLen. | |
| hLen := hash.Size() | |
| if hLen != len(mHash) { | |
| return ErrVerification | |
| } | |
| // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. | |
| emLen := (emBits + 7) / 8 | |
| if emLen < hLen+sLen+2 { | |
| return ErrVerification | |
| } | |
| // 4. If the rightmost octet of EM does not have hexadecimal value | |
| // 0xbc, output "inconsistent" and stop. | |
| if em[len(em)-1] != 0xBC { | |
| return ErrVerification | |
| } | |
| // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and | |
| // let H be the next hLen octets. | |
| db := em[:emLen-hLen-1] | |
| h := em[emLen-hLen-1 : len(em)-1] | |
| // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in | |
| // maskedDB are not all equal to zero, output "inconsistent" and | |
| // stop. | |
| if em[0]&(0xFF<<uint(8-(8*emLen-emBits))) != 0 { | |
| return ErrVerification | |
| } | |
| // 7. Let dbMask = MGF(H, emLen - hLen - 1). | |
| // | |
| // 8. Let DB = maskedDB \xor dbMask. | |
| mgf1XOR(db, hash, h) | |
| // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB | |
| // to zero. | |
| db[0] &= (0xFF >> uint(8*emLen-emBits)) | |
| if sLen == PSSSaltLengthAuto { | |
| FindSaltLength: | |
| for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { | |
| switch db[emLen-hLen-sLen-2] { | |
| case 1: | |
| break FindSaltLength | |
| case 0: | |
| continue | |
| default: | |
| return ErrVerification | |
| } | |
| } | |
| if sLen < 0 { | |
| return ErrVerification | |
| } | |
| } else { | |
| // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero | |
| // or if the octet at position emLen - hLen - sLen - 1 (the leftmost | |
| // position is "position 1") does not have hexadecimal value 0x01, | |
| // output "inconsistent" and stop. | |
| for _, e := range db[:emLen-hLen-sLen-2] { | |
| if e != 0x00 { | |
| return ErrVerification | |
| } | |
| } | |
| if db[emLen-hLen-sLen-2] != 0x01 { | |
| return ErrVerification | |
| } | |
| } | |
| // 11. Let salt be the last sLen octets of DB. | |
| salt := db[len(db)-sLen:] | |
| // 12. Let | |
| // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; | |
| // M' is an octet string of length 8 + hLen + sLen with eight | |
| // initial zero octets. | |
| // | |
| // 13. Let H' = Hash(M'), an octet string of length hLen. | |
| var prefix [8]byte | |
| hash.Write(prefix[:]) | |
| hash.Write(mHash) | |
| hash.Write(salt) | |
| h0 := hash.Sum(nil) | |
| // 14. If H = H', output "consistent." Otherwise, output "inconsistent." | |
| if !bytes.Equal(h0, h) { | |
| return ErrVerification | |
| } | |
| return nil | |
| } | |
| // signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt. | |
| // Note that hashed must be the result of hashing the input message using the | |
| // given hash function. salt is a random sequence of bytes whose length will be | |
| // later used to verify the signature. | |
| func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { | |
| nBits := priv.N.BitLen() | |
| em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New()) | |
| if err != nil { | |
| return | |
| } | |
| m := new(big.Int).SetBytes(em) | |
| c, err := decryptAndCheck(rand, priv, m) | |
| if err != nil { | |
| return | |
| } | |
| s = make([]byte, (nBits+7)/8) | |
| copyWithLeftPad(s, c.Bytes()) | |
| return | |
| } | |
| const ( | |
| // PSSSaltLengthAuto causes the salt in a PSS signature to be as large | |
| // as possible when signing, and to be auto-detected when verifying. | |
| PSSSaltLengthAuto = 0 | |
| // PSSSaltLengthEqualsHash causes the salt length to equal the length | |
| // of the hash used in the signature. | |
| PSSSaltLengthEqualsHash = -1 | |
| ) | |
| // PSSOptions contains options for creating and verifying PSS signatures. | |
| type PSSOptions struct { | |
| // SaltLength controls the length of the salt used in the PSS | |
| // signature. It can either be a number of bytes, or one of the special | |
| // PSSSaltLength constants. | |
| SaltLength int | |
| // Hash, if not zero, overrides the hash function passed to SignPSS. | |
| // This is the only way to specify the hash function when using the | |
| // crypto.Signer interface. | |
| Hash crypto.Hash | |
| } | |
| // HashFunc returns pssOpts.Hash so that PSSOptions implements | |
| // crypto.SignerOpts. | |
| func (pssOpts *PSSOptions) HashFunc() crypto.Hash { | |
| return pssOpts.Hash | |
| } | |
| func (opts *PSSOptions) saltLength() int { | |
| if opts == nil { | |
| return PSSSaltLengthAuto | |
| } | |
| return opts.SaltLength | |
| } | |
| // SignPSS calculates the signature of hashed using RSASSA-PSS [1]. | |
| // Note that hashed must be the result of hashing the input message using the | |
| // given hash function. The opts argument may be nil, in which case sensible | |
| // defaults are used. | |
| func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error) { | |
| saltLength := opts.saltLength() | |
| switch saltLength { | |
| case PSSSaltLengthAuto: | |
| saltLength = (priv.N.BitLen()+7)/8 - 2 - hash.Size() | |
| case PSSSaltLengthEqualsHash: | |
| saltLength = hash.Size() | |
| } | |
| if opts != nil && opts.Hash != 0 { | |
| hash = opts.Hash | |
| } | |
| salt := make([]byte, saltLength) | |
| if _, err := io.ReadFull(rand, salt); err != nil { | |
| return nil, err | |
| } | |
| return signPSSWithSalt(rand, priv, hash, hashed, salt) | |
| } | |
| // VerifyPSS verifies a PSS 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. The opts argument may be nil, in which case sensible | |
| // defaults are used. | |
| func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error { | |
| return verifyPSS(pub, hash, hashed, sig, opts.saltLength()) | |
| } | |
| // verifyPSS verifies a PSS signature with the given salt length. | |
| func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, saltLen int) error { | |
| nBits := pub.N.BitLen() | |
| if len(sig) != (nBits+7)/8 { | |
| return ErrVerification | |
| } | |
| s := new(big.Int).SetBytes(sig) | |
| m := encrypt(new(big.Int), pub, s) | |
| emBits := nBits - 1 | |
| emLen := (emBits + 7) / 8 | |
| if emLen < len(m.Bytes()) { | |
| return ErrVerification | |
| } | |
| em := make([]byte, emLen) | |
| copyWithLeftPad(em, m.Bytes()) | |
| if saltLen == PSSSaltLengthEqualsHash { | |
| saltLen = hash.Size() | |
| } | |
| return emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()) | |
| } |