package crypto

import (
	
	
	
	
	
	

	

	

	

	
)

func ( []byte) {
	for ,  := 0, len()-1;  < ; ,  = +1, -1 {
		[], [] = [], []
	}
}

const (
	rsaPadDataLimit       = 144
	dataWithPaddingLength = 192
	dataWithHashLength    = dataWithPaddingLength + sha256.Size
	tempKeySize           = 32
)

// RSAPad encrypts given data with RSA, prefixing with a hash.
//
// See https://core.telegram.org/mtproto/auth_key#presenting-proof-of-work-server-authentication.
func ( []byte,  *rsa.PublicKey,  io.Reader) ([]byte, error) {
	// 1) data_with_padding := data + random_padding_bytes; — where random_padding_bytes are
	// chosen so that the resulting length of data_with_padding is precisely 192 bytes, and
	// data is the TL-serialized data to be encrypted as before.
	//
	// One has to check that data is not longer than 144 bytes.
	if len() > rsaPadDataLimit {
		return nil, errors.Errorf("data length is bigger that 144 (%d)", len())
	}

	 := make([]byte, dataWithPaddingLength)
	copy(, )
	// Filling data_with_padding with random bytes.
	if ,  := io.ReadFull(, [len():]);  != nil {
		return nil, errors.Wrap(, "pad data with random")
	}

	// Make a copy.
	 := make([]byte, dataWithPaddingLength)
	copy(, )
	// 2) data_pad_reversed := BYTE_REVERSE(data_with_padding);
	reverseBytes()

	for {
		// 3) A random 32-byte temp_key is generated.
		 := make([]byte, tempKeySize)
		if ,  := io.ReadFull(, );  != nil {
			return nil, errors.Wrap(, "generate temp_key")
		}

		// 4) data_with_hash := data_pad_reversed + SHA256(temp_key + data_with_padding);
		// — after this assignment, data_with_hash is exactly 224 bytes long.
		 := make([]byte, 0, dataWithHashLength)
		 = append(, ...)
		{
			 := sha256.New()
			_, _ = .Write()
			_, _ = .Write()
			 = .Sum()
			 = [:dataWithHashLength]
		}

		// 5) aes_encrypted := AES256_IGE(data_with_hash, temp_key, 0); — AES256-IGE encryption with zero IV.
		 := make([]byte, len())
		{
			,  := aes.NewCipher()
			if  != nil {
				return nil, errors.Wrap(, "create cipher")
			}
			var  bin.Int256
			ige.EncryptBlocks(, [:], , )
		}

		// 6) temp_key_xor := temp_key XOR SHA256(aes_encrypted); — adjusted key, 32 bytes
		 := make([]byte, tempKeySize)
		{
			 := sha256.Sum256()
			xor.Bytes(, , [:])
		}

		// 7) key_aes_encrypted := temp_key_xor + aes_encrypted; — exactly 256 bytes (2048 bits) long.
		 := make([]byte, 0, tempKeySize+dataWithHashLength)
		 = append(, ...)
		 = append(, ...)

		// 8) The value of key_aes_encrypted is compared with the RSA-modulus of server_pubkey
		// as a big-endian 2048-bit (256-byte) unsigned integer. If key_aes_encrypted turns out to be
		// greater than or equal to the RSA modulus, the previous steps starting from the generation
		// of new random temp_key are repeated.
		 := big.NewInt(0).SetBytes()
		if .Cmp(.N) >= 0 {
			continue
		}
		// Otherwise the final step is performed:

		// 9) encrypted_data := RSA(key_aes_encrypted, server_pubkey);
		// — 256-byte big-endian integer is elevated to the requisite power from the RSA public key
		// modulo the RSA modulus, and the result is stored as a big-endian integer consisting of
		// exactly 256 bytes (with leading zero bytes if required).
		//
		// Encrypting "key_aes_encrypted" with RSA.
		 := rsaEncrypt(, )
		return , nil
	}
}

// DecodeRSAPad implements server-side decoder of RSAPad.
func ( []byte,  *rsa.PrivateKey) ([]byte, error) {
	var  [256]byte
	if !rsaDecrypt(, , [:]) {
		return nil, errors.New("invalid encrypted_data")
	}

	 := [:tempKeySize]
	 := [tempKeySize:]

	 := make([]byte, tempKeySize)
	{
		 := sha256.Sum256()
		xor.Bytes(, , [:])
	}

	 := make([]byte, len())
	{
		,  := aes.NewCipher()
		if  != nil {
			return nil, errors.Wrap(, "create cipher")
		}
		var  bin.Int256
		ige.DecryptBlocks(, [:], , )
	}

	 := [:dataWithPaddingLength]
	reverseBytes()

	 := [dataWithPaddingLength:]
	{
		 := sha256.New()
		_, _ = .Write()
		_, _ = .Write()

		if !bytes.Equal(, .Sum(nil)) {
			return nil, errors.New("hash mismatch")
		}
	}

	return , nil
}