package cryptoimport ()func ( []byte) {for , := 0, len()-1; < ; , = +1, -1 { [], [] = [], [] }}const (rsaPadDataLimit = 144dataWithPaddingLength = 192dataWithHashLength = dataWithPaddingLength + sha256.SizetempKeySize = 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.iflen() > rsaPadDataLimit {returnnil, 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 {returnnil, 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 {returnnil, 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 {returnnil, errors.Wrap(, "create cipher") }varbin.Int256ige.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]byteif !rsaDecrypt(, , [:]) {returnnil, errors.New("invalid encrypted_data") } := [:tempKeySize] := [tempKeySize:] := make([]byte, tempKeySize) { := sha256.Sum256()xor.Bytes(, , [:]) } := make([]byte, len()) { , := aes.NewCipher()if != nil {returnnil, errors.Wrap(, "create cipher") }varbin.Int256ige.DecryptBlocks(, [:], , ) } := [:dataWithPaddingLength]reverseBytes() := [dataWithPaddingLength:] { := sha256.New() _, _ = .Write() _, _ = .Write()if !bytes.Equal(, .Sum(nil)) {returnnil, errors.New("hash mismatch") } }return , nil}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.