// Copyright 2009 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 signing and verification using PKCS #1 v1.5 signatures.

import (
	
	
	
)

// These are ASN1 DER structures:
//
//	DigestInfo ::= SEQUENCE {
//	  digestAlgorithm AlgorithmIdentifier,
//	  digest OCTET STRING
//	}
//
// For performance, we don't use the generic ASN1 encoder. Rather, we
// precompute a prefix of the digest value that makes a valid ASN1 DER string
// with the correct contents.
var hashPrefixes = map[string][]byte{
	"MD5":         {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
	"SHA-1":       {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
	"SHA-224":     {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},
	"SHA-256":     {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
	"SHA-384":     {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
	"SHA-512":     {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
	"SHA-512/224": {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x05, 0x00, 0x04, 0x1C},
	"SHA-512/256": {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20},
	"SHA3-224":    {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07, 0x05, 0x00, 0x04, 0x1C},
	"SHA3-256":    {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20},
	"SHA3-384":    {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, 0x30},
	"SHA3-512":    {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, 0x00, 0x04, 0x40},
	"MD5+SHA1":    {}, // A special TLS case which doesn't use an ASN1 prefix.
	"RIPEMD-160":  {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
}

// SignPKCS1v15 calculates an RSASSA-PKCS1-v1.5 signature.
//
// hash is the name of the hash function as returned by [crypto.Hash.String]
// or the empty string to indicate that the message is signed directly.
func ( *PrivateKey,  string,  []byte) ([]byte, error) {
	fipsSelfTest()
	fips140.RecordApproved()
	checkApprovedHashName()

	return signPKCS1v15(, , )
}

func signPKCS1v15( *PrivateKey,  string,  []byte) ([]byte, error) {
	,  := pkcs1v15ConstructEM(&.pub, , )
	if  != nil {
		return nil, 
	}

	return decrypt(, , withCheck)
}

func pkcs1v15ConstructEM( *PublicKey,  string,  []byte) ([]byte, error) {
	// Special case: "" is used to indicate that the data is signed directly.
	var  []byte
	if  != "" {
		var  bool
		,  = hashPrefixes[]
		if ! {
			return nil, errors.New("crypto/rsa: unsupported hash function")
		}
	}

	// EM = 0x00 || 0x01 || PS || 0x00 || T
	 := .Size()
	if  < len()+len()+2+8+1 {
		return nil, ErrMessageTooLong
	}
	 := make([]byte, )
	[1] = 1
	for  := 2;  < -len()-len()-1; ++ {
		[] = 0xff
	}
	copy([-len()-len():], )
	copy([-len():], )
	return , nil
}

// VerifyPKCS1v15 verifies an RSASSA-PKCS1-v1.5 signature.
//
// hash is the name of the hash function as returned by [crypto.Hash.String]
// or the empty string to indicate that the message is signed directly.
func ( *PublicKey,  string,  []byte,  []byte) error {
	fipsSelfTest()
	fips140.RecordApproved()
	checkApprovedHashName()

	return verifyPKCS1v15(, , , )
}

func verifyPKCS1v15( *PublicKey,  string,  []byte,  []byte) error {
	if ,  := checkPublicKey();  != nil {
		return 
	} else if ! {
		fips140.RecordNonApproved()
	}

	// RFC 8017 Section 8.2.2: If the length of the signature S is not k
	// octets (where k is the length in octets of the RSA modulus n), output
	// "invalid signature" and stop.
	if .Size() != len() {
		return ErrVerification
	}

	,  := encrypt(, )
	if  != nil {
		return ErrVerification
	}

	,  := pkcs1v15ConstructEM(, , )
	if  != nil {
		return ErrVerification
	}
	if !bytes.Equal(, ) {
		return ErrVerification
	}

	return nil
}

func checkApprovedHashName( string) {
	switch  {
	case "SHA-224", "SHA-256", "SHA-384", "SHA-512", "SHA-512/224", "SHA-512/256",
		"SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512":
	default:
		fips140.RecordNonApproved()
	}
}