diff --git a/src/Utils/crypto.ts b/src/Utils/crypto.ts index fa08e22..7855eb5 100644 --- a/src/Utils/crypto.ts +++ b/src/Utils/crypto.ts @@ -46,6 +46,34 @@ export const signedKeyPair = (identityKeyPair: KeyPair, keyId: number) => { return { keyPair: preKey, signature, keyId } } +const GCM_TAG_LENGTH = 128 >> 3 + +/** + * encrypt AES 256 GCM; + * where the tag tag is suffixed to the ciphertext + * */ +export function aesEncryptGCM(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array, additionalData: Uint8Array) { + const cipher = createCipheriv('aes-256-gcm', key, iv) + cipher.setAAD(additionalData) + return Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]) +} + +/** + * decrypt AES 256 GCM; + * where the auth tag is suffixed to the ciphertext + * */ +export function aesDecryptGCM(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, additionalData: Uint8Array) { + const decipher = createDecipheriv('aes-256-gcm', key, iv) + // decrypt additional adata + const enc = ciphertext.slice(0, ciphertext.length - GCM_TAG_LENGTH) + const tag = ciphertext.slice(ciphertext.length - GCM_TAG_LENGTH) + // set additional data + decipher.setAAD(additionalData) + decipher.setAuthTag(tag) + + return Buffer.concat([ decipher.update(enc), decipher.final() ]) +} + /** decrypt AES 256 CBC; where the IV is prefixed to the buffer */ export function aesDecrypt(buffer: Buffer, key: Buffer) { return aesDecryptWithIV(buffer.slice(16, buffer.length), key, buffer.slice(0, 16)) diff --git a/src/Utils/noise-handler.ts b/src/Utils/noise-handler.ts index 7eb92ba..4bc979c 100644 --- a/src/Utils/noise-handler.ts +++ b/src/Utils/noise-handler.ts @@ -1,13 +1,10 @@ import { Boom } from '@hapi/boom' -import { createCipheriv, createDecipheriv } from 'crypto' import { Logger } from 'pino' import { proto } from '../../WAProto' import { NOISE_MODE, NOISE_WA_HEADER, WA_CERT_DETAILS } from '../Defaults' import { KeyPair } from '../Types' import { BinaryNode, decodeBinaryNode } from '../WABinary' -import { Curve, hkdf, sha256 } from './crypto' - -const TAG_LENGTH = 128 >> 3 +import { aesDecryptGCM, aesEncryptGCM, Curve, hkdf, sha256 } from './crypto' const generateIV = (counter: number) => { const iv = new ArrayBuffer(12) @@ -29,10 +26,7 @@ export const makeNoiseHandler = ( } const encrypt = (plaintext: Uint8Array) => { - const cipher = createCipheriv('aes-256-gcm', encKey, generateIV(writeCounter), { authTagLength: TAG_LENGTH }) - cipher.setAAD(hash) - - const result = Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]) + const result = aesEncryptGCM(plaintext, encKey, generateIV(writeCounter), hash) writeCounter += 1 @@ -44,15 +38,7 @@ export const makeNoiseHandler = ( // before the handshake is finished, we use the same counter // after handshake, the counters are different const iv = generateIV(isFinished ? readCounter : writeCounter) - const cipher = createDecipheriv('aes-256-gcm', decKey, iv) - // decrypt additional adata - const enc = ciphertext.slice(0, ciphertext.length - TAG_LENGTH) - const tag = ciphertext.slice(ciphertext.length - TAG_LENGTH) - // set additional data - cipher.setAAD(hash) - cipher.setAuthTag(tag) - - const result = Buffer.concat([cipher.update(enc), cipher.final()]) + const result = aesDecryptGCM(ciphertext, decKey, iv, hash) if(isFinished) { readCounter += 1