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": { "util": {
"version": "0.10.3", "version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",

View File

@ -93,6 +93,7 @@
"sladex-blowfish": "^0.8.1", "sladex-blowfish": "^0.8.1",
"sortablejs": "^1.7.0", "sortablejs": "^1.7.0",
"split.js": "^1.3.5", "split.js": "^1.3.5",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3", "vkbeautify": "^0.99.3",
"xmldom": "^0.1.27", "xmldom": "^0.1.27",
"xpath": "0.0.24", "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; 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. * Converts a string to a byte array.
* Treats the string as UTF-8 if any values are over 255. * Treats the string as UTF-8 if any values are over 255.
@ -381,17 +407,17 @@ const Utils = {
* Utils.strToUtf8ByteArray("你好"); * Utils.strToUtf8ByteArray("你好");
*/ */
strToUtf8ByteArray: function(str) { strToUtf8ByteArray: function(str) {
let wordArray = CryptoJS.enc.Utf8.parse(str), const utf8Str = utf8.encode(str);
byteArray = Utils.wordArrayToByteArray(wordArray);
if (str.length !== wordArray.sigBytes) { if (str.length !== utf8Str.length) {
if (ENVIRONMENT_IS_WORKER()) { if (ENVIRONMENT_IS_WORKER()) {
self.setOption("attemptHighlight", false); self.setOption("attemptHighlight", false);
} else if (ENVIRONMENT_IS_WEB()) { } else if (ENVIRONMENT_IS_WEB()) {
window.app.options.attemptHighlight = false; 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]); * Utils.byteArrayToUtf8([228,189,160,229,165,189]);
*/ */
byteArrayToUtf8: function(byteArray) { byteArrayToUtf8: function(byteArray) {
const str = Utils.byteArrayToChars(byteArray);
try { try {
// Try to output data as UTF-8 string const utf8Str = utf8.decode(str);
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);
if (str.length !== wordArray.sigBytes) { if (str.length !== utf8Str.length) {
if (ENVIRONMENT_IS_WORKER()) { if (ENVIRONMENT_IS_WORKER()) {
self.setOption("attemptHighlight", false); self.setOption("attemptHighlight", false);
} else if (ENVIRONMENT_IS_WEB()) { } else if (ENVIRONMENT_IS_WEB()) {
window.app.options.attemptHighlight = false; window.app.options.attemptHighlight = false;
} }
} }
return str; return utf8Str;
} catch (err) { } catch (err) {
// If it fails, treat it as ANSI // 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. * 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 "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; export default Utils;
@ -1374,31 +1356,3 @@ Array.prototype.equals = function(other) {
String.prototype.count = function(chr) { String.prototype.count = function(chr) {
return this.split(chr).length - 1; 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: * Libraries:
* - Utils.js * - Utils.js
* - CryptoJS
* - otp * - otp
* *
* @author n1474335 [n1474335@gmail.com] * @author n1474335 [n1474335@gmail.com]

View File

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

View File

@ -61,9 +61,9 @@ const Cipher = {
* @returns {string} * @returns {string}
*/ */
_enc: function (algo, input, args) { _enc: function (algo, input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || ""), let key = Cipher._format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""), iv = Cipher._format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""), salt = Cipher._format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]], mode = CryptoJS.mode[args[3]],
padding = CryptoJS.pad[args[4]], padding = CryptoJS.pad[args[4]],
resultOption = args[5].toLowerCase(), resultOption = args[5].toLowerCase(),
@ -83,12 +83,12 @@ const Cipher = {
let result = ""; let result = "";
if (resultOption === "show all") { if (resultOption === "show all") {
result += "Key: " + encrypted.key.toString(Utils.format[outputFormat]); result += "Key: " + encrypted.key.toString(Cipher._format[outputFormat]);
result += "\nIV: " + encrypted.iv.toString(Utils.format[outputFormat]); result += "\nIV: " + encrypted.iv.toString(Cipher._format[outputFormat]);
if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Utils.format[outputFormat]); if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Cipher._format[outputFormat]);
result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Utils.format[outputFormat]); result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Cipher._format[outputFormat]);
} else { } else {
result = encrypted[resultOption].toString(Utils.format[outputFormat]); result = encrypted[resultOption].toString(Cipher._format[outputFormat]);
} }
return result; return result;
@ -105,9 +105,9 @@ const Cipher = {
* @returns {string} * @returns {string}
*/ */
_dec: function (algo, input, args) { _dec: function (algo, input, args) {
let key = Utils.format[args[0].option].parse(args[0].string || ""), let key = Cipher._format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""), iv = Cipher._format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""), salt = Cipher._format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]], mode = CryptoJS.mode[args[3]],
padding = CryptoJS.pad[args[4]], padding = CryptoJS.pad[args[4]],
inputFormat = args[5], inputFormat = args[5],
@ -118,7 +118,7 @@ const Cipher = {
return "No input"; return "No input";
} }
const ciphertext = Utils.format[inputFormat].parse(input); const ciphertext = Cipher._format[inputFormat].parse(input);
if (iv.sigBytes === 0) { if (iv.sigBytes === 0) {
// Use passphrase rather than key. Need to convert it to a string. // Use passphrase rather than key. Need to convert it to a string.
@ -136,7 +136,7 @@ const Cipher = {
let result; let result;
try { try {
result = decrypted.toString(Utils.format[outputFormat]); result = decrypted.toString(Cipher._format[outputFormat]);
} catch (err) { } catch (err) {
result = "Decrypt error: " + err.message; result = "Decrypt error: " + err.message;
} }
@ -260,7 +260,7 @@ const Cipher = {
* @returns {string} * @returns {string}
*/ */
runBlowfishEnc: function (input, args) { 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], mode = args[1],
outputFormat = args[2]; outputFormat = args[2];
@ -272,7 +272,7 @@ const Cipher = {
}), }),
enc = CryptoJS.enc.Hex.parse(encHex); 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} * @returns {string}
*/ */
runBlowfishDec: function (input, args) { 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], mode = args[1],
inputFormat = args[2]; inputFormat = args[2];
if (key.length === 0) return "Enter a key"; 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, { return Blowfish.decrypt(input.toString(CryptoJS.enc.Base64), key, {
outputType: 0, // This actually means inputType. The library is weird. outputType: 0, // This actually means inputType. The library is weird.
@ -329,14 +329,14 @@ const Cipher = {
salt = CryptoJS.enc.Hex.parse(args[3] || ""), salt = CryptoJS.enc.Hex.parse(args[3] || ""),
inputFormat = args[4], inputFormat = args[4],
outputFormat = args[5], outputFormat = args[5],
passphrase = Utils.format[inputFormat].parse(input), passphrase = Cipher._format[inputFormat].parse(input),
key = CryptoJS.PBKDF2(passphrase, salt, { key = CryptoJS.PBKDF2(passphrase, salt, {
keySize: keySize, keySize: keySize,
hasher: CryptoJS.algo[hasher], hasher: CryptoJS.algo[hasher],
iterations: iterations, 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] || ""), salt = CryptoJS.enc.Hex.parse(args[3] || ""),
inputFormat = args[4], inputFormat = args[4],
outputFormat = args[5], outputFormat = args[5],
passphrase = Utils.format[inputFormat].parse(input), passphrase = Cipher._format[inputFormat].parse(input),
key = CryptoJS.EvpKDF(passphrase, salt, { key = CryptoJS.EvpKDF(passphrase, salt, {
keySize: keySize, keySize: keySize,
hasher: CryptoJS.algo[hasher], hasher: CryptoJS.algo[hasher],
iterations: iterations, iterations: iterations,
}); });
return key.toString(Utils.format[outputFormat]); return key.toString(Cipher._format[outputFormat]);
}, },
@ -373,11 +373,11 @@ const Cipher = {
* @returns {string} * @returns {string}
*/ */
runRc4: function (input, args) { runRc4: function (input, args) {
let message = Utils.format[args[1]].parse(input), let message = Cipher._format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string), passphrase = Cipher._format[args[0].option].parse(args[0].string),
encrypted = CryptoJS.RC4.encrypt(message, passphrase); 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} * @returns {string}
*/ */
runRc4drop: function (input, args) { runRc4drop: function (input, args) {
let message = Utils.format[args[1]].parse(input), let message = Cipher._format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string), passphrase = Cipher._format[args[0].option].parse(args[0].string),
drop = args[3], drop = args[3],
encrypted = CryptoJS.RC4Drop.encrypt(message, passphrase, { drop: drop }); 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; 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; export default Cipher;
@ -827,3 +844,27 @@ CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
// Return params // Return params
return CryptoJS.lib.CipherParams.create({ key: key, iv: iv, salt: salt }); 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 // 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. // 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 startPlaceholder = "[startHighlight]";
const startPlaceholderRegex = /\[startHighlight\]/g; const startPlaceholderRegex = /\[startHighlight\]/g;

View File

@ -282,4 +282,14 @@ OutputWaiter.prototype.setStatusMsg = function(msg) {
el.textContent = 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; export default OutputWaiter;