// Copyright 2024 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

import (
	
	
	
	
	
	
	
)

const (
	// PSSSaltLengthAuto causes the salt in a PSS signature to be as large
	// as possible when signing, and to be auto-detected when verifying.
	//
	// When signing in FIPS 140-3 mode, the salt length is capped at the length
	// of the hash function used in the signature.
	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 positive number of bytes, or one of the special
	// PSSSaltLength constants.
	SaltLength int

	// Hash is the hash function used to generate the message digest. If not
	// zero, it overrides the hash function passed to SignPSS. It's required
	// when using PrivateKey.Sign.
	Hash crypto.Hash
}

// HashFunc returns opts.Hash so that [PSSOptions] implements [crypto.SignerOpts].
func ( *PSSOptions) () crypto.Hash {
	return .Hash
}

func ( *PSSOptions) () int {
	if  == nil {
		return PSSSaltLengthAuto
	}
	return .SaltLength
}

// SignPSS calculates the signature of digest using PSS.
//
// digest 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. If opts.Hash is set, it overrides hash.
//
// The signature is randomized depending on the message, key, and salt size,
// using bytes from rand. Most applications should use [crypto/rand.Reader] as
// rand.
func ( io.Reader,  *PrivateKey,  crypto.Hash,  []byte,  *PSSOptions) ([]byte, error) {
	if  := checkPublicKeySize(&.PublicKey);  != nil {
		return nil, 
	}
	if  := checkFIPS140OnlyPrivateKey();  != nil {
		return nil, 
	}
	if fips140only.Enabled && !fips140only.ApprovedHash(.New()) {
		return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
	}
	if fips140only.Enabled && !fips140only.ApprovedRandomReader() {
		return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
	}

	if  != nil && .Hash != 0 {
		 = .Hash
	}

	if boring.Enabled &&  == boring.RandReader {
		,  := boringPrivateKey()
		if  != nil {
			return nil, 
		}
		return boring.SignRSAPSS(, , , .saltLength())
	}
	boring.UnreachableExceptTests()

	,  := fipsPrivateKey()
	if  != nil {
		return nil, 
	}
	 := .New()

	 := .saltLength()
	if fips140only.Enabled &&  > .Size() {
		return nil, errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
	}
	switch  {
	case PSSSaltLengthAuto:
		,  = rsa.PSSMaxSaltLength(.PublicKey(), )
		if  != nil {
			return nil, fipsError()
		}
	case PSSSaltLengthEqualsHash:
		 = .Size()
	default:
		// If we get here saltLength is either > 0 or < -1, in the
		// latter case we fail out.
		if  <= 0 {
			return nil, errors.New("crypto/rsa: invalid PSS salt length")
		}
	}

	return fipsError2(rsa.SignPSS(, , , , ))
}

// VerifyPSS verifies a PSS signature.
//
// A valid signature is indicated by returning a nil error. digest 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. opts.Hash is
// ignored.
//
// The inputs are not considered confidential, and may leak through timing side
// channels, or if an attacker has control of part of the inputs.
func ( *PublicKey,  crypto.Hash,  []byte,  []byte,  *PSSOptions) error {
	if  := checkPublicKeySize();  != nil {
		return 
	}
	if  := checkFIPS140OnlyPublicKey();  != nil {
		return 
	}
	if fips140only.Enabled && !fips140only.ApprovedHash(.New()) {
		return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
	}

	if boring.Enabled {
		,  := boringPublicKey()
		if  != nil {
			return 
		}
		if  := boring.VerifyRSAPSS(, , , , .saltLength());  != nil {
			return ErrVerification
		}
		return nil
	}

	,  := fipsPublicKey()
	if  != nil {
		return 
	}

	 := .saltLength()
	if fips140only.Enabled &&  > .Size() {
		return errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode")
	}
	switch  {
	case PSSSaltLengthAuto:
		return fipsError(rsa.VerifyPSS(, .New(), , ))
	case PSSSaltLengthEqualsHash:
		return fipsError(rsa.VerifyPSSWithSaltLength(, .New(), , , .Size()))
	default:
		return fipsError(rsa.VerifyPSSWithSaltLength(, .New(), , , ))
	}
}

