Add Chacha20-Poly1305 Decryption

This commit is contained in:
Andy Wang 2020-01-14 00:12:05 +00:00
parent f30000e62f
commit ff72ea1116
2 changed files with 127 additions and 0 deletions

View file

@ -72,6 +72,7 @@
"Blowfish Encrypt",
"Blowfish Decrypt",
"Chacha20-Poly1305 Encrypt",
"Chacha20-Poly1305 Decrypt",
"DES Encrypt",
"DES Decrypt",
"Triple DES Encrypt",

View file

@ -0,0 +1,126 @@
/**
* @author cbeuw [cbeuw.andy@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import Chacha20 from "../lib/Chacha20";
import Chacha20Poly1305 from "../lib/Chacha20Poly1305";
/**
* Chacha20-Poly1305 Decrypt operation
*/
class Chacha20Poly1305Decrypt extends Operation {
/**
* Chacha20Poly1305Decrypt constructor
*/
constructor() {
super();
this.name = "Chacha20-Poly1305 Decrypt";
this.module = "Crypto";
this.description = "Chacha20 is a stream cipher developed by Daniel Bernstein based on Salsa20. The cipher and the massage authentication code Poly1305 are defined by RFC8439. Chacha20 and Poly1305 are frequently used together for authenticated encryption, and has been included in TLS 1.3 protocol.<br><br><b>Key:</b> Key length should be 32 bytes (256 bits).<br><br><b>Nonce:</b> The one-time nonce should be 8 or 12 bytes long (64 or 96 bits).";
this.infoURL = "https://tools.ietf.org/html/rfc8439";
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": "Input",
"type": "option",
"value": ["Raw", "Hex"]
},
{
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
},
{
"name": "Mode",
"type": "option",
"value": ["Chacha20", "Chacha20-Poly1305"]
},
{
"name": "Optional Additional Authentication Data",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Authentication Tag",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const key = Utils.convertToByteArray(args[0].string, args[0].option),
nonce = Utils.convertToByteArray(args[1].string, args[1].option),
inputType = args[2],
outputType = args[3],
mode = args[4],
aad = Utils.convertToByteArray(args[5].string, args[5].option),
tag = Utils.convertToByteArray(args[6].string, args[6].option);
if (key.length !== 32) {
throw new OperationError(`Invalid key length: ${key.length} bytes
Chacha20 requires a key length of 32 bytes`);
}
if (nonce.length !== 8 && nonce.length !== 12) {
throw new OperationError(`Invalid nonce length: ${nonce.length} bytes
Chacha20 requires a nonce length of 8 or 12 bytes`);
}
const useAEAD = mode === "Chacha20-Poly1305";
if (useAEAD && tag.length !== 16) {
throw new OperationError(`Invalid authentication tag length: ${tag.length} bytes
Poly1305 produces a 16 bytes long tag`);
}
input = Utils.convertToByteArray(input, inputType);
let output;
if (useAEAD) {
const aead = new Chacha20Poly1305(key, nonce);
output = aead.open(input, aad, tag);
if (!output) {
throw new OperationError("Authentication failed");
}
} else {
const cipher = new Chacha20(key, nonce);
output = cipher.decrypt(input);
}
if (outputType === "Hex") {
return Buffer.from(output).toString("hex");
} else {
return Buffer.from(output).toString();
}
}
}
export default Chacha20Poly1305Decrypt;