Hilary Chipunza
Hilary Chipunza

Reputation: 11

AES-256 GCM Encryption For Flows Response

I am working on WhatsApp Flows API and decided to take up on the challenge in Go.

Part of the implementation requires me to encrypt a response using AES-256 Encryption and I have managed to have it working in Python. Problem is when I attempt to do the same in Go, I get a different result. Can someone help me replicate the following code, input and output in go please:

Inputs

encrypted_flow_data_b64 = 'H78/q8TCjizJhK8yt8tPEHG2QzArPsEFIoLajXWuPb5s6RA0QfHE7JMFFw3hTNh1byNSwjGVic8r2V9j76q4Et8UM9/bMCsF3UnXEzPNTZgQH4FHUIyjNQ=='

encrypted_aes_key_b64 = 'rjbs78LfWHLLqay/Fe4ofEisbMhCINmdUMlwXREuBGfRVRQzDmfEMoMFdCwLaX66nh/x7lJDyyjQZ+XA50gN1hEuDji0qbyGgpzZUUUfkxqYsgDW61Nf93cWvCPIRsgfuP5Brggoqr3slfRLbLPUOjkYOaof7lGJqHHbBeIb4RgEOAaIOXCA+84W5wrU/hmODoGNQ5FV7zjRdOpd8vX6JXcQ46LCLtmfPr0zx0NVetP8qvM7sn2X7FXlZtebut3k4XWkWQd3GEyWw5MEm4a4TJGtrXBAqcl7jsbTExgfVnVFD6saRKCoy2m6FqouMw9CzU5KyNItWhXkE4HtzKQilA=='

initial_vector_b64 = 'S84bbuqcCYjCtLECg9sq+A=='

Python Implementation And Input

import json
import os
import base64
from base64 import b64decode, b64encode
from cryptography.hazmat.primitives.asymmetric.padding import OAEP, MGF1, hashes
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.backends import default_backend

PRIVATE_KEY = b"""-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7vQZb2hKIDIow
jq7Vcwvq3/24kJpES26WUhcMXchqghgjAHP4X/2WMP37Qf+m4qahl91ZVyC8lQ1m
edSOJWoFj62I8ShI32EEQHFwhEIQKP/Q/6DY4xy7psetLcxZErcB5XJuxK6vni/j
EkJcGxmAYOHeatqY/Ij4TOPlrRJjMNgTsSxdgu5o+ulQAm7n/iBavbCwLkusog/8
6GG7V+2EQ143mKHTdAeohTcn/PR9W7l6kq7ChYIkXQbc/pG1Jq7dqsW1IQGBCxNT
SwOCOFq6nQgtV+x4gowIF3OJ7Ae6KNPKbVCec78LtiTM9pxPoWzvov3+3JsGAB3U
zBiZdHD1AgMBAAECggEAAJz/C2eZ4Lq6bIBZfFuDmgkQx7H7Owa3DgPRzPR1I49D
Zmve38cVKZDakjVL5pQ+IJrXJNlRbfmbrAPGXg+BD5MW/p1GY9SM+Sn/ujMdvHac
fVGJyY5BCVuOXUJgH5iyzdgIHhSuOxHMd2oCGvxrV9LD3MmNvMBdxIKLH7SHce5V
DhpqTGx0WNG9LVd3IUZP6TkdgMMinY1wgSzL2Eq7qlW0obMBYY9puAV2gshj6lGP
rwIBlkoR0O0LacG4YMWuQAcOVbqGtC7NkLJM14n70YErb3QPMfl0ChaiVSHJYUPP
TC5F9V9kkFltb1lJeYWDJuWPCIR9+vq6JsciYjyyGQKBgQD4wCdENUeg83t7uCtE
l7qVmxN3z15C/zWgUzRtqK/YInXKx4daQA3Aj3NwBRzCRH5KJouhcFgWDjAHIdzB
HsVBHPZXleBicm09JjIIKBZ+g+nUHZEpvClTgQNRNH7C2eMDpO0HPSTF2nORXWxb
GQkVDsfUG8bYJCdnB7L8BY2vHQKBgQDBNa3l9U6cJ16MSdf/E9h+2STR4yN8vn9m
qD89aMKkMtKyve3oVPdVOiKUhPMXkK8x3IUYU+IpBxiQXGe1F9rgAFBY2vWQ9LMQ
eMsChRcrP/tSaEWJZZNMzmtsDiJq+vOHA9WemvvxB9DvLoCZu1gPpDdsXKCTYiV8
swv2w9ZpuQKBgBvqnL2H6TkD+ljBK4HwMU128PFiQWbtc1xB2kFwTAPKokOWrvcO
9zwkHUV2HWsj+rRhrQv6KriW8Qbr4vV9eY+8K11bAaqqwt24+qZ1sUiTj1tx0gfI
CS9I7FFhvdQqVdLj4IIOd6EIyi2HOZDjt2Q4m26Pi3pYXF+wuoKUMPl1AoGAGznI
NnZZzHFTxmsFb+FJCZ7prFXYg1SIuVuOBcZEX0T2Ic/XvXxzmePmSY1uf+yYc2tC
qgnv/Z4NXRJYXtFsu1HwAIViQznoHbMX0FQWzrZmYNdmrRTOK+2Of5yCRxbzyBvH
N2FZjT5vt7SS1Jbsss+OK8vlqL8Uzzyfu/ceuKkCgYEAmWBTmlikPfI/64k/dKi/
Kf86RRzV1oXpKSIA2bh+nuk3X7vdP04s8Eop3UGBMD3qq6C0TAMPM7UdbvM1LfG6
iAY48rnKhmeDr1MJkjvHybjOawftMjW1A2/UTdBSDevYd1bnIMYAFJl4dcmRadSE
PLqGDB6VSIOEA+T8Ie3IeH8=
-----END PRIVATE KEY-----
"""

