blob: 4a043213fd03d7496fd71ef04e51938a57759a84 [file] [edit]
// 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
}