diff --git a/src/core/operations/AESDecrypt.mjs b/src/core/operations/AESDecrypt.mjs new file mode 100644 index 00000000..01415ddc --- /dev/null +++ b/src/core/operations/AESDecrypt.mjs @@ -0,0 +1,105 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + +/** + * AES Decrypt operation + */ +class AESDecrypt extends Operation { + + /** + * AESDecrypt constructor + */ + constructor() { + super(); + + this.name = "AES Decrypt"; + this.module = "Ciphers"; + this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.

Key: The following algorithms will be used based on the size of the key:

IV: The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used.

GCM Tag: This field is ignored unless 'GCM' mode is used."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Mode", + "type": "option", + "value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"] + }, + { + "name": "Input", + "type": "option", + "value": ["Hex", "Raw"] + }, + { + "name": "Output", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "GCM 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), + iv = Utils.convertToByteArray(args[1].string, args[1].option), + mode = args[2], + inputType = args[3], + outputType = args[4], + gcmTag = Utils.convertToByteString(args[5].string, args[5].option); + + if ([16, 24, 32].indexOf(key.length) < 0) { + return `Invalid key length: ${key.length} bytes + +The following algorithms will be used based on the size of the key: + 16 bytes = AES-128 + 24 bytes = AES-192 + 32 bytes = AES-256`; + } + + input = Utils.convertToByteString(input, inputType); + + const decipher = forge.cipher.createDecipher("AES-" + mode, key); + decipher.start({ + iv: iv, + tag: gcmTag + }); + decipher.update(forge.util.createBuffer(input)); + const result = decipher.finish(); + + if (result) { + return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes(); + } else { + return "Unable to decrypt input with these parameters."; + } + } + +} + +export default AESDecrypt; diff --git a/src/core/operations/AESEncrypt.mjs b/src/core/operations/AESEncrypt.mjs new file mode 100644 index 00000000..62763c5f --- /dev/null +++ b/src/core/operations/AESEncrypt.mjs @@ -0,0 +1,103 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + +/** + * AES Encrypt operation + */ +class AESEncrypt extends Operation { + + /** + * AESEncrypt constructor + */ + constructor() { + super(); + + this.name = "AES Encrypt"; + this.module = "Ciphers"; + this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.

Key: The following algorithms will be used based on the size of the key:You can generate a password-based key using one of the KDF operations.

IV: The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Mode", + "type": "option", + "value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"] + }, + { + "name": "Input", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "Output", + "type": "option", + "value": ["Hex", "Raw"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteArray(args[0].string, args[0].option), + iv = Utils.convertToByteArray(args[1].string, args[1].option), + mode = args[2], + inputType = args[3], + outputType = args[4]; + + if ([16, 24, 32].indexOf(key.length) < 0) { + return `Invalid key length: ${key.length} bytes + +The following algorithms will be used based on the size of the key: + 16 bytes = AES-128 + 24 bytes = AES-192 + 32 bytes = AES-256`; + } + + input = Utils.convertToByteString(input, inputType); + + const cipher = forge.cipher.createCipher("AES-" + mode, key); + cipher.start({iv: iv}); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(); + + if (outputType === "Hex") { + if (mode === "GCM") { + return cipher.output.toHex() + "\n\n" + + "Tag: " + cipher.mode.tag.toHex(); + } + return cipher.output.toHex(); + } else { + if (mode === "GCM") { + return cipher.output.getBytes() + "\n\n" + + "Tag: " + cipher.mode.tag.getBytes(); + } + return cipher.output.getBytes(); + } + } + +} + +export default AESEncrypt; diff --git a/webpack.config.js b/webpack.config.js index 3f88cc78..822c8561 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -69,6 +69,10 @@ module.exports = { exclude: /node_modules\/(?!jsesc)/, loader: "babel-loader?compact=false" }, + { + test: /forge.min.js$/, + loader: "imports-loader?jQuery=>null" + }, { test: /\.css$/, use: ExtractTextPlugin.extract({