// EncryptOAEP encrypts the given message with RSA-OAEP.
//
// OAEP is parameterised by a hash function that is used as a random oracle.
// Encryption and decryption of a given message must use the same hash function
// and sha256.New() is a reasonable choice.
//
// The random parameter is used as a source of entropy to ensure that
// encrypting the same message twice doesn't result in the same ciphertext.
// Most applications should use [crypto/rand.Reader] as random.
//
// The label parameter may contain arbitrary data that will not be encrypted,
// but which gives important context to the message. For example, if a given
// public key is used to encrypt two types of messages then distinct label
// values could be used to ensure that a ciphertext for one purpose cannot be
// used for another by an attacker. If not required it can be empty.
//
// The message must be no longer than the length of the public modulus minus
// twice the hash length, minus a further 2.
func ( hash.Hash,  io.Reader,  *PublicKey,  []byte,  []byte) ([]byte, error) {
	if  := checkPublicKeySize();  != nil {
		return nil, 
	}
	if  := checkFIPS140OnlyPublicKey();  != nil {
		return nil, 
	}
	if fips140only.Enabled && !fips140only.ApprovedHash() {
		return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
	}
	if fips140only.Enabled && !fips140only.ApprovedRandomReader() {
		return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
	}

	defer .Reset()

	if boring.Enabled &&  == boring.RandReader {
		.Reset()
		 := .Size()
		if len() > -2*.Size()-2 {
			return nil, ErrMessageTooLong
		}
		,  := boringPublicKey()
		if  != nil {
			return nil, 
		}
		return boring.EncryptRSAOAEP(, , , , )
	}
	boring.UnreachableExceptTests()

	,  := fipsPublicKey()
	if  != nil {
		return nil, 
	}
	return fipsError2(rsa.EncryptOAEP(, , , , , ))
}

// DecryptOAEP decrypts ciphertext using RSA-OAEP.
//
// OAEP is parameterised by a hash function that is used as a random oracle.
// Encryption and decryption of a given message must use the same hash function
// and sha256.New() is a reasonable choice.
//
// The random parameter is legacy and ignored, and it can be nil.
//
// The label parameter must match the value given when encrypting. See
// [EncryptOAEP] for details.
func ( hash.Hash,  io.Reader,  *PrivateKey,  []byte,  []byte) ([]byte, error) {
	defer .Reset()
	return decryptOAEP(, , , , )
}

func decryptOAEP(,  hash.Hash,  *PrivateKey,  []byte,  []byte) ([]byte, error) {
	if  := checkPublicKeySize(&.PublicKey);  != nil {
		return nil, 
	}
	if  := checkFIPS140OnlyPrivateKey();  != nil {
		return nil, 
	}
	if fips140only.Enabled {
		if !fips140only.ApprovedHash() || !fips140only.ApprovedHash() {
			return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
		}
	}

	if boring.Enabled {
		 := .Size()
		if len() >  ||
			 < .Size()*2+2 {
			return nil, ErrDecryption
		}
		,  := boringPrivateKey()
		if  != nil {
			return nil, 
		}
		,  := boring.DecryptRSAOAEP(, , , , )
		if  != nil {
			return nil, ErrDecryption
		}
		return , nil
	}

	,  := fipsPrivateKey()
	if  != nil {
		return nil, 
	}

	return fipsError2(rsa.DecryptOAEP(, , , , ))
}

