import { MAX_ATTACHMENT_FILESIZE_BYTES } from '../constants'; /** * This file is used to pad message buffer and attachments */ const PADDING_BYTE = 0x00; /** * Unpad the buffer from its padding. * An error is thrown if there is no padding. * A padded buffer is * * whatever at start * * ends with 0x80 and any number of 0x00 until the end */ export function removeMessagePadding(paddedData: ArrayBuffer): ArrayBuffer { const paddedPlaintext = new Uint8Array(paddedData); // window?.log?.info('Removing message padding...'); for (let i = paddedPlaintext.length - 1; i >= 0; i -= 1) { if (paddedPlaintext[i] === 0x80) { const plaintext = new Uint8Array(i); plaintext.set(paddedPlaintext.subarray(0, i)); return plaintext.buffer; } else if (paddedPlaintext[i] !== PADDING_BYTE) { // window?.log?.warn('got a message without padding... Letting it through for now'); return paddedPlaintext; } } throw new Error('Invalid padding'); } /** * Add padding to a message buffer * @param messageBuffer The buffer to add padding to. */ export function addMessagePadding(messageBuffer: Uint8Array): Uint8Array { // window?.log?.info('Adding message padding...'); const plaintext = new Uint8Array(getPaddedMessageLength(messageBuffer.byteLength + 1) - 1); plaintext.set(new Uint8Array(messageBuffer)); plaintext[messageBuffer.byteLength] = 0x80; return plaintext; } function getPaddedMessageLength(originalLength: number): number { const messageLengthWithTerminator = originalLength + 1; let messagePartCount = Math.floor(messageLengthWithTerminator / 160); if (messageLengthWithTerminator % 160 !== 0) { messagePartCount += 1; } return messagePartCount * 160; } /* * If the attachment has padding, remove the padding and return the unpad attachment */ export function getUnpaddedAttachment( data: ArrayBuffer, unpaddedExpectedSize: number ): ArrayBuffer | null { // window?.log?.debug('Removing attachment padding...'); // to have a padding we must have a strictly longer length expected if (data.byteLength <= unpaddedExpectedSize) { return null; } // we now consider that anything coming after the expected size is padding, no matter what there is there return data.slice(0, unpaddedExpectedSize); } export function addAttachmentPadding(data: ArrayBuffer): ArrayBuffer { const originalUInt = new Uint8Array(data); window?.log?.info('Adding attachment padding...'); let paddedSize = Math.max( 541, Math.floor(Math.pow(1.05, Math.ceil(Math.log(originalUInt.length) / Math.log(1.05)))) ); if ( paddedSize > MAX_ATTACHMENT_FILESIZE_BYTES && originalUInt.length <= MAX_ATTACHMENT_FILESIZE_BYTES ) { paddedSize = MAX_ATTACHMENT_FILESIZE_BYTES; } const paddedData = new ArrayBuffer(paddedSize); const paddedUInt = new Uint8Array(paddedData); paddedUInt.fill(PADDING_BYTE, originalUInt.length); paddedUInt.set(originalUInt); return paddedUInt.buffer; }