| // 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 RSASSA-PSS signature scheme and the RSAES-OAEP |
| // encryption scheme according to RFC 8017, aka PKCS #1 v2.2. |
| |
| import ( |
| "bytes" |
| "crypto/internal/constanttime" |
| "crypto/internal/fips140" |
| "crypto/internal/fips140/drbg" |
| "crypto/internal/fips140/sha256" |
| "crypto/internal/fips140/sha3" |
| "crypto/internal/fips140/sha512" |
| "crypto/internal/fips140/subtle" |
| "errors" |
| "hash" |
| "io" |
| ) |
| |
| // Per RFC 8017, Section 9.1 |
| // |
| // EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc |
| // |
| // where |
| // |
| // DB = PS || 0x01 || salt |
| // |
| // and PS can be empty so |
| // |
| // emLen = dbLen + hLen + 1 = psLen + sLen + hLen + 2 |
| // |
| |
| // incCounter increments a four byte, big-endian counter. |
| func incCounter(c *[4]byte) { |
| if c[3]++; c[3] != 0 { |
| return |
| } |
| if c[2]++; c[2] != 0 { |
| return |
| } |
| if c[1]++; c[1] != 0 { |
| return |
| } |
| c[0]++ |
| } |
| |
| // mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function |
| // specified in PKCS #1 v2.1. |
| func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { |
| var counter [4]byte |
| var digest []byte |
| |
| done := 0 |
| for done < len(out) { |
| hash.Reset() |
| hash.Write(seed) |
| hash.Write(counter[0:4]) |
| digest = hash.Sum(digest[:0]) |
| |
| for i := 0; i < len(digest) && done < len(out); i++ { |
| out[done] ^= digest[i] |
| done++ |
| } |
| incCounter(&counter) |
| } |
| } |
| |
| func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { |
| // See RFC 8017, 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 with given hash") |
| } |
| |
| // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. |
| |
| if emLen < hLen+sLen+2 { |
| return nil, ErrMessageTooLong |
| } |
| |
| em := make([]byte, emLen) |
| psLen := emLen - sLen - hLen - 2 |
| db := em[:psLen+1+sLen] |
| h := em[psLen+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.Reset() |
| hash.Write(prefix[:]) |
| hash.Write(mHash) |
| hash.Write(salt) |
| |
| h = hash.Sum(h[:0]) |
| |
| // 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[psLen] = 0x01 |
| copy(db[psLen+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 >> (8*emLen - emBits) |
| |
| // 12. Let EM = maskedDB || H || 0xbc. |
| em[emLen-1] = 0xbc |
| |
| // 13. Output EM. |
| return em, nil |
| } |
| |
| const pssSaltLengthAutodetect = -1 |
| |
| func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { |
| // See RFC 8017, Section 9.1.2. |
| |
| hLen := hash.Size() |
| emLen := (emBits + 7) / 8 |
| if emLen != len(em) { |
| return errors.New("rsa: internal error: inconsistent length") |
| } |
| |
| // 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. |
| if hLen != len(mHash) { |
| return ErrVerification |
| } |
| |
| // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. |
| 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[emLen-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 : emLen-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. |
| var bitMask byte = 0xff >> (8*emLen - emBits) |
| if em[0] & ^bitMask != 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] &= bitMask |
| |
| // If we don't know the salt length, look for the 0x01 delimiter. |
| if sLen == pssSaltLengthAutodetect { |
| psLen := bytes.IndexByte(db, 0x01) |
| if psLen < 0 { |
| return ErrVerification |
| } |
| sLen = len(db) - psLen - 1 |
| } |
| |
| // FIPS 186-5, Section 5.4(g): "the length (in bytes) of the salt (sLen) |
| // shall satisfy 0 ≤ sLen ≤ hLen". |
| if sLen > hLen { |
| fips140.RecordNonApproved() |
| } |
| |
| // 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. |
| psLen := emLen - hLen - sLen - 2 |
| for _, e := range db[:psLen] { |
| if e != 0x00 { |
| return ErrVerification |
| } |
| } |
| if db[psLen] != 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. |
| hash.Reset() |
| 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 |
| } |
| |
| // PSSMaxSaltLength returns the maximum salt length for a given public key and |
| // hash function. |
| func PSSMaxSaltLength(pub *PublicKey, hash hash.Hash) (int, error) { |
| saltLength := (pub.N.BitLen()-1+7)/8 - 2 - hash.Size() |
| if saltLength < 0 { |
| return 0, ErrMessageTooLong |
| } |
| // FIPS 186-5, Section 5.4(g): "the length (in bytes) of the salt (sLen) |
| // shall satisfy 0 ≤ sLen ≤ hLen". |
| if fips140.Enabled && saltLength > hash.Size() { |
| return hash.Size(), nil |
| } |
| return saltLength, nil |
| } |
| |
| // SignPSS calculates the signature of hashed using RSASSA-PSS. |
| func SignPSS(rand io.Reader, priv *PrivateKey, hash hash.Hash, hashed []byte, saltLength int) ([]byte, error) { |
| fipsSelfTest() |
| fips140.RecordApproved() |
| checkApprovedHash(hash) |
| |
| // Note that while we don't commit to deterministic execution with respect |
| // to the rand stream, we also never applied MaybeReadByte, so per Hyrum's |
| // Law it's probably relied upon by some. It's a tolerable promise because a |
| // well-specified number of random bytes is included in the signature, in a |
| // well-specified way. |
| |
| if saltLength < 0 { |
| return nil, errors.New("crypto/rsa: salt length cannot be negative") |
| } |
| // FIPS 186-5, Section 5.4(g): "the length (in bytes) of the salt (sLen) |
| // shall satisfy 0 ≤ sLen ≤ hLen". |
| if saltLength > hash.Size() { |
| fips140.RecordNonApproved() |
| } |
| salt := make([]byte, saltLength) |
| if err := drbg.ReadWithReader(rand, salt); err != nil { |
| return nil, err |
| } |
| |
| emBits := priv.pub.N.BitLen() - 1 |
| em, err := emsaPSSEncode(hashed, emBits, salt, hash) |
| if err != nil { |
| return nil, err |
| } |
| |
| // RFC 8017: "Note that the octet length of EM will be one less than k if |
| // modBits - 1 is divisible by 8 and equal to k otherwise, where k is the |
| // length in octets of the RSA modulus n." 🙄 |
| // |
| // This is extremely annoying, as all other encrypt and decrypt inputs are |
| // always the exact same size as the modulus. Since it only happens for |
| // weird modulus sizes, fix it by padding inefficiently. |
| if emLen, k := len(em), priv.pub.Size(); emLen < k { |
| emNew := make([]byte, k) |
| copy(emNew[k-emLen:], em) |
| em = emNew |
| } |
| |
| return decrypt(priv, em, withCheck) |
| } |
| |
| // VerifyPSS verifies sig with RSASSA-PSS automatically detecting the salt length. |
| func VerifyPSS(pub *PublicKey, hash hash.Hash, digest []byte, sig []byte) error { |
| return verifyPSS(pub, hash, digest, sig, pssSaltLengthAutodetect) |
| } |
| |
| // VerifyPSSWithSaltLength verifies sig with RSASSA-PSS and an expected salt length. |
| func VerifyPSSWithSaltLength(pub *PublicKey, hash hash.Hash, digest []byte, sig []byte, saltLength int) error { |
| if saltLength < 0 { |
| return errors.New("crypto/rsa: salt length cannot be negative") |
| } |
| return verifyPSS(pub, hash, digest, sig, saltLength) |
| } |
| |
| func verifyPSS(pub *PublicKey, hash hash.Hash, digest []byte, sig []byte, saltLength int) error { |
| fipsSelfTest() |
| fips140.RecordApproved() |
| checkApprovedHash(hash) |
| if fipsApproved, err := checkPublicKey(pub); err != nil { |
| return err |
| } else if !fipsApproved { |
| fips140.RecordNonApproved() |
| } |
| |
| if len(sig) != pub.Size() { |
| return ErrVerification |
| } |
| |
| emBits := pub.N.BitLen() - 1 |
| emLen := (emBits + 7) / 8 |
| em, err := encrypt(pub, sig) |
| if err != nil { |
| return ErrVerification |
| } |
| |
| // Like in signPSSWithSalt, deal with mismatches between emLen and the size |
| // of the modulus. The spec would have us wire emLen into the encoding |
| // function, but we'd rather always encode to the size of the modulus and |
| // then strip leading zeroes if necessary. This only happens for weird |
| // modulus sizes anyway. |
| for len(em) > emLen && len(em) > 0 { |
| if em[0] != 0 { |
| return ErrVerification |
| } |
| em = em[1:] |
| } |
| |
| return emsaPSSVerify(digest, em, emBits, saltLength, hash) |
| } |
| |
| func checkApprovedHash(hash hash.Hash) { |
| switch hash.(type) { |
| case *sha256.Digest, *sha512.Digest, *sha3.Digest: |
| default: |
| fips140.RecordNonApproved() |
| } |
| } |
| |
| // EncryptOAEP encrypts the given message with RSAES-OAEP. |
| func EncryptOAEP(hash, mgfHash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) { |
| // Note that while we don't commit to deterministic execution with respect |
| // to the random stream, we also never applied MaybeReadByte, so per Hyrum's |
| // Law it's probably relied upon by some. It's a tolerable promise because a |
| // well-specified number of random bytes is included in the ciphertext, in a |
| // well-specified way. |
| |
| fipsSelfTest() |
| fips140.RecordApproved() |
| checkApprovedHash(hash) |
| if fipsApproved, err := checkPublicKey(pub); err != nil { |
| return nil, err |
| } else if !fipsApproved { |
| fips140.RecordNonApproved() |
| } |
| k := pub.Size() |
| if len(msg) > k-2*hash.Size()-2 { |
| return nil, ErrMessageTooLong |
| } |
| |
| hash.Reset() |
| hash.Write(label) |
| lHash := hash.Sum(nil) |
| |
| em := make([]byte, k) |
| seed := em[1 : 1+hash.Size()] |
| db := em[1+hash.Size():] |
| |
| copy(db[0:hash.Size()], lHash) |
| db[len(db)-len(msg)-1] = 1 |
| copy(db[len(db)-len(msg):], msg) |
| |
| if err := drbg.ReadWithReader(random, seed); err != nil { |
| return nil, err |
| } |
| |
| mgf1XOR(db, mgfHash, seed) |
| mgf1XOR(seed, mgfHash, db) |
| |
| return encrypt(pub, em) |
| } |
| |
| // DecryptOAEP decrypts ciphertext using RSAES-OAEP. |
| func DecryptOAEP(hash, mgfHash hash.Hash, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) { |
| fipsSelfTest() |
| fips140.RecordApproved() |
| checkApprovedHash(hash) |
| |
| k := priv.pub.Size() |
| if len(ciphertext) > k || |
| k < hash.Size()*2+2 { |
| return nil, ErrDecryption |
| } |
| |
| em, err := decrypt(priv, ciphertext, noCheck) |
| if err != nil { |
| return nil, err |
| } |
| |
| hash.Reset() |
| hash.Write(label) |
| lHash := hash.Sum(nil) |
| |
| firstByteIsZero := constanttime.ByteEq(em[0], 0) |
| |
| seed := em[1 : hash.Size()+1] |
| db := em[hash.Size()+1:] |
| |
| mgf1XOR(seed, mgfHash, db) |
| mgf1XOR(db, mgfHash, seed) |
| |
| lHash2 := db[0:hash.Size()] |
| |
| // We have to validate the plaintext in constant time in order to avoid |
| // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal |
| // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 |
| // v2.0. In J. Kilian, editor, Advances in Cryptology. |
| lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2) |
| |
| // The remainder of the plaintext must be zero or more 0x00, followed |
| // by 0x01, followed by the message. |
| // lookingForIndex: 1 iff we are still looking for the 0x01 |
| // index: the offset of the first 0x01 byte |
| // invalid: 1 iff we saw a non-zero byte before the 0x01. |
| var lookingForIndex, index, invalid int |
| lookingForIndex = 1 |
| rest := db[hash.Size():] |
| |
| for i := 0; i < len(rest); i++ { |
| equals0 := constanttime.ByteEq(rest[i], 0) |
| equals1 := constanttime.ByteEq(rest[i], 1) |
| index = constanttime.Select(lookingForIndex&equals1, i, index) |
| lookingForIndex = constanttime.Select(equals1, 0, lookingForIndex) |
| invalid = constanttime.Select(lookingForIndex&^equals0, 1, invalid) |
| } |
| |
| if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 { |
| return nil, ErrDecryption |
| } |
| |
| return rest[index+1:], nil |
| } |