session-desktop/ts/session/crypto/BufferPadding.ts
2021-10-14 14:12:14 +11:00

88 lines
2.7 KiB
TypeScript

/**
* 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?.info('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...');
const paddedSize = Math.max(
541,
Math.floor(Math.pow(1.05, Math.ceil(Math.log(originalUInt.length) / Math.log(1.05))))
);
const paddedData = new ArrayBuffer(paddedSize);
const paddedUInt = new Uint8Array(paddedData);
paddedUInt.fill(PADDING_BYTE, originalUInt.length);
paddedUInt.set(originalUInt);
return paddedUInt.buffer;
}