Path: blob/master/node_modules/@adiwajshing/baileys/lib/Utils/noise-handler.js
2593 views
"use strict";1Object.defineProperty(exports, "__esModule", { value: true });2exports.makeNoiseHandler = void 0;3const boom_1 = require("@hapi/boom");4const crypto_1 = require("crypto");5const WAProto_1 = require("../../WAProto");6const Defaults_1 = require("../Defaults");7const WABinary_1 = require("../WABinary");8const WABinary_2 = require("../WABinary");9const crypto_2 = require("./crypto");10const generateIV = (counter) => {11const iv = new ArrayBuffer(12);12new DataView(iv).setUint32(8, counter);13return new Uint8Array(iv);14};15const makeNoiseHandler = ({ public: publicKey, private: privateKey }) => {16const authenticate = (data) => {17if (!isFinished) {18hash = crypto_2.sha256(Buffer.from(WABinary_1.Binary.build(hash, data).readByteArray()));19}20};21const encrypt = (plaintext) => {22const authTagLength = 128 >> 3;23const cipher = crypto_1.createCipheriv('aes-256-gcm', encKey, generateIV(writeCounter), { authTagLength });24cipher.setAAD(hash);25const result = Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]);26writeCounter += 1;27authenticate(result);28return result;29};30const decrypt = (ciphertext) => {31// before the handshake is finished, we use the same counter32// after handshake, the counters are different33const iv = generateIV(isFinished ? readCounter : writeCounter);34const cipher = crypto_1.createDecipheriv('aes-256-gcm', decKey, iv);35// decrypt additional adata36const tagLength = 128 >> 3;37const enc = ciphertext.slice(0, ciphertext.length - tagLength);38const tag = ciphertext.slice(ciphertext.length - tagLength);39// set additional data40cipher.setAAD(hash);41cipher.setAuthTag(tag);42const result = Buffer.concat([cipher.update(enc), cipher.final()]);43if (isFinished) {44readCounter += 1;45}46else {47writeCounter += 1;48}49authenticate(ciphertext);50return result;51};52const localHKDF = (data) => {53const key = crypto_2.hkdf(Buffer.from(data), 64, { salt, info: '' });54return [key.slice(0, 32), key.slice(32)];55};56const mixIntoKey = (data) => {57const [write, read] = localHKDF(data);58salt = write;59encKey = read;60decKey = read;61readCounter = 0;62writeCounter = 0;63};64const finishInit = () => {65const [write, read] = localHKDF(new Uint8Array(0));66encKey = write;67decKey = read;68hash = Buffer.from([]);69readCounter = 0;70writeCounter = 0;71isFinished = true;72};73const data = WABinary_1.Binary.build(Defaults_1.NOISE_MODE).readBuffer();74let hash = Buffer.from(data.byteLength === 32 ? data : crypto_2.sha256(Buffer.from(data)));75let salt = hash;76let encKey = hash;77let decKey = hash;78let readCounter = 0;79let writeCounter = 0;80let isFinished = false;81let sentIntro = false;82const outBinary = new WABinary_1.Binary();83const inBinary = new WABinary_1.Binary();84authenticate(Defaults_1.NOISE_WA_HEADER);85authenticate(publicKey);86return {87encrypt,88decrypt,89authenticate,90mixIntoKey,91finishInit,92processHandshake: ({ serverHello }, noiseKey) => {93authenticate(serverHello.ephemeral);94mixIntoKey(crypto_2.Curve.sharedKey(privateKey, serverHello.ephemeral));95const decStaticContent = decrypt(serverHello.static);96mixIntoKey(crypto_2.Curve.sharedKey(privateKey, decStaticContent));97const certDecoded = decrypt(serverHello.payload);98const { details: certDetails, signature: certSignature } = WAProto_1.proto.NoiseCertificate.decode(certDecoded);99const { key: certKey } = WAProto_1.proto.NoiseCertificateDetails.decode(certDetails);100if (Buffer.compare(decStaticContent, certKey) !== 0) {101throw new boom_1.Boom('certification match failed', { statusCode: 400 });102}103const keyEnc = encrypt(noiseKey.public);104mixIntoKey(crypto_2.Curve.sharedKey(noiseKey.private, serverHello.ephemeral));105return keyEnc;106},107encodeFrame: (data) => {108if (isFinished) {109data = encrypt(data);110}111const introSize = sentIntro ? 0 : Defaults_1.NOISE_WA_HEADER.length;112outBinary.ensureAdditionalCapacity(introSize + 3 + data.byteLength);113if (!sentIntro) {114outBinary.writeByteArray(Defaults_1.NOISE_WA_HEADER);115sentIntro = true;116}117outBinary.writeUint8(data.byteLength >> 16);118outBinary.writeUint16(65535 & data.byteLength);119outBinary.write(data);120const bytes = outBinary.readByteArray();121return bytes;122},123decodeFrame: (newData, onFrame) => {124// the binary protocol uses its own framing mechanism125// on top of the WS frames126// so we get this data and separate out the frames127const getBytesSize = () => {128return (inBinary.readUint8() << 16) | inBinary.readUint16();129};130const peekSize = () => {131return !(inBinary.size() < 3) && getBytesSize() <= inBinary.size();132};133inBinary.writeByteArray(newData);134while (inBinary.peek(peekSize)) {135const bytes = getBytesSize();136let frame = inBinary.readByteArray(bytes);137if (isFinished) {138const result = decrypt(frame);139const unpacked = new WABinary_1.Binary(result).decompressed();140frame = WABinary_2.decodeBinaryNode(unpacked);141}142onFrame(frame);143}144inBinary.peek(peekSize);145}146};147};148exports.makeNoiseHandler = makeNoiseHandler;149150151