// 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 (
	
	
	
	
	
	
	
	
	
)

// 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( *[4]byte) {
	if [3]++; [3] != 0 {
		return
	}
	if [2]++; [2] != 0 {
		return
	}
	if [1]++; [1] != 0 {
		return
	}
	[0]++
}

// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
// specified in PKCS #1 v2.1.
func mgf1XOR( []byte,  fips140.Hash,  []byte) {
	var  [4]byte
	var  []byte

	 := 0
	for  < len() {
		.Reset()
		.Write()
		.Write([0:4])
		 = .Sum([:0])

		for  := 0;  < len() &&  < len(); ++ {
			[] ^= []
			++
		}
		incCounter(&)
	}
}

func emsaPSSEncode( []byte,  int,  []byte,  fips140.Hash) ([]byte, error) {
	// See RFC 8017, Section 9.1.1.

	 := .Size()
	 := len()
	 := ( + 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() !=  {
		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  < ++2 {
		return nil, ErrMessageTooLong
	}

	 := make([]byte, )
	 :=  -  -  - 2
	 := [:+1+]
	 := [+1+ : -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  [8]byte

	.Reset()
	.Write([:])
	.Write()
	.Write()

	 = .Sum([: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.

	[] = 0x01
	copy([+1:], )

	// 9.  Let dbMask = MGF(H, emLen - hLen - 1).
	//
	// 10. Let maskedDB = DB \xor dbMask.

	mgf1XOR(, , )

	// 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in
	//     maskedDB to zero.

	[0] &= 0xff >> (8* - )

	// 12. Let EM = maskedDB || H || 0xbc.
	[-1] = 0xbc

	// 13. Output EM.
	return , nil
}

const pssSaltLengthAutodetect = -1

func emsaPSSVerify(,  []byte, ,  int,  fips140.Hash) error {
	// See RFC 8017, Section 9.1.2.

	 := .Size()
	 := ( + 7) / 8
	if  != len() {
		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  != len() {
		return ErrVerification
	}

	// 3.  If emLen < hLen + sLen + 2, output "inconsistent" and stop.
	if  < ++2 {
		return ErrVerification
	}

	// 4.  If the rightmost octet of EM does not have hexadecimal value
	//     0xbc, output "inconsistent" and stop.
	if [-1] != 0xbc {
		return ErrVerification
	}

	// 5.  Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
	//     let H be the next hLen octets.
	 := [:--1]
	 := [--1 : -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  byte = 0xff >> (8* - )
	if [0] & ^ != 0 {
		return ErrVerification
	}

	// 7.  Let dbMask = MGF(H, emLen - hLen - 1).
	//
	// 8.  Let DB = maskedDB \xor dbMask.
	mgf1XOR(, , )

	// 9.  Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
	//     to zero.
	[0] &= 

	// If we don't know the salt length, look for the 0x01 delimiter.
	if  == pssSaltLengthAutodetect {
		 := bytes.IndexByte(, 0x01)
		if  < 0 {
			return ErrVerification
		}
		 = len() -  - 1
	}

	// FIPS 186-5, Section 5.4(g): "the length (in bytes) of the salt (sLen)
	// shall satisfy 0 ≤ sLen ≤ hLen".
	if  >  {
		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.
	 :=  -  -  - 2
	for ,  := range [:] {
		if  != 0x00 {
			return ErrVerification
		}
	}
	if [] != 0x01 {
		return ErrVerification
	}

	// 11.  Let salt be the last sLen octets of DB.
	 := [len()-:]

	// 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.
	.Reset()
	var  [8]byte
	.Write([:])
	.Write()
	.Write()

	 := .Sum(nil)

	// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
	if !bytes.Equal(, ) { // TODO: constant time?
		return ErrVerification
	}
	return nil
}

// PSSMaxSaltLength returns the maximum salt length for a given public key and
// hash function.
func ( *PublicKey,  fips140.Hash) (int, error) {
	 := (.N.BitLen()-1+7)/8 - 2 - .Size()
	if  < 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 &&  > .Size() {
		return .Size(), nil
	}
	return , nil
}

// SignPSS calculates the signature of hashed using RSASSA-PSS.
func ( io.Reader,  *PrivateKey,  fips140.Hash,  []byte,  int) ([]byte, error) {
	fipsSelfTest()
	fips140.RecordApproved()
	checkApprovedHash()

	// Note that while we don't commit to deterministic execution with respect
	// to the rand stream, we also don't apply 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  < 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  > .Size() {
		fips140.RecordNonApproved()
	}
	 := make([]byte, )
	if  := drbg.ReadWithReaderDeterministic(, );  != nil {
		return nil, 
	}

	 := .pub.N.BitLen() - 1
	,  := emsaPSSEncode(, , , )
	if  != nil {
		return nil, 
	}

	// 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 ,  := len(), .pub.Size();  <  {
		 := make([]byte, )
		copy([-:], )
		 = 
	}

	return decrypt(, , withCheck)
}

// VerifyPSS verifies sig with RSASSA-PSS automatically detecting the salt length.
func ( *PublicKey,  fips140.Hash,  []byte,  []byte) error {
	return verifyPSS(, , , , pssSaltLengthAutodetect)
}

// VerifyPSS verifies sig with RSASSA-PSS and an expected salt length.
func ( *PublicKey,  fips140.Hash,  []byte,  []byte,  int) error {
	if  < 0 {
		return errors.New("crypto/rsa: salt length cannot be negative")
	}
	return verifyPSS(, , , , )
}

func verifyPSS( *PublicKey,  fips140.Hash,  []byte,  []byte,  int) error {
	fipsSelfTest()
	fips140.RecordApproved()
	checkApprovedHash()
	if ,  := checkPublicKey();  != nil {
		return 
	} else if ! {
		fips140.RecordNonApproved()
	}

	if len() != .Size() {
		return ErrVerification
	}

	 := .N.BitLen() - 1
	 := ( + 7) / 8
	,  := encrypt(, )
	if  != 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() >  && len() > 0 {
		if [0] != 0 {
			return ErrVerification
		}
		 = [1:]
	}

	return emsaPSSVerify(, , , , )
}

func checkApprovedHash( fips140.Hash) {
	switch .(type) {
	case *sha256.Digest, *sha512.Digest, *sha3.Digest:
	default:
		fips140.RecordNonApproved()
	}
}

// EncryptOAEP encrypts the given message with RSAES-OAEP.
func (,  fips140.Hash,  io.Reader,  *PublicKey,  []byte,  []byte) ([]byte, error) {
	// Note that while we don't commit to deterministic execution with respect
	// to the random stream, we also don't apply 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()
	if ,  := checkPublicKey();  != nil {
		return nil, 
	} else if ! {
		fips140.RecordNonApproved()
	}
	 := .Size()
	if len() > -2*.Size()-2 {
		return nil, ErrMessageTooLong
	}

	.Reset()
	.Write()
	 := .Sum(nil)

	 := make([]byte, )
	 := [1 : 1+.Size()]
	 := [1+.Size():]

	copy([0:.Size()], )
	[len()-len()-1] = 1
	copy([len()-len():], )

	if  := drbg.ReadWithReaderDeterministic(, );  != nil {
		return nil, 
	}

	mgf1XOR(, , )
	mgf1XOR(, , )

	return encrypt(, )
}

// DecryptOAEP decrypts ciphertext using RSAES-OAEP.
func (,  fips140.Hash,  *PrivateKey,  []byte,  []byte) ([]byte, error) {
	fipsSelfTest()
	fips140.RecordApproved()
	checkApprovedHash()

	 := .pub.Size()
	if len() >  ||
		 < .Size()*2+2 {
		return nil, ErrDecryption
	}

	,  := decrypt(, , noCheck)
	if  != nil {
		return nil, 
	}

	.Reset()
	.Write()
	 := .Sum(nil)

	 := subtle.ConstantTimeByteEq([0], 0)

	 := [1 : .Size()+1]
	 := [.Size()+1:]

	mgf1XOR(, , )
	mgf1XOR(, , )

	 := [0:.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.
	 := subtle.ConstantTimeCompare(, )

	// 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 , ,  int
	 = 1
	 := [.Size():]

	for  := 0;  < len(); ++ {
		 := subtle.ConstantTimeByteEq([], 0)
		 := subtle.ConstantTimeByteEq([], 1)
		 = subtle.ConstantTimeSelect(&, , )
		 = subtle.ConstantTimeSelect(, 0, )
		 = subtle.ConstantTimeSelect(&^, 1, )
	}

	if &&^&^ != 1 {
		return nil, ErrDecryption
	}

	return [+1:], nil
}