WhatsApp Flows Decryption Error-error:02000079:rsa routines::oaep decoding error

38 views Asked by At

I have utilized the WhatsApp Flows API to integrate flows into our application. When publishing the flow, I need to decrypt it using the following structure:

{
    encrypted_flow_data: "<ENCRYPTED FLOW DATA>",
    encrypted_aes_key: "<ENCRYPTED_AES_KEY>",
    initial_vector: "<INITIAL VECTOR>"
 }

referred to this documentation (https://developers.facebook.com/docs/whatsapp/flows/guides/implementingyourflowendpoint#nodejs-express-example) for decrypting the key.

However, I am encountering the following error:

{
"code": "ERR_OSSL_RSA_OAEP_DECODING_ERROR",
"library": "rsa routines",
"reason": "oaep decoding error",
"message": "error:02000079:rsa routines::oaep decoding error",
"stack": "Error: error:02000079:rsa routines::oaep decoding error\n    at Object.privateDecrypt (node:internal/crypto/cipher:79:12)\n    at decryptRequest"

}

For reference, here is the relevant code snippet:

const express = require("express");
const crypto = require("crypto");
const fs = require('fs');
const util = require('util');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);

require("dotenv").config();

const PORT = 3000;
const app = express();
app.use(express.json());

app.post("/data", async ({ body }, res) => {
    const PRIVATE_KEY_PATH = 'path/to/your/private_key.pem'; 
    const PRIVATE_KEY_PASSPHRASE = 'your_private_key_passphrase';

    const PRIVATE_KEY = await readFile(PRIVATE_KEY_PATH, 'utf-8');

    const { decryptedBody, aesKeyBuffer, initialVectorBuffer } = decryptRequest(
        body,
        PRIVATE_KEY,
        PRIVATE_KEY_PASSPHRASE,
    );

    const { screen, data, version, action } = decryptedBody;
    // Return the next screen & data to the client
    const screenData = {
        version,
        screen: "SCREEN_NAME",
        data: {
            some_key: "some_value",
        },
    };

    // Return the response as plaintext
    res.send(encryptResponse(screenData, aesKeyBuffer, initialVectorBuffer));
});

const decryptRequest = async (body, privatePem, passphrase) => {
    try {
        const { encrypted_aes_key, encrypted_flow_data, initial_vector } = body;

        // Decrypt the AES key created by the client
        const decryptedAesKey = crypto.privateDecrypt(
            {
                key: crypto.createPrivateKey(
                    {
                        key: privatePem,
                        passphrase: passphrase,
                    }
                ),
                padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
                oaepHash: "sha256",
            },
            Buffer.from(encrypted_aes_key, "base64"),
        );

        // Decrypt the Flow data
        const flowDataBuffer = Buffer.from(encrypted_flow_data, "base64");
        const initialVectorBuffer = Buffer.from(initial_vector, "base64");

        const TAG_LENGTH = 16;
        const encrypted_flow_data_body = flowDataBuffer.subarray(0, -TAG_LENGTH);
        const encrypted_flow_data_tag = flowDataBuffer.subarray(-TAG_LENGTH);

        const decipher = crypto.createDecipheriv(
            "aes-128-gcm",
            decryptedAesKey,
            initialVectorBuffer,
        );
        decipher.setAuthTag(encrypted_flow_data_tag);

        const decryptedJSONString = Buffer.concat([
            decipher.update(encrypted_flow_data_body),
            decipher.final(),
        ]).toString("utf-8");

        return {
            decryptedBody: JSON.parse(decryptedJSONString),
            aesKeyBuffer: decryptedAesKey,
            initialVectorBuffer,
        };
    } catch (e) {
        console.log('Error decoding:', e)
    }
};

const encryptResponse = (
    response,
    aesKeyBuffer,
    initialVectorBuffer,
) => {
    // Flip the initialization vector
    const flipped_iv = [];
    for (const pair of initialVectorBuffer.entries()) {
        flipped_iv.push(~pair[1]);
    }
    // Encrypt the response data
    const cipher = crypto.createCipheriv(
        "aes-128-gcm",
        aesKeyBuffer,
        Buffer.from(flipped_iv),
    );
    return Buffer.concat([
        cipher.update(JSON.stringify(response), "utf-8"),
        cipher.final(),
        cipher.getAuthTag(),
    ]).toString("base64");
};

app.listen(PORT, () => {
    console.log(`App is listening on port ${PORT}!`);
});

I don't know whether i'm making wrong in generating the private key Could you assist me in resolving this issue? I appreciate your help in advance. Thank you.

0

There are 0 answers