This commit is contained in:
Sam Hadow 2025-03-05 16:41:58 +01:00
parent 512b827b40
commit b43894b58f
3 changed files with 141 additions and 1 deletions

115
src/aead.js Normal file
View File

@ -0,0 +1,115 @@
const kdf = require('./kdf');
const keccak = require('./keccak');
function splitIntoChunks(data) {
const chunks = [];
const chunkSize = 16;
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
chunks.push(chunk);
}
return chunks;
}
class keccakAEAD {
constructor(iv, key) {
const input = kdf.concatUint8Arrays(iv, key);
this.state = keccak.SHAKE256(input, 32);
}
associated_data_processing(associated_data) {
const chunks = splitIntoChunks(associated_data);
let to_xor = null;
let c = null;
let r = null;
let input = null;
chunks.forEach((chunk) => {
to_xor = this.state.slice(0, 16);
c = this.state.slice(16, 32);
r = new Uint8Array(chunk.length);
for (let i = 0; i < chunk.length; i++) {
r[i] = chunk[i] ^ to_xor[i];
}
input = kdf.concatUint8Arrays(c, r);
this.state = keccak.SHAKE256(input, 32);
});
}
plaintext_processing(plaintext) {
const chunks = splitIntoChunks(plaintext);
let to_xor = null;
let c = null;
let r = null;
let input = null;
let cipherchunks = [];
chunks.forEach((chunk) => {
to_xor = this.state.slice(0, 16);
c = this.state.slice(16, 32);
r = new Uint8Array(chunk.length);
for (let i = 0; i < chunk.length; i++) {
r[i] = chunk[i] ^ to_xor[i];
}
cipherchunks.push(r);
input = kdf.concatUint8Arrays(c, r);
this.state = keccak.SHAKE256(input, 32);
});
return cipherchunks;
}
ciphertext_processing(ciphertext) {
const chunks = splitIntoChunks(ciphertext);
let to_xor = null;
let c = null;
let r = null;
let input = null;
let plaintextchunks = [];
chunks.forEach((chunk) => {
to_xor = this.state.slice(0, 16);
c = this.state.slice(16, 32);
r = new Uint8Array(chunk.length);
for (let i = 0; i < chunk.length; i++) {
r[i] = chunk[i] ^ to_xor[i];
}
plaintextchunks.push(r);
input = kdf.concatUint8Arrays(c, chunk);
this.state = keccak.SHAKE256(input, 32);
});
return plaintextchunks;
}
finalize(key) {
const output = keccak.SHAKE256(this.state, 32);
let to_xor = output.slice(16, 32);
let tag = new Uint8Array(key.length);
for (let i = 0; i < key.length; i++) {
tag[i] = key[i] ^ to_xor[i];
}
return tag;
}
static encrypt(key, plaintext, iv, associated_data) {
let sponge = new keccakAEAD(iv, key);
sponge.associated_data_processing(associated_data);
let cipherChunks = sponge.plaintext_processing(plaintext);
let ciphertext = kdf.concatUint8Arrays(...cipherChunks);
let tag = sponge.finalize(key);
return {
cipher: ciphertext,
tag: tag
};
}
static decrypt(key, ciphertext, iv, associated_data) {
let sponge = new keccakAEAD(iv, key);
sponge.associated_data_processing(associated_data);
let plaintextChunks = sponge.ciphertext_processing(ciphertext);
let plaintext = kdf.concatUint8Arrays(...plaintextChunks);
let tag = sponge.finalize(key);
return {
plaintext: plaintext,
tag: tag
};
}
}
module.exports = { keccakAEAD };

View File

@ -37,4 +37,4 @@ class keccakKDF {
}
module.exports = { keccakKDF };
module.exports = { keccakKDF, concatUint8Arrays };

25
tests/aead.test.js Normal file
View File

@ -0,0 +1,25 @@
const aead = require('../src/aead');
const crypto = require('crypto');
function generateRandomUint8Array(length = 16) {
const randomArray = new Uint8Array(length);
crypto.getRandomValues(randomArray);
return randomArray;
}
describe('aead.js functions', () => {
it('encrypt and decrypt', () => {
let msg = generateRandomUint8Array(28);
console.log(msg);
let ad = generateRandomUint8Array(12);
let iv = generateRandomUint8Array();
let key = generateRandomUint8Array();
let result = aead.keccakAEAD.encrypt(key, msg, iv, ad);
console.log(result.tag);
console.log(result.cipher);
let result2 = aead.keccakAEAD.decrypt(key, result.cipher, iv, ad);
console.log(result2.tag);
console.log(result2.plaintext);
});
});