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}!`);
});
Could you assist me in resolving this issue? I appreciate your help in advance. Thank you.
The decryption code seems fine to me. The issue might be with the private key.