Skip to content

Instantly share code, notes, and snippets.

@HereOrCode
Forked from Gimenz/wa-decrypt.js
Created February 19, 2025 10:49
Show Gist options
  • Save HereOrCode/f5db7fd871699c67357c58ef893dcba6 to your computer and use it in GitHub Desktop.
Save HereOrCode/f5db7fd871699c67357c58ef893dcba6 to your computer and use it in GitHub Desktop.
a function to decrypt WA Media
/**
* this code is copied from https://github.com/open-wa/wa-decrypt-nodejs
* i just made it more simplified
*/
const { default: axios } = require('axios');
const crypto = require('crypto');
const hkdf = require('futoin-hkdf');
const atob = require('atob');
const fixPadding = (data, expectedSize) => {
const padding = (16 - (expectedSize % 16)) & 0xf;
if (padding > 0) {
if ((expectedSize + padding) == data.length) {
// console.log(`trimmed: ${padding} bytes`);
data = data.slice(0, data.length - padding);
} else if ((data.length + padding) == expectedSize) {
// console.log(`adding: ${padding} bytes`);
const arr = new Uint16Array(padding).map(() => padding);
data = Buffer.concat([data, Buffer.from(arr)]);
}
}
// @ts-ignore
return Buffer.from(data, 'utf-8');
};
const hexToBytes = (hexStr) => {
const intArray = [];
for (let i = 0; i < hexStr.length; i += 2) {
intArray.push(parseInt(hexStr.substr(i, 2), 16));
}
return new Uint8Array(intArray);
};
const base64ToBytes = (base64Str) => {
const binaryStr = atob(base64Str);
const byteArray = new Uint8Array(binaryStr.length);
for (let i = 0; i < binaryStr.length; i++) {
byteArray[i] = binaryStr.charCodeAt(i);
}
return byteArray;
};
const mediaTypes = {
IMAGE: 'Image',
VIDEO: 'Video',
AUDIO: 'Audio',
PTT: 'Audio',
DOCUMENT: 'Document',
STICKER: 'Image',
};
const magix = (fileData, mediaKeyBase64, mediaType, expectedSize = '', mimetype = '') => {
const encodedHex = fileData.toString('hex');
const encodedBytes = hexToBytes(encodedHex);
const mediaKeyBytes = base64ToBytes(mediaKeyBase64);
const info = `WhatsApp ${mediaTypes[mediaType.toUpperCase()] || mediaTypes[Object.keys(mediaTypes).filter((type) => mimetype.includes(type.toLowerCase()))[0]]} Keys`;
const hash = 'sha256';
const salt = new Uint8Array(32);
const expandedSize = 112;
const mediaKeyExpanded = hkdf(mediaKeyBytes, expandedSize, {
salt,
info,
hash,
});
const iv = mediaKeyExpanded.slice(0, 16);
const cipherKey = mediaKeyExpanded.slice(16, 48);
const decipher = crypto.createDecipheriv('aes-256-cbc', cipherKey, iv);
const decoded = decipher.update(encodedBytes);
const mediaDataBuffer = expectedSize ? fixPadding(decoded, expectedSize) : decoded;
return mediaDataBuffer;
};
const decryptMedia = async (message) => {
const options = {
responseType: 'arraybuffer',
headers: {
'User-Agent': 'WhatsApp/2.16.352 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36',
DNT: 1,
'Upgrade-Insecure-Requests': 1,
origin: 'https://web.whatsapp.com/',
referer: 'https://web.whatsapp.com/',
},
};
const res = await axios.get(message.deprecatedMms3Url.trim(), options);
const buff = Buffer.from(res.data, 'binary');
return magix(buff, message.mediaKey, message.type, message.size, message.mimetype);
};
const message = {
type: 'image',
deprecatedMms3Url: 'https://mmg.whatsapp.net/v/t62.7118-24/32988171_775415480878877_6103136834163776922_n.enc?ccb=11-4&oh=01_AdS7iKRPVP9je_HosEutBTpM5s7jFPlWIK3WVz19bZM4xA&oe=647B3771&mms3=true',
directPath: '/v/t62.7118-24/32988171_775415480878877_6103136834163776922_n.enc?ccb=11-4&oh=01_AdS7iKRPVP9je_HosEutBTpM5s7jFPlWIK3WVz19bZM4xA&oe=647B3771',
staticUrl: '',
mimetype: 'image/jpeg',
caption: 'Kek punya @areta',
filehash: 'c4ovTdfcoO5LClgIPRJTnwzA+eUdGYIx670iLLlKiNU=',
encFilehash: '1jyLb2XbsTnca0CZZ+Du7Rux0xPeW75IJ80ChxUZDdA=',
size: 189236,
height: 1520,
width: 720,
mediaKey: 'b+Jq/CPv8E1PJy+S0FB9TD4gQGVpcoVFeSKzBqPUYZI=',
mediaKeyTimestamp: 1683209371,
body: '',
interactiveAnnotations: [],
scanLengths: [
11842,
65657,
46750,
64987,
],
scansSidecar: {},
isViewOnce: true,
};
const fs = require('fs');
decryptMedia(message).then((res) => fs.writeFileSync('img.jpeg', res));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment