aead
This commit is contained in:
		
							
								
								
									
										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); | ||||
|     }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user