From 8117926ca3cec9f0661966f01d614d808df9cc5f Mon Sep 17 00:00:00 2001 From: n1474335 Date: Tue, 29 Mar 2022 18:01:57 +0100 Subject: [PATCH] Tidied up SM4 ops and NoPadding options for AES, DES and TripleDES --- src/core/config/Categories.json | 4 ++-- src/core/lib/SM4.mjs | 12 +++++++----- src/core/operations/AESDecrypt.mjs | 5 ++++- src/core/operations/DESDecrypt.mjs | 7 +++++-- src/core/operations/SM4Decrypt.mjs | 2 +- src/core/operations/SM4Encrypt.mjs | 2 +- src/core/operations/TripleDESDecrypt.mjs | 7 +++++-- tests/node/tests/nodeApi.mjs | 2 +- 8 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 77ab364d..9540f8a3 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -83,12 +83,12 @@ "RC2 Decrypt", "RC4", "RC4 Drop", + "SM4 Encrypt", + "SM4 Decrypt", "ROT13", "ROT47", "XOR", "XOR Brute Force", - "SM4 Encrypt", - "SM4 Decrypt", "Vigenère Encode", "Vigenère Decode", "To Morse Code", diff --git a/src/core/lib/SM4.mjs b/src/core/lib/SM4.mjs index 36648348..5f5846a2 100644 --- a/src/core/lib/SM4.mjs +++ b/src/core/lib/SM4.mjs @@ -38,7 +38,8 @@ const Sbox = [ 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, - 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48]; + 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 +]; /** "Fixed parameter CK" used in key expansion */ const CK = [ @@ -170,7 +171,7 @@ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) { if (mode === "ECB" || mode === "CBC") { if (noPadding) { if (nPadding !== 16) - throw new OperationError("No padding requested in "+mode+" mode but input is not a 16-byte multiple."); + throw new OperationError(`No padding requested in ${mode} mode but input is not a 16-byte multiple.`); nPadding = 0; } else padByte = nPadding; @@ -255,10 +256,11 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) /* Init decryption key */ roundKey = roundKey.reverse(); if ((originalLength & 0xF) !== 0 && !ignorePadding) - throw new OperationError("With ECB or CBC modes, the input must be divisible into 16 byte blocks. ("+(cipherText.length & 0xF)+" bytes extra)"); - } else /* Pad dummy bytes for other modes, chop them off at the end */ + throw new OperationError(`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra)`); + } else { /* Pad dummy bytes for other modes, chop them off at the end */ while ((cipherText.length & 0xF) !== 0) cipherText.push(0); + } const clearText = []; switch (mode) { @@ -310,7 +312,7 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) } break; default: - throw new OperationError("Invalid block cipher mode: "+mode); + throw new OperationError(`Invalid block cipher mode: ${mode}`); } /* Check PKCS#7 padding */ if (mode === "ECB" || mode === "CBC") { diff --git a/src/core/operations/AESDecrypt.mjs b/src/core/operations/AESDecrypt.mjs index b45fb6d1..e24a5119 100644 --- a/src/core/operations/AESDecrypt.mjs +++ b/src/core/operations/AESDecrypt.mjs @@ -113,6 +113,7 @@ class AESDecrypt extends Operation { const key = Utils.convertToByteString(args[0].string, args[0].option), iv = Utils.convertToByteString(args[1].string, args[1].option), mode = args[2].substring(0, 3), + noPadding = args[2].endsWith("NoPadding"), inputType = args[3], outputType = args[4], gcmTag = Utils.convertToByteString(args[5].string, args[5].option), @@ -130,12 +131,14 @@ The following algorithms will be used based on the size of the key: input = Utils.convertToByteString(input, inputType); const decipher = forge.cipher.createDecipher("AES-" + mode, key); + /* Allow for a "no padding" mode */ - if (args[2].endsWith("NoPadding")) { + if (noPadding) { decipher.mode.unpad = function(output, options) { return true; }; } + decipher.start({ iv: iv.length === 0 ? "" : iv, tag: mode === "GCM" ? gcmTag : undefined, diff --git a/src/core/operations/DESDecrypt.mjs b/src/core/operations/DESDecrypt.mjs index 13ae7482..856aa065 100644 --- a/src/core/operations/DESDecrypt.mjs +++ b/src/core/operations/DESDecrypt.mjs @@ -66,6 +66,7 @@ class DESDecrypt extends Operation { const key = Utils.convertToByteString(args[0].string, args[0].option), iv = Utils.convertToByteArray(args[1].string, args[1].option), mode = args[2].substring(0, 3), + noPadding = args[2].endsWith("NoPadding"), [,,, inputType, outputType] = args; if (key.length !== 8) { @@ -84,12 +85,14 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`); input = Utils.convertToByteString(input, inputType); const decipher = forge.cipher.createDecipher("DES-" + mode, key); - /* Allow for a "no padding" mode */ - if (args[2].endsWith("NoPadding")) { + + /* Allow for a "no padding" mode */ + if (noPadding) { decipher.mode.unpad = function(output, options) { return true; }; } + decipher.start({iv: iv}); decipher.update(forge.util.createBuffer(input)); const result = decipher.finish(); diff --git a/src/core/operations/SM4Decrypt.mjs b/src/core/operations/SM4Decrypt.mjs index 7ee3e689..a0853021 100644 --- a/src/core/operations/SM4Decrypt.mjs +++ b/src/core/operations/SM4Decrypt.mjs @@ -24,7 +24,7 @@ class SM4Decrypt extends Operation { this.name = "SM4 Decrypt"; this.module = "Ciphers"; this.description = "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China."; - this.infoURL = "https://en.wikipedia.org/wiki/SM4_(cipher)"; + this.infoURL = "https://wikipedia.org/wiki/SM4_(cipher)"; this.inputType = "string"; this.outputType = "string"; this.args = [ diff --git a/src/core/operations/SM4Encrypt.mjs b/src/core/operations/SM4Encrypt.mjs index 220898a4..0a58dfb9 100644 --- a/src/core/operations/SM4Encrypt.mjs +++ b/src/core/operations/SM4Encrypt.mjs @@ -24,7 +24,7 @@ class SM4Encrypt extends Operation { this.name = "SM4 Encrypt"; this.module = "Ciphers"; this.description = "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China. Multiple block cipher modes are supported. When using CBC or ECB mode, the PKCS#7 padding scheme is used."; - this.infoURL = "https://en.wikipedia.org/wiki/SM4_(cipher)"; + this.infoURL = "https://wikipedia.org/wiki/SM4_(cipher)"; this.inputType = "string"; this.outputType = "string"; this.args = [ diff --git a/src/core/operations/TripleDESDecrypt.mjs b/src/core/operations/TripleDESDecrypt.mjs index b11c2b7f..7626eeab 100644 --- a/src/core/operations/TripleDESDecrypt.mjs +++ b/src/core/operations/TripleDESDecrypt.mjs @@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation { this.name = "Triple DES Decrypt"; this.module = "Ciphers"; - this.description = "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

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

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; + this.description = "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

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

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."; this.infoURL = "https://wikipedia.org/wiki/Triple_DES"; this.inputType = "string"; this.outputType = "string"; @@ -66,6 +66,7 @@ class TripleDESDecrypt extends Operation { const key = Utils.convertToByteString(args[0].string, args[0].option), iv = Utils.convertToByteArray(args[1].string, args[1].option), mode = args[2].substring(0, 3), + noPadding = args[2].endsWith("NoPadding"), inputType = args[3], outputType = args[4]; @@ -85,12 +86,14 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`); input = Utils.convertToByteString(input, inputType); const decipher = forge.cipher.createDecipher("3DES-" + mode, key); + /* Allow for a "no padding" mode */ - if (args[2].endsWith("NoPadding")) { + if (noPadding) { decipher.mode.unpad = function(output, options) { return true; }; } + decipher.start({iv: iv}); decipher.update(forge.util.createBuffer(input)); const result = decipher.finish(); diff --git a/tests/node/tests/nodeApi.mjs b/tests/node/tests/nodeApi.mjs index 52f79330..0d4a04a4 100644 --- a/tests/node/tests/nodeApi.mjs +++ b/tests/node/tests/nodeApi.mjs @@ -119,7 +119,7 @@ TestRegister.addApiTests([ assert.strictEqual(result[0].module, "Ciphers"); assert.strictEqual(result[0].inputType, "string"); assert.strictEqual(result[0].outputType, "string"); - assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

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

Padding: In CBC and ECB mode, PKCS#7 padding will be used."); + assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

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

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."); assert.strictEqual(result[0].args.length, 5); }),