Removed CryptoJS from Utils.js. UTF8 conversion is now achieved with the much smaller and actively maintained utf8 library.

This commit is contained in:
n1474335 2017-12-25 23:11:52 +00:00
parent 4e00ac9300
commit 0e7989111f
9 changed files with 151 additions and 123 deletions

5
package-lock.json generated
View File

@ -8663,6 +8663,11 @@
}
}
},
"utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
"integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ=="
},
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",

View File

@ -93,6 +93,7 @@
"sladex-blowfish": "^0.8.1",
"sortablejs": "^1.7.0",
"split.js": "^1.3.5",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
"xmldom": "^0.1.27",
"xpath": "0.0.24",

View File

@ -217,4 +217,28 @@ Dish.prototype.valid = function() {
}
};
/**
* Determines how much space the Dish takes up.
* Numbers in JavaScript are 64-bit floating point, however for the purposes of the Dish,
* we measure how many bytes are taken up when the number is written as a string.
*
* @returns {number}
*/
Dish.prototype.size = function() {
switch (this.type) {
case Dish.BYTE_ARRAY:
case Dish.STRING:
case Dish.HTML:
return this.value.length;
case Dish.NUMBER:
return this.value.toString().length;
case Dish.ARRAY_BUFFER:
return this.value.byteLength;
default:
return -1;
}
};
export default Dish;

View File