def decrypt_request(encrypted_flow_data_b64, encrypted_aes_key_b64, initial_vector_b64):
    flow_data = b64decode(encrypted_flow_data_b64)
    iv = b64decode(initial_vector_b64)

    # Decrypt the AES encryption key
    encrypted_aes_key = b64decode(encrypted_aes_key_b64)
    private_key = load_pem_private_key(PRIVATE_KEY, None, default_backend())
    aes_key = private_key.decrypt(encrypted_aes_key, OAEP(
        mgf=MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None))

    # Decrypt the Flow data
    encrypted_flow_data_body = flow_data[:-16]
    encrypted_flow_data_tag = flow_data[-16:]
    decryptor = Cipher(algorithms.AES(aes_key),
                       modes.GCM(iv, encrypted_flow_data_tag)).decryptor()
    decrypted_data_bytes = decryptor.update(
        encrypted_flow_data_body) + decryptor.finalize()
    decrypted_data = json.loads(decrypted_data_bytes.decode("utf-8"))
    return decrypted_data, aes_key, iv

def encrypt_response(response, aes_key, iv):
    # Flip the initialization vector
    flipped_iv = bytearray()
    for byte in iv:
        flipped_iv.append(byte ^ 0xFF)

    # Encrypt the response data
    encryptor = Cipher(algorithms.AES(aes_key),
                       modes.GCM(flipped_iv)).encryptor()

    data = encryptor.update(json.dumps(response).encode("utf-8")) + encryptor.finalize() + encryptor.tag                 
    return b64encode(
        data
    ).decode("utf-8")

encrypted_flow_data_b64 = 'H78/q8TCjizJhK8yt8tPEHG2QzArPsEFIoLajXWuPb5s6RA0QfHE7JMFFw3hTNh1byNSwjGVic8r2V9j76q4Et8UM9/bMCsF3UnXEzPNTZgQH4FHUIyjNQ=='
encrypted_aes_key_b64 = 'rjbs78LfWHLLqay/Fe4ofEisbMhCINmdUMlwXREuBGfRVRQzDmfEMoMFdCwLaX66nh/x7lJDyyjQZ+XA50gN1hEuDji0qbyGgpzZUUUfkxqYsgDW61Nf93cWvCPIRsgfuP5Brggoqr3slfRLbLPUOjkYOaof7lGJqHHbBeIb4RgEOAaIOXCA+84W5wrU/hmODoGNQ5FV7zjRdOpd8vX6JXcQ46LCLtmfPr0zx0NVetP8qvM7sn2X7FXlZtebut3k4XWkWQd3GEyWw5MEm4a4TJGtrXBAqcl7jsbTExgfVnVFD6saRKCoy2m6FqouMw9CzU5KyNItWhXkE4HtzKQilA=='
initial_vector_b64 = 'S84bbuqcCYjCtLECg9sq+A=='
    