// SignPKCS1v15 calculates the signature of hashed using
// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS #1 v1.5.  Note that hashed must
// be the result of hashing the input message using the given hash
// function. If hash is zero, hashed is signed directly. This isn't
// advisable except for interoperability.
//
// The random parameter is legacy and ignored, and it can be nil.
//
// This function is deterministic. Thus, if the set of possible
// messages is small, an attacker may be able to build a map from
// messages to signatures and identify the signed messages. As ever,
// signatures provide authenticity, not confidentiality.
func ( io.Reader,  *PrivateKey,  crypto.Hash,  []byte) ([]byte, error) {
	var  string
	if  != crypto.Hash(0) {
		if len() != .Size() {
			return nil, errors.New("crypto/rsa: input must be hashed message")
		}
		 = .String()
	}

	if  := checkPublicKeySize(&.PublicKey);  != nil {
		return nil, 
	}
	if  := checkFIPS140OnlyPrivateKey();  != nil {
		return nil, 
	}
	if fips140only.Enabled && !fips140only.ApprovedHash(.New()) {
		return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
	}

	if boring.Enabled {
		,  := boringPrivateKey()
		if  != nil {
			return nil, 
		}
		return boring.SignRSAPKCS1v15(, , )
	}

	,  := fipsPrivateKey()
	if  != nil {
		return nil, 
	}
	return fipsError2(rsa.SignPKCS1v15(, , ))
}

// VerifyPKCS1v15 verifies an RSA PKCS #1 v1.5 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. If hash is zero then hashed is used directly. This
// isn't advisable except for interoperability.
//
// The inputs are not considered confidential, and may leak through timing side
// channels, or if an attacker has control of part of the inputs.
func ( *PublicKey,  crypto.Hash,  []byte,  []byte) error {
	if  := checkPublicKeySize();  != nil {
		return 
	}
	if  := checkFIPS140OnlyPublicKey();  != nil {
		return 
	}
	if fips140only.Enabled && !fips140only.ApprovedHash(.New()) {
		return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
	}

	if boring.Enabled {
		,  := boringPublicKey()
		if  != nil {
			return 
		}
		if  := boring.VerifyRSAPKCS1v15(, , , );  != nil {
			return ErrVerification
		}
		return nil
	}

	,  := fipsPublicKey()
	if  != nil {
		return 
	}
	var  string
	if  != crypto.Hash(0) {
		if len() != .Size() {
			return errors.New("crypto/rsa: input must be hashed message")
		}
		 = .String()
	}
	return fipsError(rsa.VerifyPKCS1v15(, , , ))
}

func fipsError( error) error {
	switch  {
	case rsa.ErrDecryption:
		return ErrDecryption
	case rsa.ErrVerification:
		return ErrVerification
	case rsa.ErrMessageTooLong:
		return ErrMessageTooLong
	}
	return 
}

func fipsError2[ any]( ,  error) (, error) {
	return , fipsError()
}

func checkFIPS140OnlyPublicKey( *PublicKey) error {
	if !fips140only.Enabled {
		return nil
	}
	if .N == nil {
		return errors.New("crypto/rsa: public key missing N")
	}
	if .N.BitLen() < 2048 {
		return errors.New("crypto/rsa: use of keys smaller than 2048 bits is not allowed in FIPS 140-only mode")
	}
	if .N.BitLen()%2 == 1 {
		return errors.New("crypto/rsa: use of keys with odd size is not allowed in FIPS 140-only mode")
	}
	if .E <= 1<<16 {
		return errors.New("crypto/rsa: use of public exponent <= 2¹⁶ is not allowed in FIPS 140-only mode")
	}
	if .E&1 == 0 {
		return errors.New("crypto/rsa: use of even public exponent is not allowed in FIPS 140-only mode")
	}
	return nil
}

func checkFIPS140OnlyPrivateKey( *PrivateKey) error {
	if !fips140only.Enabled {
		return nil
	}
	if  := checkFIPS140OnlyPublicKey(&.PublicKey);  != nil {
		return 
	}
	if len(.Primes) != 2 {
		return errors.New("crypto/rsa: use of multi-prime keys is not allowed in FIPS 140-only mode")
	}
	if .Primes[0] == nil || .Primes[1] == nil || .Primes[0].BitLen() != .Primes[1].BitLen() {
		return errors.New("crypto/rsa: use of primes of different sizes is not allowed in FIPS 140-only mode")
	}
	return nil
}