Tidied up SM4 ops and NoPadding options for AES, DES and TripleDES

This commit is contained in:
n1474335 2022-03-29 18:01:57 +01:00
parent 31e9d27f1a
commit 8117926ca3
8 changed files with 26 additions and 15 deletions

View file

@ -83,12 +83,12 @@
"RC2 Decrypt", "RC2 Decrypt",
"RC4", "RC4",
"RC4 Drop", "RC4 Drop",
"SM4 Encrypt",
"SM4 Decrypt",
"ROT13", "ROT13",
"ROT47", "ROT47",
"XOR", "XOR",
"XOR Brute Force", "XOR Brute Force",
"SM4 Encrypt",
"SM4 Decrypt",
"Vigenère Encode", "Vigenère Encode",
"Vigenère Decode", "Vigenère Decode",
"To Morse Code", "To Morse Code",

View file

@ -38,7 +38,8 @@ const Sbox = [
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 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, 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, 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 */ /** "Fixed parameter CK" used in key expansion */
const CK = [ const CK = [
@ -170,7 +171,7 @@ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
if (mode === "ECB" || mode === "CBC") { if (mode === "ECB" || mode === "CBC") {
if (noPadding) { if (noPadding) {
if (nPadding !== 16) 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; nPadding = 0;
} else } else
padByte = nPadding; padByte = nPadding;
@ -255,10 +256,11 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
/* Init decryption key */ /* Init decryption key */
roundKey = roundKey.reverse(); roundKey = roundKey.reverse();
if ((originalLength & 0xF) !== 0 && !ignorePadding) 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)"); 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 */ } else { /* Pad dummy bytes for other modes, chop them off at the end */
while ((cipherText.length & 0xF) !== 0) while ((cipherText.length & 0xF) !== 0)
cipherText.push(0); cipherText.push(0);
}
const clearText = []; const clearText = [];
switch (mode) { switch (mode) {
@ -310,7 +312,7 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
} }
break; break;
default: default:
throw new OperationError("Invalid block cipher mode: "+mode); throw new OperationError(`Invalid block cipher mode: ${mode}`);
} }
/* Check PKCS#7 padding */ /* Check PKCS#7 padding */
if (mode === "ECB" || mode === "CBC") { if (mode === "ECB" || mode === "CBC") {

View file

@ -113,6 +113,7 @@ class AESDecrypt extends Operation {
const key = Utils.convertToByteString(args[0].string, args[0].option), const key = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteString(args[1].string, args[1].option), iv = Utils.convertToByteString(args[1].string, args[1].option),
mode = args[2].substring(0, 3), mode = args[2].substring(0, 3),
noPadding = args[2].endsWith("NoPadding"),
inputType = args[3], inputType = args[3],
outputType = args[4], outputType = args[4],
gcmTag = Utils.convertToByteString(args[5].string, args[5].option), 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); input = Utils.convertToByteString(input, inputType);
const decipher = forge.cipher.createDecipher("AES-" + mode, key); const decipher = forge.cipher.createDecipher("AES-" + mode, key);
/* Allow for a "no padding" mode */ /* Allow for a "no padding" mode */
if (args[2].endsWith("NoPadding")) { if (noPadding) {
decipher.mode.unpad = function(output, options) { decipher.mode.unpad = function(output, options) {
return true; return true;
}; };
} }
decipher.start({ decipher.start({
iv: iv.length === 0 ? "" : iv, iv: iv.length === 0 ? "" : iv,
tag: mode === "GCM" ? gcmTag : undefined, tag: mode === "GCM" ? gcmTag : undefined,

View file

@ -66,6 +66,7 @@ class DESDecrypt extends Operation {
const key = Utils.convertToByteString(args[0].string, args[0].option), const key = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteArray(args[1].string, args[1].option), iv = Utils.convertToByteArray(args[1].string, args[1].option),
mode = args[2].substring(0, 3), mode = args[2].substring(0, 3),
noPadding = args[2].endsWith("NoPadding"),
[,,, inputType, outputType] = args; [,,, inputType, outputType] = args;
if (key.length !== 8) { 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); input = Utils.convertToByteString(input, inputType);
const decipher = forge.cipher.createDecipher("DES-" + mode, key); const decipher = forge.cipher.createDecipher("DES-" + mode, key);
/* Allow for a "no padding" mode */ /* Allow for a "no padding" mode */
if (args[2].endsWith("NoPadding")) { if (noPadding) {
decipher.mode.unpad = function(output, options) { decipher.mode.unpad = function(output, options) {
return true; return true;
}; };
} }
decipher.start({iv: iv}); decipher.start({iv: iv});
decipher.update(forge.util.createBuffer(input)); decipher.update(forge.util.createBuffer(input));
const result = decipher.finish(); const result = decipher.finish();

View file

@ -24,7 +24,7 @@ class SM4Decrypt extends Operation {
this.name = "SM4 Decrypt"; this.name = "SM4 Decrypt";
this.module = "Ciphers"; 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.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.inputType = "string";
this.outputType = "string"; this.outputType = "string";
this.args = [ this.args = [

View file

@ -24,7 +24,7 @@ class SM4Encrypt extends Operation {
this.name = "SM4 Encrypt"; this.name = "SM4 Encrypt";
this.module = "Ciphers"; 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.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.inputType = "string";
this.outputType = "string"; this.outputType = "string";
this.args = [ this.args = [

View file

@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation {
this.name = "Triple DES Decrypt"; this.name = "Triple DES Decrypt";
this.module = "Ciphers"; this.module = "Ciphers";
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> 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.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
this.infoURL = "https://wikipedia.org/wiki/Triple_DES"; this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
this.inputType = "string"; this.inputType = "string";
this.outputType = "string"; this.outputType = "string";
@ -66,6 +66,7 @@ class TripleDESDecrypt extends Operation {
const key = Utils.convertToByteString(args[0].string, args[0].option), const key = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteArray(args[1].string, args[1].option), iv = Utils.convertToByteArray(args[1].string, args[1].option),
mode = args[2].substring(0, 3), mode = args[2].substring(0, 3),
noPadding = args[2].endsWith("NoPadding"),
inputType = args[3], inputType = args[3],
outputType = args[4]; 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); input = Utils.convertToByteString(input, inputType);
const decipher = forge.cipher.createDecipher("3DES-" + mode, key); const decipher = forge.cipher.createDecipher("3DES-" + mode, key);
/* Allow for a "no padding" mode */ /* Allow for a "no padding" mode */
if (args[2].endsWith("NoPadding")) { if (noPadding) {
decipher.mode.unpad = function(output, options) { decipher.mode.unpad = function(output, options) {
return true; return true;
}; };
} }
decipher.start({iv: iv}); decipher.start({iv: iv});
decipher.update(forge.util.createBuffer(input)); decipher.update(forge.util.createBuffer(input));
const result = decipher.finish(); const result = decipher.finish();

View file

@ -119,7 +119,7 @@ TestRegister.addApiTests([
assert.strictEqual(result[0].module, "Ciphers"); assert.strictEqual(result[0].module, "Ciphers");
assert.strictEqual(result[0].inputType, "string"); assert.strictEqual(result[0].inputType, "string");
assert.strictEqual(result[0].outputType, "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.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> 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.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.");
assert.strictEqual(result[0].args.length, 5); assert.strictEqual(result[0].args.length, 5);
}), }),