mirror of
https://github.com/gchq/CyberChef.git
synced 2026-01-30 04:10:31 -08:00
Merge 113b5bb0d5 into dd26c09003
This commit is contained in:
commit
3502c64a6d
10 changed files with 1015 additions and 0 deletions
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -53,6 +53,7 @@
|
|||
"jimp": "^0.22.12",
|
||||
"jq-web": "^0.5.1",
|
||||
"jquery": "3.7.1",
|
||||
"js-ascon": "^1.3.0",
|
||||
"js-sha3": "^0.9.3",
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.3",
|
||||
|
|
@ -12349,6 +12350,14 @@
|
|||
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-ascon": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/js-ascon/-/js-ascon-1.3.0.tgz",
|
||||
"integrity": "sha512-7GdMP11Ut8klrwkx+G2qRqEHhkWxmIoyVH6w+MU/4pRwWO0Dh/n3xo8wKe5IkTAdCCpU22uoHiaoB6JwGpbxcA==",
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/js-sha3": {
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz",
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@
|
|||
"jimp": "^0.22.12",
|
||||
"jq-web": "^0.5.1",
|
||||
"jquery": "3.7.1",
|
||||
"js-ascon": "^1.3.0",
|
||||
"js-sha3": "^0.9.3",
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.3",
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@
|
|||
"Rabbit",
|
||||
"SM4 Encrypt",
|
||||
"SM4 Decrypt",
|
||||
"Ascon Encrypt",
|
||||
"Ascon Decrypt",
|
||||
"GOST Encrypt",
|
||||
"GOST Decrypt",
|
||||
"GOST Sign",
|
||||
|
|
@ -427,6 +429,8 @@
|
|||
"BLAKE2b",
|
||||
"BLAKE2s",
|
||||
"BLAKE3",
|
||||
"Ascon Hash",
|
||||
"Ascon MAC",
|
||||
"GOST Hash",
|
||||
"Streebog",
|
||||
"SSDEEP",
|
||||
|
|
|
|||
112
src/core/operations/AsconDecrypt.mjs
Normal file
112
src/core/operations/AsconDecrypt.mjs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* @author Medjedtxm
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
import JsAscon from "js-ascon";
|
||||
|
||||
/**
|
||||
* Ascon Decrypt operation
|
||||
*/
|
||||
class AsconDecrypt extends Operation {
|
||||
|
||||
/**
|
||||
* AsconDecrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Ascon Decrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Ascon-AEAD128 authenticated decryption as standardised in NIST SP 800-232. Decrypts ciphertext and verifies the authentication tag. Decryption will fail if the ciphertext or associated data has been tampered with.<br><br><b>Key:</b> Must be exactly 16 bytes (128 bits).<br><br><b>Nonce:</b> Must be exactly 16 bytes (128 bits). Must match the nonce used during encryption.<br><br><b>Associated Data:</b> Must match the associated data used during encryption. Any mismatch will cause authentication failure.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Ascon_(cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Nonce",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Associated Data",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
"name": "Output",
|
||||
"type": "option",
|
||||
"value": ["Raw", "Hex"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
* @throws {OperationError} if invalid key or nonce length, or authentication fails
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
nonce = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
ad = Utils.convertToByteArray(args[2].string, args[2].option),
|
||||
inputType = args[3],
|
||||
outputType = args[4];
|
||||
|
||||
if (key.length !== 16) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes.
|
||||
|
||||
Ascon-AEAD128 requires a key of exactly 16 bytes (128 bits).`);
|
||||
}
|
||||
|
||||
if (nonce.length !== 16) {
|
||||
throw new OperationError(`Invalid nonce length: ${nonce.length} bytes.
|
||||
|
||||
Ascon-AEAD128 requires a nonce of exactly 16 bytes (128 bits).`);
|
||||
}
|
||||
|
||||
// Convert input to byte array
|
||||
const inputData = Utils.convertToByteArray(input, inputType);
|
||||
|
||||
const keyUint8 = new Uint8Array(key);
|
||||
const nonceUint8 = new Uint8Array(nonce);
|
||||
const adUint8 = new Uint8Array(ad);
|
||||
const ciphertextUint8 = new Uint8Array(inputData);
|
||||
|
||||
try {
|
||||
// Decrypt (returns Uint8Array containing plaintext)
|
||||
const plaintext = JsAscon.decrypt(keyUint8, nonceUint8, adUint8, ciphertextUint8);
|
||||
|
||||
// Return in requested format
|
||||
if (outputType === "Hex") {
|
||||
return toHexFast(plaintext);
|
||||
} else {
|
||||
return Utils.arrayBufferToStr(Uint8Array.from(plaintext).buffer);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new OperationError("Unable to decrypt: authentication failed. The ciphertext, key, nonce, or associated data may be incorrect or tampered with.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AsconDecrypt;
|
||||
108
src/core/operations/AsconEncrypt.mjs
Normal file
108
src/core/operations/AsconEncrypt.mjs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* @author Medjedtxm
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
import JsAscon from "js-ascon";
|
||||
|
||||
/**
|
||||
* Ascon Encrypt operation
|
||||
*/
|
||||
class AsconEncrypt extends Operation {
|
||||
|
||||
/**
|
||||
* AsconEncrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Ascon Encrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Ascon-AEAD128 authenticated encryption as standardised in NIST SP 800-232. Ascon is a family of lightweight authenticated encryption algorithms designed for constrained devices such as IoT sensors and embedded systems.<br><br><b>Key:</b> Must be exactly 16 bytes (128 bits).<br><br><b>Nonce:</b> Must be exactly 16 bytes (128 bits). Should be unique for each encryption with the same key. Never reuse a nonce with the same key.<br><br><b>Associated Data:</b> Optional additional data that is authenticated but not encrypted. Useful for including metadata like headers or timestamps.<br><br>The output includes both the ciphertext and a 128-bit authentication tag.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Ascon_(cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Nonce",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Associated Data",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
"type": "option",
|
||||
"value": ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
"name": "Output",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Raw"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
* @throws {OperationError} if invalid key or nonce length
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
nonce = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
ad = Utils.convertToByteArray(args[2].string, args[2].option),
|
||||
inputType = args[3],
|
||||
outputType = args[4];
|
||||
|
||||
if (key.length !== 16) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes.
|
||||
|
||||
Ascon-AEAD128 requires a key of exactly 16 bytes (128 bits).`);
|
||||
}
|
||||
|
||||
if (nonce.length !== 16) {
|
||||
throw new OperationError(`Invalid nonce length: ${nonce.length} bytes.
|
||||
|
||||
Ascon-AEAD128 requires a nonce of exactly 16 bytes (128 bits).`);
|
||||
}
|
||||
|
||||
// Convert input to byte array
|
||||
const inputData = Utils.convertToByteArray(input, inputType);
|
||||
|
||||
const keyUint8 = new Uint8Array(key);
|
||||
const nonceUint8 = new Uint8Array(nonce);
|
||||
const adUint8 = new Uint8Array(ad);
|
||||
const inputUint8 = new Uint8Array(inputData);
|
||||
|
||||
// Encrypt (returns Uint8Array containing ciphertext + tag)
|
||||
const ciphertext = JsAscon.encrypt(keyUint8, nonceUint8, adUint8, inputUint8);
|
||||
|
||||
// Return in requested format
|
||||
if (outputType === "Hex") {
|
||||
return toHexFast(ciphertext);
|
||||
} else {
|
||||
return Utils.arrayBufferToStr(Uint8Array.from(ciphertext).buffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AsconEncrypt;
|
||||
49
src/core/operations/AsconHash.mjs
Normal file
49
src/core/operations/AsconHash.mjs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @author Medjedtxm
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
import JsAscon from "js-ascon";
|
||||
|
||||
/**
|
||||
* Ascon Hash operation
|
||||
*/
|
||||
class AsconHash extends Operation {
|
||||
|
||||
/**
|
||||
* AsconHash constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Ascon Hash";
|
||||
this.module = "Crypto";
|
||||
this.description = "Ascon-Hash256 produces a fixed 256-bit (32-byte) cryptographic hash as standardised in NIST SP 800-232. Ascon is a family of lightweight authenticated encryption and hashing algorithms designed for constrained devices such as IoT sensors and embedded systems.<br><br>The algorithm was selected by NIST in 2023 as the new standard for lightweight cryptography after a multi-year competition.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Ascon_(cipher)";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
|
||||
const inputUint8 = new Uint8Array(input);
|
||||
|
||||
// Compute hash (returns Uint8Array)
|
||||
const hashResult = JsAscon.hash(inputUint8);
|
||||
|
||||
// Convert to hex string
|
||||
return toHexFast(hashResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AsconHash;
|
||||
68
src/core/operations/AsconMAC.mjs
Normal file
68
src/core/operations/AsconMAC.mjs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @author Medjedtxm
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
import AsconMac from "../vendor/ascon.mjs";
|
||||
|
||||
/**
|
||||
* Ascon MAC operation
|
||||
*/
|
||||
class AsconMAC extends Operation {
|
||||
|
||||
/**
|
||||
* AsconMAC constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Ascon MAC";
|
||||
this.module = "Crypto";
|
||||
this.description = "Ascon-Mac produces a 128-bit (16-byte) message authentication code as part of the Ascon family standardised by NIST in SP 800-232. It provides authentication for messages using a secret key, ensuring both data integrity and authenticity.<br><br>Ascon is designed for lightweight cryptography on constrained devices such as IoT sensors and embedded systems.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Ascon_(cipher)";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
* @throws {OperationError} if invalid key length
|
||||
*/
|
||||
run(input, args) {
|
||||
const keyArray = Utils.convertToByteArray(args[0].string, args[0].option);
|
||||
|
||||
if (keyArray.length !== 16) {
|
||||
throw new OperationError(`Invalid key length: ${keyArray.length} bytes.
|
||||
|
||||
Ascon-Mac requires a key of exactly 16 bytes (128 bits).`);
|
||||
}
|
||||
|
||||
// Convert to Uint8Array for vendor Ascon implementation
|
||||
const keyUint8 = new Uint8Array(keyArray);
|
||||
const inputUint8 = new Uint8Array(input);
|
||||
|
||||
// Compute MAC (returns Uint8Array)
|
||||
const macResult = AsconMac.mac(keyUint8, inputUint8);
|
||||
|
||||
// Convert to hex string
|
||||
return toHexFast(macResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AsconMAC;
|
||||
162
src/core/vendor/ascon.mjs
vendored
Normal file
162
src/core/vendor/ascon.mjs
vendored
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/**
|
||||
* Ascon MAC implementation following NIST SP 800-232
|
||||
* Vendor file for CyberChef
|
||||
*
|
||||
* @author Medjedtxm
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* NIST SP 800-232 compliant Ascon-Mac implementation
|
||||
* Uses little-endian byte ordering as per NIST specification
|
||||
*/
|
||||
class AsconMac {
|
||||
// NIST SP 800-232 constants
|
||||
static ASCON_MAC_IV = 0x0010200080cc0005n;
|
||||
static ASCON_PRF_IN_RATE = 32; // 4 * 8 bytes
|
||||
static ASCON_PRF_OUT_RATE = 16; // 2 * 8 bytes
|
||||
|
||||
/**
|
||||
* Compute Ascon-Mac tag
|
||||
* @param {Uint8Array} key - 16-byte key
|
||||
* @param {Uint8Array} message - Message to authenticate
|
||||
* @param {number} tagLength - Output tag length (default 16)
|
||||
* @returns {Uint8Array} - MAC tag
|
||||
*/
|
||||
static mac(key, message, tagLength = 16) {
|
||||
if (key.length !== 16) {
|
||||
throw new Error(`Invalid key length: ${key.length} bytes. Ascon-Mac requires exactly 16 bytes.`);
|
||||
}
|
||||
|
||||
// Initialise state
|
||||
const state = new BigUint64Array(5);
|
||||
|
||||
// Load key as two 64-bit words (little-endian per NIST SP 800-232)
|
||||
const K0 = AsconMac.loadBytes(key, 0, 8);
|
||||
const K1 = AsconMac.loadBytes(key, 8, 8);
|
||||
|
||||
// Set initial value per NIST SP 800-232
|
||||
state[0] = AsconMac.ASCON_MAC_IV;
|
||||
state[1] = K0;
|
||||
state[2] = K1;
|
||||
state[3] = 0n;
|
||||
state[4] = 0n;
|
||||
|
||||
// Initial permutation P12
|
||||
AsconMac.permutation(state, 12);
|
||||
|
||||
// Absorb message in 8-byte chunks, cycling through state[0..3]
|
||||
let pos = 0;
|
||||
let wordIdx = 0;
|
||||
|
||||
while (pos + 8 <= message.length) {
|
||||
state[wordIdx] ^= AsconMac.loadBytes(message, pos, 8);
|
||||
wordIdx++;
|
||||
if (wordIdx === 4) {
|
||||
wordIdx = 0;
|
||||
AsconMac.permutation(state, 12);
|
||||
}
|
||||
pos += 8;
|
||||
}
|
||||
|
||||
// Absorb final partial block with padding
|
||||
const remaining = message.length - pos;
|
||||
if (remaining > 0) {
|
||||
state[wordIdx] ^= AsconMac.loadBytes(message, pos, remaining);
|
||||
}
|
||||
// PAD(remaining) = 0x01 << (8 * remaining)
|
||||
state[wordIdx] ^= 0x01n << BigInt(8 * remaining);
|
||||
|
||||
// Domain separation: DSEP() = 0x80 << 56 = 0x8000000000000000
|
||||
state[4] ^= 0x8000000000000000n;
|
||||
|
||||
// Finalisation permutation P12
|
||||
AsconMac.permutation(state, 12);
|
||||
|
||||
// Squeeze output
|
||||
const tag = new Uint8Array(tagLength);
|
||||
let outPos = 0;
|
||||
wordIdx = 0;
|
||||
|
||||
while (outPos < tagLength) {
|
||||
const toCopy = Math.min(8, tagLength - outPos);
|
||||
AsconMac.storeBytes(tag, outPos, state[wordIdx], toCopy);
|
||||
outPos += toCopy;
|
||||
wordIdx++;
|
||||
if (wordIdx === 2 && outPos < tagLength) {
|
||||
wordIdx = 0;
|
||||
AsconMac.permutation(state, 12);
|
||||
}
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load n bytes as little-endian 64-bit integer (NIST SP 800-232 byte order)
|
||||
* LOADBYTES: bytes[i] goes to position i (byte 0 = LSB)
|
||||
*/
|
||||
static loadBytes(arr, offset, n) {
|
||||
let result = 0n;
|
||||
for (let i = 0; i < n && offset + i < arr.length; i++) {
|
||||
result |= BigInt(arr[offset + i]) << BigInt(i * 8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store n bytes from 64-bit integer in little-endian order
|
||||
* STOREBYTES: position i goes to bytes[i] (LSB = byte 0)
|
||||
*/
|
||||
static storeBytes(arr, offset, val, n) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
arr[offset + i] = Number((val >> BigInt(i * 8)) & 0xFFn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascon permutation
|
||||
*/
|
||||
static permutation(state, rounds) {
|
||||
for (let r = 12 - rounds; r < 12; r++) {
|
||||
// Add round constant
|
||||
state[2] ^= BigInt(0xf0 - r * 0x10 + r);
|
||||
|
||||
// Substitution layer
|
||||
state[0] ^= state[4];
|
||||
state[4] ^= state[3];
|
||||
state[2] ^= state[1];
|
||||
|
||||
const t0 = state[0] ^ (~state[1] & state[2]);
|
||||
const t1 = state[1] ^ (~state[2] & state[3]);
|
||||
const t2 = state[2] ^ (~state[3] & state[4]);
|
||||
const t3 = state[3] ^ (~state[4] & state[0]);
|
||||
const t4 = state[4] ^ (~state[0] & state[1]);
|
||||
|
||||
state[0] = t0 ^ t4;
|
||||
state[1] = t1 ^ t0;
|
||||
state[2] = ~t2;
|
||||
state[3] = t3 ^ t2;
|
||||
state[4] = t4;
|
||||
|
||||
// Linear diffusion layer
|
||||
state[0] ^= AsconMac.rotr64(state[0], 19n) ^ AsconMac.rotr64(state[0], 28n);
|
||||
state[1] ^= AsconMac.rotr64(state[1], 61n) ^ AsconMac.rotr64(state[1], 39n);
|
||||
state[2] ^= AsconMac.rotr64(state[2], 1n) ^ AsconMac.rotr64(state[2], 6n);
|
||||
state[3] ^= AsconMac.rotr64(state[3], 10n) ^ AsconMac.rotr64(state[3], 17n);
|
||||
state[4] ^= AsconMac.rotr64(state[4], 7n) ^ AsconMac.rotr64(state[4], 41n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 64-bit rotate right
|
||||
*/
|
||||
static rotr64(val, n) {
|
||||
const mask = 0xFFFFFFFFFFFFFFFFn;
|
||||
val = val & mask;
|
||||
return ((val >> n) | (val << (64n - n))) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
export default AsconMac;
|
||||
|
|
@ -16,6 +16,7 @@ import { setLongTestFailure, logTestReport } from "../lib/utils.mjs";
|
|||
import TestRegister from "../lib/TestRegister.mjs";
|
||||
import "./tests/AESKeyWrap.mjs";
|
||||
import "./tests/AlternatingCaps.mjs";
|
||||
import "./tests/Ascon.mjs";
|
||||
import "./tests/AvroToJSON.mjs";
|
||||
import "./tests/BaconCipher.mjs";
|
||||
import "./tests/Base32.mjs";
|
||||
|
|
|
|||
501
tests/operations/tests/Ascon.mjs
Normal file
501
tests/operations/tests/Ascon.mjs
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
/**
|
||||
* Ascon tests.
|
||||
*
|
||||
* Test vectors include official NIST ACVP vectors from:
|
||||
* https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/Ascon-Hash256-SP800-232
|
||||
* https://github.com/ascon/ascon-c (LWC_AEAD_KAT files)
|
||||
*
|
||||
* @author Medjedtxm
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
// ============= Ascon Hash Tests (NIST SP 800-232) =============
|
||||
// Official NIST ACVP test vector
|
||||
{
|
||||
name: "Ascon Hash: NIST ACVP vector (msg=0x50)",
|
||||
input: "P", // 0x50
|
||||
expectedOutput: "b96da347d720272533a87f5a94a356155f49cdf7c0c10a3e6f346d8a2293e480",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Hash",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Hash: empty input",
|
||||
input: "",
|
||||
expectedOutput: "0b3be5850f2f6b98caf29f8fdea89b64a1fa70aa249b8f839bd53baa304d92b2",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Hash",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Hash: Hello",
|
||||
input: "Hello",
|
||||
expectedOutput: "c1beebe1251d562c4526d6b947cefb932998499424f6cd186e764aa0a36cddb7",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Hash",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Hash: Hello, World!",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "f40e1ce8d4272e628e9535193f196f4ff2a720b00f6380c5d6f16b975f3a7777",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Hash",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// ============= Ascon MAC Tests (NIST LWC_MAC_KAT_128_128.txt) =============
|
||||
// Official test vectors from ascon-c: https://github.com/ascon/ascon-c/blob/main/crypto_auth/asconmacv13/LWC_MAC_KAT_128_128.txt
|
||||
{
|
||||
name: "Ascon MAC: NIST KAT Count=1 (empty message)",
|
||||
input: "",
|
||||
expectedOutput: "eac9d74bbedf8bf1eba2862b26aa6d39",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon MAC",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon MAC: NIST KAT Count=2 (Msg=0x10)",
|
||||
input: "\x10",
|
||||
expectedOutput: "e5be5b6dfb7b0e3eae00a070791947a8",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon MAC",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon MAC: NIST KAT Count=5 (Msg=0x10111213)",
|
||||
input: "\x10\x11\x12\x13",
|
||||
expectedOutput: "727f6386405a52ad7ca0669a6a885294",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon MAC",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon MAC: invalid key length",
|
||||
input: "test",
|
||||
expectedOutput: "Invalid key length: 8 bytes.\n\nAscon-Mac requires a key of exactly 16 bytes (128 bits).",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon MAC",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "0001020304050607"}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// ============= Ascon Encrypt Tests (NIST SP 800-232) =============
|
||||
// Official NIST ascon-c KAT test vector (Count=1)
|
||||
// https://github.com/ascon/ascon-c/blob/main/crypto_aead/asconaead128/LWC_AEAD_KAT_128_128.txt
|
||||
{
|
||||
name: "Ascon Encrypt: NIST KAT Count=1 (empty PT, empty AD)",
|
||||
input: "",
|
||||
expectedOutput: "4f9c278211bec9316bf68f46ee8b2ec6",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
// Official NIST ascon-c KAT test vector (Count=2)
|
||||
{
|
||||
name: "Ascon Encrypt: NIST KAT Count=2 (empty PT, AD=0x30)",
|
||||
input: "",
|
||||
expectedOutput: "cccb674fe18a09a285d6ab11b35675c0",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "Hex", "string": "30"},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
// Official NIST ascon-c KAT test vector (Count=34) - PT=0x20
|
||||
{
|
||||
name: "Ascon Encrypt: NIST KAT Count=34 (PT=0x20, empty AD)",
|
||||
input: "\x20",
|
||||
expectedOutput: "e8dd576aba1cd3e6fc704de02aedb79588",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
// Official NIST ascon-c KAT test vector (Count=341) - PT + AD
|
||||
{
|
||||
name: "Ascon Encrypt: NIST KAT Count=341 (PT=10 bytes, AD=10 bytes)",
|
||||
input: "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29",
|
||||
expectedOutput: "12042996da42b4536e5a0e64692cf6041ff8c367e1423253c84c",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "Hex", "string": "30313233343536373839"},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
// Official NIST ascon-c KAT test vector (PT=16 bytes, AD=16 bytes)
|
||||
{
|
||||
name: "Ascon Encrypt: NIST KAT (PT=16 bytes, AD=16 bytes)",
|
||||
input: "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
|
||||
expectedOutput: "6373ebb28be97c9bac090cf399c13ef13abfc0d209e8f4844c90814d13f32c59",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "Hex", "string": "303132333435363738393a3b3c3d3e3f"},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
// https://github.com/ascon/ascon-c/blob/main/crypto_aead/asconaead128/LWC_AEAD_KAT_128_128.txt
|
||||
{
|
||||
name: "Ascon Encrypt: no key",
|
||||
input: "test message",
|
||||
expectedOutput: `Invalid key length: 0 bytes.
|
||||
|
||||
Ascon-AEAD128 requires a key of exactly 16 bytes (128 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: invalid key length",
|
||||
input: "test message",
|
||||
expectedOutput: `Invalid key length: 8 bytes.
|
||||
|
||||
Ascon-AEAD128 requires a key of exactly 16 bytes (128 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "0001020304050607"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: no nonce",
|
||||
input: "test message",
|
||||
expectedOutput: `Invalid nonce length: 0 bytes.
|
||||
|
||||
Ascon-AEAD128 requires a nonce of exactly 16 bytes (128 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: invalid nonce length",
|
||||
input: "test message",
|
||||
expectedOutput: `Invalid nonce length: 12 bytes.
|
||||
|
||||
Ascon-AEAD128 requires a nonce of exactly 16 bytes (128 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: basic encryption",
|
||||
input: "Hello",
|
||||
expectedOutput: "af14bce6b9b6588c3aa63f9ddc5a0cf5f565f358b0",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: with associated data",
|
||||
input: "Hello",
|
||||
expectedOutput: "351880c09f9dee12c20c4ba973066bc10dd26000b6",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "UTF8", "string": "metadata"},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: longer message",
|
||||
input: "test message",
|
||||
expectedOutput: "9314a3fef6cc299a07b8c9e0f9e479ca0d1187e87345cf590adc572b",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: empty plaintext",
|
||||
input: "",
|
||||
expectedOutput: "4427d64b8e1e1451fc445960f0839bb0",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Encrypt: zero key and nonce",
|
||||
input: "Hello",
|
||||
expectedOutput: "403281e117ebb087e2d9196552b2d123bccb7b5500",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "00000000000000000000000000000000"},
|
||||
{"option": "Hex", "string": "00000000000000000000000000000000"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// ============= Ascon Decrypt Tests =============
|
||||
{
|
||||
name: "Ascon Decrypt: no key",
|
||||
input: "af14bce6b9b6588c3aa63f9ddc5a0cf5f565f358b0",
|
||||
expectedOutput: `Invalid key length: 0 bytes.
|
||||
|
||||
Ascon-AEAD128 requires a key of exactly 16 bytes (128 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Decrypt: basic decryption",
|
||||
input: "af14bce6b9b6588c3aa63f9ddc5a0cf5f565f358b0",
|
||||
expectedOutput: "Hello",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Decrypt: with associated data",
|
||||
input: "351880c09f9dee12c20c4ba973066bc10dd26000b6",
|
||||
expectedOutput: "Hello",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "UTF8", "string": "metadata"},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Decrypt: longer message",
|
||||
input: "9314a3fef6cc299a07b8c9e0f9e479ca0d1187e87345cf590adc572b",
|
||||
expectedOutput: "test message",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Decrypt: authentication failure (tampered ciphertext)",
|
||||
input: "bf14bce6b9b6588c3aa63f9ddc5a0cf5f565f358b0",
|
||||
expectedOutput: "Unable to decrypt: authentication failed. The ciphertext, key, nonce, or associated data may be incorrect or tampered with.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Decrypt: authentication failure (wrong key)",
|
||||
input: "af14bce6b9b6588c3aa63f9ddc5a0cf5f565f358b0",
|
||||
expectedOutput: "Unable to decrypt: authentication failed. The ciphertext, key, nonce, or associated data may be incorrect or tampered with.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "ff0102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": ""},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Ascon Decrypt: authentication failure (wrong associated data)",
|
||||
input: "351880c09f9dee12c20c4ba973066bc10dd26000b6",
|
||||
expectedOutput: "Unable to decrypt: authentication failed. The ciphertext, key, nonce, or associated data may be incorrect or tampered with.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "UTF8", "string": "wrong data"},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
// ============= Round-trip Tests =============
|
||||
{
|
||||
name: "Ascon: encrypt then decrypt round-trip",
|
||||
input: "This is a test message for Ascon AEAD encryption!",
|
||||
expectedOutput: "This is a test message for Ascon AEAD encryption!",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Ascon Encrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "UTF8", "string": "additional data"},
|
||||
"Raw", "Hex"
|
||||
]
|
||||
},
|
||||
{
|
||||
"op": "Ascon Decrypt",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
|
||||
{"option": "Hex", "string": "101112131415161718191a1b1c1d1e1f"},
|
||||
{"option": "UTF8", "string": "additional data"},
|
||||
"Hex", "Raw"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
Loading…
Add table
Add a link
Reference in a new issue