aead
This commit is contained in:
parent
512b827b40
commit
b43894b58f
115
src/aead.js
Normal file
115
src/aead.js
Normal 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 };
|
@ -37,4 +37,4 @@ class keccakKDF {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { keccakKDF };
|
module.exports = { keccakKDF, concatUint8Arrays };
|
||||||
|
25
tests/aead.test.js
Normal file
25
tests/aead.test.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user