@ -1,4 +1,4 @@
import CryptoJS from "crypto-js";
import utf8 from "utf8";
/**
@ -340,6 +340,32 @@ const Utils = {
},
/**
* Coverts data of varying types to a byteArray.
* Accepts hex, Base64, UTF8 and Latin1 strings.
*
* @param {string} str
* @param {string} type - One of "Hex", "Base64", "UTF8" or "Latin1"
* @returns {byteArray}
*
* @example
* // returns []
*/
convertToByteArray: function(str, type) {
switch (type.toLowerCase()) {
case "hex":
return Utils.fromHex(str);
case "base64":
return Utils.fromBase64(str, null, "byteArray");
case "utf8":
return Utils.strToUtf8ByteArray(str);
case "latin1":
default:
return Utils.strToByteArray(str);
}
},
/**
* Converts a string to a byte array.
* Treats the string as UTF-8 if any values are over 255.
@ -381,17 +407,17 @@ const Utils = {
* Utils.strToUtf8ByteArray("你好");
*/
strToUtf8ByteArray: function(str) {
let wordArray = CryptoJS.enc.Utf8.parse(str),
byteArray = Utils.wordArrayToByteArray(wordArray);
const utf8Str = utf8.encode(str);
if (str.length !== wordArray.sigBytes) {
if (str.length !== utf8Str.length) {
if (ENVIRONMENT_IS_WORKER()) {
self.setOption("attemptHighlight", false);
} else if (ENVIRONMENT_IS_WEB()) {
window.app.options.attemptHighlight = false;
}
}
return byteArray;
return Utils.strToByteArray(utf8Str);
},
@ -443,26 +469,21 @@ const Utils = {
* Utils.byteArrayToUtf8([228,189,160,229,165,189]);
*/
byteArrayToUtf8: function(byteArray) {
const str = Utils.byteArrayToChars(byteArray);
try {
// Try to output data as UTF-8 string
const words = [];
for (let i = 0; i < byteArray.length; i++) {
words[i >>> 2] |= byteArray[i] << (24 - (i % 4) * 8);
}
let wordArray = new CryptoJS.lib.WordArray.init(words, byteArray.length),
str = CryptoJS.enc.Utf8.stringify(wordArray);
const utf8Str = utf8.decode(str);
if (str.length !== wordArray.sigBytes) {
if (str.length !== utf8Str.length) {
if (ENVIRONMENT_IS_WORKER()) {
self.setOption("attemptHighlight", false);
} else if (ENVIRONMENT_IS_WEB()) {
window.app.options.attemptHighlight = false;
}
}
return str;
return utf8Str;
} catch (err) {
// If it fails, treat it as ANSI
return Utils.byteArrayToChars(byteArray);
return str;
}
},
@ -490,30 +511,6 @@ const Utils = {
},
/**
* Converts a CryptoJS.lib.WordArray to a byteArray.
*
* @param {CryptoJS.lib.WordArray} wordArray
* @returns {byteArray}
*
* @example
* // returns [84, 101, 115, 116]
* Utils.wordArrayToByteArray(CryptoJS.enc.Hex.parse("54657374"));
*/
wordArrayToByteArray: function(wordArray) {
if (wordArray.sigBytes <= 0) return [];
let words = wordArray.words,
byteArray = [];
for (let i = 0; i < wordArray.sigBytes; i++) {
byteArray.push((words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
}
return byteArray;
},
/**
* Base64's the input byte array using the given alphabet, returning a string.
*
@ -1248,21 +1245,6 @@ const Utils = {
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
},
/**
* A mapping of string formats to their classes in the CryptoJS library.
* @constant
*/
format: {
"Hex": CryptoJS.enc.Hex,
"Base64": CryptoJS.enc.Base64,
"UTF8": CryptoJS.enc.Utf8,
"UTF16": CryptoJS.enc.Utf16,
"UTF16LE": CryptoJS.enc.Utf16LE,
"UTF16BE": CryptoJS.enc.Utf16BE,
"Latin1": CryptoJS.enc.Latin1,
},
};
export default Utils;
@ -1374,31 +1356,3 @@ Array.prototype.equals = function(other) {
String.prototype.count = function(chr) {
return this.split(chr).length - 1;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Library overrides ///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Override for the CryptoJS Hex encoding parser to remove whitespace before attempting to parse
* the hex string.
*
* @param {string} hexStr
* @returns {CryptoJS.lib.WordArray}
*/
CryptoJS.enc.Hex.parse = function (hexStr) {
// Remove whitespace
hexStr = hexStr.replace(/\s/g, "");
// Shortcut
const hexStrLength = hexStr.length;
// Convert
const words = [];
for (let i = 0; i < hexStrLength; i += 2) {
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
}
return new CryptoJS.lib.WordArray.init(words, hexStrLength / 2);
};

View File

@ -37,7 +37,6 @@ import UUID from "../../operations/UUID.js";
*
* Libraries:
* - Utils.js
* - CryptoJS
* - otp
*
* @author n1474335 [n1474335@gmail.com]

View File

@ -67,7 +67,7 @@ const BitwiseOp = {
* @constant
* @default
*/
KEY_FORMAT: ["Hex", "Base64", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1"],
KEY_FORMAT: ["Hex", "Base64", "UTF8", "Latin1"],
/**
* XOR operation.
@ -77,12 +77,10 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runXor: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || ""),
const key = Utils.convertToByteArray(args[0].string || "", args[0].option),
scheme = args[1],
nullPreserving = args[2];
key = Utils.wordArrayToByteArray(key);
return BitwiseOp._bitOp(input, key, BitwiseOp._xor, nullPreserving, scheme);
},
@ -200,8 +198,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runAnd: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
return BitwiseOp._bitOp(input, key, BitwiseOp._and);
},
@ -215,8 +212,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runOr: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
return BitwiseOp._bitOp(input, key, BitwiseOp._or);
},
@ -230,8 +226,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runAdd: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
return BitwiseOp._bitOp(input, key, BitwiseOp._add);
},
@ -245,8 +240,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runSub: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
return BitwiseOp._bitOp(input, key, BitwiseOp._sub);
},

View File

@ -61,9 +61,9 @@ const Cipher = {
* @returns {string}
*/
_enc: function (algo, input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""),
let key = Cipher._format[args[0].option].parse(args[0].string || ""),
iv = Cipher._format[args[1].option].parse(args[1].string || ""),
salt = Cipher._format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]],
padding = CryptoJS.pad[args[4]],
resultOption = args[5].toLowerCase(),
@ -83,12 +83,12 @@ const Cipher = {
let result = "";
if (resultOption === "show all") {
result += "Key: " + encrypted.key.toString(Utils.format[outputFormat]);
result += "\nIV: " + encrypted.iv.toString(Utils.format[outputFormat]);
if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Utils.format[outputFormat]);
result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Utils.format[outputFormat]);
result += "Key: " + encrypted.key.toString(Cipher._format[outputFormat]);
result += "\nIV: " + encrypted.iv.toString(Cipher._format[outputFormat]);
if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Cipher._format[outputFormat]);
result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Cipher._format[outputFormat]);
} else {
result = encrypted[resultOption].toString(Utils.format[outputFormat]);
result = encrypted[resultOption].toString(Cipher._format[outputFormat]);
}
return result;
@ -105,9 +105,9 @@ const Cipher = {
* @returns {string}
*/
_dec: function (algo, input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""),
let key = Cipher._format[args[0].option].parse(args[0].string || ""),
iv = Cipher._format[args[1].option].parse(args[1].string || ""),
salt = Cipher._format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]],
padding = CryptoJS.pad[args[4]],
inputFormat = args[5],
@ -118,7 +118,7 @@ const Cipher = {
return "No input";
}
const ciphertext = Utils.format[inputFormat].parse(input);
const ciphertext = Cipher._format[inputFormat].parse(input);
if (iv.sigBytes === 0) {
// Use passphrase rather than key. Need to convert it to a string.
@ -136,7 +136,7 @@ const Cipher = {
let result;
try {
result = decrypted.toString(Utils.format[outputFormat]);
result = decrypted.toString(Cipher._format[outputFormat]);
} catch (err) {
result = "Decrypt error: " + err.message;
}
@ -260,7 +260,7 @@ const Cipher = {
* @returns {string}
*/
runBlowfishEnc: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
let key = Cipher._format[args[0].option].parse(args[0].string).toString(Cipher._format.Latin1),
mode = args[1],
outputFormat = args[2];
@ -272,7 +272,7 @@ const Cipher = {
}),
enc = CryptoJS.enc.Hex.parse(encHex);
return enc.toString(Utils.format[outputFormat]);
return enc.toString(Cipher._format[outputFormat]);
},
@ -284,13 +284,13 @@ const Cipher = {
* @returns {string}
*/
runBlowfishDec: function (input, args) {
let key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
let key = Cipher._format[args[0].option].parse(args[0].string).toString(Cipher._format.Latin1),
mode = args[1],
inputFormat = args[2];
if (key.length === 0) return "Enter a key";
input = Utils.format[inputFormat].parse(input);
input = Cipher._format[inputFormat].parse(input);
return Blowfish.decrypt(input.toString(CryptoJS.enc.Base64), key, {
outputType: 0, // This actually means inputType. The library is weird.
@ -329,14 +329,14 @@ const Cipher = {
salt = CryptoJS.enc.Hex.parse(args[3] || ""),
inputFormat = args[4],
outputFormat = args[5],
passphrase = Utils.format[inputFormat].parse(input),
passphrase = Cipher._format[inputFormat].parse(input),
key = CryptoJS.PBKDF2(passphrase, salt, {
keySize: keySize,
hasher: CryptoJS.algo[hasher],
iterations: iterations,
});
return key.toString(Utils.format[outputFormat]);
return key.toString(Cipher._format[outputFormat]);
},
@ -354,14 +354,14 @@ const Cipher = {
salt = CryptoJS.enc.Hex.parse(args[3] || ""),
inputFormat = args[4],
outputFormat = args[5],
passphrase = Utils.format[inputFormat].parse(input),
passphrase = Cipher._format[inputFormat].parse(input),
key = CryptoJS.EvpKDF(passphrase, salt, {
keySize: keySize,
hasher: CryptoJS.algo[hasher],
iterations: iterations,
});
return key.toString(Utils.format[outputFormat]);
return key.toString(Cipher._format[outputFormat]);
},
@ -373,11 +373,11 @@ const Cipher = {
* @returns {string}
*/
runRc4: function (input, args) {
let message = Utils.format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string),
let message = Cipher._format[args[1]].parse(input),
passphrase = Cipher._format[args[0].option].parse(args[0].string),
encrypted = CryptoJS.RC4.encrypt(message, passphrase);
return encrypted.ciphertext.toString(Utils.format[args[2]]);
return encrypted.ciphertext.toString(Cipher._format[args[2]]);
},
@ -395,12 +395,12 @@ const Cipher = {
* @returns {string}
*/
runRc4drop: function (input, args) {
let message = Utils.format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string),
let message = Cipher._format[args[1]].parse(input),
passphrase = Cipher._format[args[0].option].parse(args[0].string),
drop = args[3],
encrypted = CryptoJS.RC4Drop.encrypt(message, passphrase, { drop: drop });
return encrypted.ciphertext.toString(Utils.format[args[2]]);
return encrypted.ciphertext.toString(Cipher._format[args[2]]);
},
@ -783,6 +783,23 @@ const Cipher = {
return output;
},
/**
* A mapping of string formats to their classes in the CryptoJS library.
*
* @private
* @constant
*/
_format: {
"Hex": CryptoJS.enc.Hex,
"Base64": CryptoJS.enc.Base64,
"UTF8": CryptoJS.enc.Utf8,
"UTF16": CryptoJS.enc.Utf16,
"UTF16LE": CryptoJS.enc.Utf16LE,
"UTF16BE": CryptoJS.enc.Utf16BE,
"Latin1": CryptoJS.enc.Latin1,
},
};
export default Cipher;
@ -827,3 +844,27 @@ CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
// Return params
return CryptoJS.lib.CipherParams.create({ key: key, iv: iv, salt: salt });
};
/**
* Override for the CryptoJS Hex encoding parser to remove whitespace before attempting to parse
* the hex string.
*
* @param {string} hexStr
* @returns {CryptoJS.lib.WordArray}
*/
CryptoJS.enc.Hex.parse = function (hexStr) {
// Remove whitespace
hexStr = hexStr.replace(/\s/g, "");
// Shortcut
const hexStrLength = hexStr.length;
// Convert
const words = [];
for (let i = 0; i < hexStrLength; i += 2) {
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
}
return new CryptoJS.lib.WordArray.init(words, hexStrLength / 2);
};

View File

@ -402,7 +402,7 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
// Check if there is a carriage return in the output dish as this will not
// be displayed by the HTML textarea and will mess up highlighting offsets.
if (!this.app.dishStr || this.app.dishStr.indexOf("\r") >= 0) return false;
if (this.manager.output.containsCR()) return false;
const startPlaceholder = "[startHighlight]";
const startPlaceholderRegex = /\[startHighlight\]/g;

View File

@ -282,4 +282,14 @@ OutputWaiter.prototype.setStatusMsg = function(msg) {
el.textContent = msg;
};
/**
* Returns true if the output contains carriage returns
*
* @returns {boolean}
*/
OutputWaiter.prototype.containsCR = function() {
return this.app.dishStr.indexOf("\r") >= 0;
};
export default OutputWaiter;