decrypted_data, aes_key, iv = decrypt_request(encrypted_flow_data_b64, encrypted_aes_key_b64, initial_vector_b64)

json_string = '{"version":"3.0","screen":"SENDER_DETAIL","data":{"areas":[{"id":"0","title":"Testing"},{"id":"1","title":"Testo"}],"cities":[{"id":"0","title":"Sweeto"},{"id":"1","title":"LEts Go"}]}}'
response_object = json.loads(json_string)

print(response_object)
print(aes_key)
print(iv)
print(encrypt_response(response_object, aes_key, iv))

#Expected Results: 
# response_object = {'version': '3.0', 'screen': 'SENDER_DETAIL', 'data': {'areas': [{'id': '0', 'title': 'Testing'}, {'id': '1', 'title': 'Testo'}], 'cities': [{'id': '0', 'title': 'Sweeto'}, {'id': '1', 'title': 'LEts Go'}]}}
# encrypt_response(response_object, aes_key, iv) = '+8JsaVL25x4CIadr+eprJzOmYr3BZMEoykdUkFn3RXz5OUQQkYRa2BbzM3gqV9skRYU+klYX+6VeLS9oDLNAP8CI7HJYwkqxnDRodwxL1LHKfzn4P+9yjdepVSkXg5020OQMnZru8VpDxIjlUECiaDCkTgFjXYvhyfxU/nqwhX8PvILfAvSq8ZRd+CV6qLItGQcPBQ7PVBQqtamdWDtSOxWDOe8bK/eYtUWTfVnE29RsVOMrby58br/kLhCMNbGwJYXdDxTpZoeAqg2YKCTPe/eVv9qmXRGEeSXXoiGllw=='

Go Implementation

func aesEncryption(aesKey []byte, iv []byte, plainText []byte) string {

flippedIV := make([]byte, len(iv))
for i, b := range iv {
    flippedIV[i] = b ^ 0xFF
}

block, _ := aes.NewCipher(aesKey)
mode := cipher.NewCBCEncrypter(block, flippedIV)

padder := padding.NewPkcs7Padding(block.BlockSize())
paddedPlainText, _ := padder.Pad(plainText)

ciphertext := make([]byte, len(paddedPlainText))
mode.CryptBlocks(ciphertext, paddedPlainText)

encodedText := base64.StdEncoding.EncodeToString(ciphertext)
return encodedText

expected encryption response

'+8JsaVL25x4CIadr+eprJzOmYr3BZMEoykdUkFn3RXz5OUQQkYRa2BbzM3gqV9skRYU+klYX+6VeLS9oDLNAP8CI7HJYwkqxnDRodwxL1LHKfzn4P+9yjdepVSkXg5020OQMnZru8VpDxIjlUECiaDCkTgFjXYvhyfxU/nqwhX8PvILfAvSq8ZRd+CV6qLItGQcPBQ7PVBQqtamdWDtSOxWDOe8bK/eYtUWTfVnE29RsVOMrby58br/kLhCMNbGwJYXdDxTpZoeAqg2YKCTPe/eVv9qmXRGEeSXXoiGllw=='

The output I get from Go with this input is:

8AhYU9io9kn9SUVWIS00NW/i8/rBYZjXnLjxfad6hZvUXGhilig7/HsM5y6f5swcCJule+eCXROIs55W+IwLkvVTB3kxjL9FC/wJrSw76FJjY21I1AymaWFJC7rjt+2aPHWFtoYAQIwhvWu9oqqzJsTQce2GqRAT/1mK7N/Pa5HwKt3M4H/mrQzOtMa7BbGcI1Sf20eFmWcavz0VoLs+mVfDGk6FonLKs+WwsBNJ2lwIxDhmYleHwioviZGoOml2

Upvotes: 1

Views: 263

Answers (0)

Related Questions