UNPKG

encryption-for-node

Version:

Portable Crypto libraries for Node and Browsers

530 lines 18.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DES3 = void 0; function isBufferOrUint8Array(obj) { return obj instanceof Uint8Array || (typeof Buffer !== 'undefined' && obj instanceof Buffer); } function isBuffer(obj) { return (typeof Buffer !== 'undefined' && obj instanceof Buffer); } function extendUint8Array(array, newLength, padValue) { const newArray = new Uint8Array(newLength); newArray.set(array); for (let i = array.length; i < newLength; i++) { newArray[i] = padValue; } return newArray; } function concatenateUint8Arrays(arrays) { const totalLength = arrays.reduce((length, array) => length + array.length, 0); const concatenatedArray = new Uint8Array(totalLength); let offset = 0; for (let i = 0; i < arrays.length; i++) { concatenatedArray.set(arrays[i], offset); offset += arrays[i].length; } return concatenatedArray; } function xor(buf1, buf2) { let number = -1; const bufResult = buf1.map((b) => { if (number != buf2.length - 1) { number = number + 1; } else { number = 0; } return b ^ buf2[number]; }); return bufResult; } function align(a, n) { var a = a % n; if (a) { return (n - a); } else { return 0; } } function removePKCSPadding(buffer, number, PKCS = false) { const lastByte = buffer[buffer.length - 1]; if (PKCS == true) { return buffer.subarray(0, buffer.length - lastByte); } else if (lastByte != number) { return buffer; } else { var len = buffer.length; for (let i = buffer.length - 1; i > 0; i--) { if (buffer[i] == number) { len--; } } return buffer.subarray(0, len); } } /** * DES3 encryption. * * Key must be 8 bytes, 8 byte IV * * Example: * ``` * const cipher = new DES3(); * // Key for browser * const encoder_key = new TextEncoder(); * const key = encoder_key.encode("01234567"); * cipher.set_key(key) * // Key for node * const key = Buffer.from("01234567"); * cipher.set_key(key) * // set IV for browser * const encoder_IV = new TextEncoder(); * const IV = encoder_IV.encode("01234567"); * cipher.set_iv(IV) * // set IV for node * const IV = Buffer.from("01234567"); * cipher.set_iv(IV) * // Encrypt for browser * const encoder_text = new TextEncoder(); * const text = encoder_text.encode("test text"); * const text_length = text.length * const ciphertext = cipher.encrypt(text) * // Encrypt for node * const text = Buffer.from("test text"); * const text_length = text.length * const ciphertext = cipher.encrypt(text) * // Decrypt for browser * cipher.set_key(key) * cipher.set_iv(IV) * const ciphertext = new Uint8Array(data.length) * ciphertext.set(data) * const decrypt_text = cipher.decrypt(ciphertext) * const decoded_text = new TextDecoder(); * const string_data = decoded_text.decode(decrypt_text.subarray(0,text_length)); * // Decrypt for Node * cipher.set_key(key) * cipher.set_iv(IV) * const ciphertext = Buffer.from(data); * const decrypt_text = cipher.decrypt(ciphertext) * const final_text = ciphertext.subarray(0,message_len) * const string_data = final_text.toString() * ``` */ class DES3 { constructor() { this.key_set = false; this.iv_set = false; this.ROUNDS = 16; this.KEY_LENGTH = 8; this.sKey = new Uint32Array(32); this.INTERNAL_KEY_LENGTH = this.ROUNDS * 2; this.SKB = new Uint32Array(8 * 64); this.SP_TRANS = new Uint32Array(8 * 64); } s(c) { return (c.charCodeAt == null ? c : c.charCodeAt(0)); } __static_initializer_0() { var cd = "D]PKESYM`UBJ\\@RXA`I[T`HC`LZQ\\PB]TL`[C`JQ@Y`HSXDUIZRAM`EK"; var j; var s; var bit; var count = 0; var offset = 0; for (var i = 0; i < cd.length; i++) { { s = this.s(cd.charAt(i)) - '@'.charCodeAt(0); if (s !== 32) { bit = 1 << count++; for (j = 0; j < 64; j++) { if ((bit & j) !== 0) this.SKB[offset + j] |= 1 << s; ; } if (count === 6) { offset += 64; count = 0; } } } ; } var spt = "g3H821:80:H03BA0@N1290BAA88::3112aIH8:8282@0@AH0:1W3A8P810@22;22A18^@9H9@129:<8@822`?:@0@8PH2H81A19:G1@03403A0B1;:0@1g192:@919AA0A109:W21492H@0051919811:215011139883942N8::3112A2:31981jM118::A101@I88:1aN0<@030128:X;811`920:;H0310D1033@W980:8A4@804A3803o1A2021B2:@1AH023GA:8:@81@@12092B:098042P@:0:A0HA9>1;289:@1804:40Ph=1:H0I0HP0408024bC9P8@I808A;@0@0PnH0::8:19J@818:@iF0398:8A9H0<13@001@11<8;@82B01P0a2989B:0AY0912889bD0A1@B1A0A0AB033O91182440A9P8@I80n@1I03@1J828212A`A8:12B1@19A9@9@8^B:0@H00<82AB030bB840821Q:8310A302102::A1::20A1;8"; offset = 0; var k; var c; var param; for (var i = 0; i < 32; i++) { { k = -1; bit = 1 << i; for (j = 0; j < 32; j++) { { c = this.s(spt.charAt(offset >> 1)) - '0'.charCodeAt(0) >> (offset & 1) * 3 & 7; offset++; if (c < 5) { k += c + 1; this.SP_TRANS[k] |= bit; continue; } param = this.s(spt.charAt(offset >> 1)) - '0'.charCodeAt(0) >> (offset & 1) * 3 & 7; offset++; if (c === 5) { k += param + 6; this.SP_TRANS[k] |= bit; } else if (c === 6) { k += (param << 6) + 1; this.SP_TRANS[k] |= bit; } else { k += param << 6; j--; } } ; } } ; } } ; /** * Key for encryption. * * Key must be 8 bytes! * * @param {Buffer|Uint8Array} key - ```Buffer``` or ```Uint8Array``` */ set_key(key) { if (!isBufferOrUint8Array(key)) { throw Error("key must be Buffer or Uint8Array"); } var userkey = key; if (userkey == null) { throw new Error("Null user key"); } if (userkey.length !== this.KEY_LENGTH) { throw new Error("key must be 8 bytes"); } this.__static_initializer_0(); var i = 0; var c = (userkey[i++] & 255) | (userkey[i++] & 255) << 8 | (userkey[i++] & 255) << 16 | (userkey[i++] & 255) << 24; var d = (userkey[i++] & 255) | (userkey[i++] & 255) << 8 | (userkey[i++] & 255) << 16 | (userkey[i++] & 255) << 24; var t = ((d >>> 4) ^ c) & 252645135; c ^= t; d ^= t << 4; t = ((c << 18) ^ c) & -859045888; c ^= t ^ t >>> 18; t = ((d << 18) ^ d) & -859045888; d ^= t ^ t >>> 18; t = ((d >>> 1) ^ c) & 1431655765; c ^= t; d ^= t << 1; t = ((c >>> 8) ^ d) & 16711935; d ^= t; c ^= t << 8; t = ((d >>> 1) ^ c) & 1431655765; c ^= t; d ^= t << 1; d = (d & 255) << 16 | (d & 65280) | (d & 16711680) >>> 16 | (c & -268435456) >>> 4; c &= 268435455; var s; var j = 0; for (i = 0; i < this.ROUNDS; i++) { { if ((32508 >> i & 1) === 1) { c = (c >>> 2 | c << 26) & 268435455; d = (d >>> 2 | d << 26) & 268435455; } else { c = (c >>> 1 | c << 27) & 268435455; d = (d >>> 1 | d << 27) & 268435455; } s = this.SKB[c & 63] | this.SKB[64 | (((c >>> 6) & 3) | ((c >>> 7) & 60))] | this.SKB[128 | (((c >>> 13) & 15) | ((c >>> 14) & 48))] | this.SKB[192 | (((c >>> 20) & 1) | ((c >>> 21) & 6) | ((c >>> 22) & 56))]; t = this.SKB[256 | (d & 63)] | this.SKB[320 | (((d >>> 7) & 3) | ((d >>> 8) & 60))] | this.SKB[384 | ((d >>> 15) & 63)] | this.SKB[448 | (((d >>> 21) & 15) | ((d >>> 22) & 48))]; this.sKey[j++] = t << 16 | (s & 65535); s = s >>> 16 | (t & -65536); this.sKey[j++] = s << 4 | s >>> 28; } ; } this.key_set = true; } ; /** * IV for CBC encryption. * * Must be 8 bytes! * * @param {Buffer|Uint8Array} iv - ```Buffer``` or ```Uint8Array``` */ set_iv(iv) { if (iv) { if (!isBufferOrUint8Array(iv)) { throw Error("IV must be a buffer or UInt8Array"); } else { if (iv.length != 8) { throw Error("Enter a vaild 8 byte IV for CBC mode"); } else { this.iv = iv; this.iv_set = true; } } } else { throw Error("Enter a vaild 8 byte IV for CBC mode"); } } ; initialPermutation(io) { var L = io[0]; var R = io[1]; var t = ((R >>> 4) ^ L) & 252645135; L ^= t; R ^= t << 4; t = ((L >>> 16) ^ R) & 65535; R ^= t; L ^= t << 16; t = ((R >>> 2) ^ L) & 858993459; L ^= t; R ^= t << 2; t = ((L >>> 8) ^ R) & 16711935; R ^= t; L ^= t << 8; t = ((R >>> 1) ^ L) & 1431655765; io[0] = L ^ t; io[1] = R ^ (t << 1); } ; run_block(block, encrypt) { var __in = block; var out = new Uint8Array(8); var outOffset = 0; var inOffset = 0; var lr = [(__in[inOffset++] & 255) | (__in[inOffset++] & 255) << 8 | (__in[inOffset++] & 255) << 16 | (__in[inOffset++] & 255) << 24, (__in[inOffset++] & 255) | (__in[inOffset++] & 255) << 8 | (__in[inOffset++] & 255) << 16 | (__in[inOffset] & 255) << 24]; this.initialPermutation(lr); if (encrypt) { this.encrypt_base(lr); } else { this.decrypt_base(lr); } this.finalPermutation(lr); var R = lr[0]; var L = lr[1]; out[outOffset++] = (L | 0); out[outOffset++] = ((L >> 8) | 0); out[outOffset++] = ((L >> 16) | 0); out[outOffset++] = ((L >> 24) | 0); out[outOffset++] = (R | 0); out[outOffset++] = ((R >> 8) | 0); out[outOffset++] = ((R >> 16) | 0); out[outOffset] = ((R >> 24) | 0); if (isBuffer(block)) { out = Buffer.from(out); } return out; } ; encrypt_base(io) { var L = io[0]; var R = io[1]; var u = R << 1 | R >>> 31; R = L << 1 | L >>> 31; L = u; var t; for (var i = 0; i < this.INTERNAL_KEY_LENGTH;) { { u = R ^ this.sKey[i++]; t = R ^ this.sKey[i++]; t = t >>> 4 | t << 28; L ^= (this.SP_TRANS[64 | (t & 63)] | this.SP_TRANS[192 | ((t >>> 8) & 63)] | this.SP_TRANS[320 | ((t >>> 16) & 63)] | this.SP_TRANS[448 | ((t >>> 24) & 63)] | this.SP_TRANS[u & 63] | this.SP_TRANS[128 | ((u >>> 8) & 63)] | this.SP_TRANS[256 | ((u >>> 16) & 63)] | this.SP_TRANS[384 | ((u >>> 24) & 63)]); u = L ^ this.sKey[i++]; t = L ^ this.sKey[i++]; t = t >>> 4 | t << 28; R ^= (this.SP_TRANS[64 | (t & 63)] | this.SP_TRANS[192 | ((t >>> 8) & 63)] | this.SP_TRANS[320 | ((t >>> 16) & 63)] | this.SP_TRANS[448 | ((t >>> 24) & 63)] | this.SP_TRANS[u & 63] | this.SP_TRANS[128 | ((u >>> 8) & 63)] | this.SP_TRANS[256 | ((u >>> 16) & 63)] | this.SP_TRANS[384 | ((u >>> 24) & 63)]); } ; } io[0] = R >>> 1 | R << 31; io[1] = L >>> 1 | L << 31; } ; decrypt_base(io) { var L = io[0]; var R = io[1]; var u = R << 1 | R >>> 31; R = L << 1 | L >>> 31; L = u; var t; for (var i = this.INTERNAL_KEY_LENGTH - 1; i > 0;) { { t = R ^ this.sKey[i--]; u = R ^ this.sKey[i--]; t = t >>> 4 | t << 28; L ^= (this.SP_TRANS[64 | (t & 63)] | this.SP_TRANS[192 | ((t >>> 8) & 63)] | this.SP_TRANS[320 | ((t >>> 16) & 63)] | this.SP_TRANS[448 | ((t >>> 24) & 63)] | this.SP_TRANS[u & 63] | this.SP_TRANS[128 | ((u >>> 8) & 63)] | this.SP_TRANS[256 | ((u >>> 16) & 63)] | this.SP_TRANS[384 | ((u >>> 24) & 63)]); t = L ^ this.sKey[i--]; u = L ^ this.sKey[i--]; t = t >>> 4 | t << 28; R ^= (this.SP_TRANS[64 | (t & 63)] | this.SP_TRANS[192 | ((t >>> 8) & 63)] | this.SP_TRANS[320 | ((t >>> 16) & 63)] | this.SP_TRANS[448 | ((t >>> 24) & 63)] | this.SP_TRANS[u & 63] | this.SP_TRANS[128 | ((u >>> 8) & 63)] | this.SP_TRANS[256 | ((u >>> 16) & 63)] | this.SP_TRANS[384 | ((u >>> 24) & 63)]); } ; } io[0] = R >>> 1 | R << 31; io[1] = L >>> 1 | L << 31; } ; finalPermutation(io) { var L = io[1]; var R = io[0]; var t = (R >>> 1 ^ L) & 1431655765; L ^= t; R ^= t << 1; t = (L >>> 8 ^ R) & 16711935; R ^= t; L ^= t << 8; t = (R >>> 2 ^ L) & 858993459; L ^= t; R ^= t << 2; t = (L >>> 16 ^ R) & 65535; R ^= t; L ^= t << 16; t = (R >>> 4 ^ L) & 252645135; io[1] = L ^ t; io[0] = R ^ (t << 4); } ; /** * If IV is not set, runs in ECB mode. * * If IV was set, runs in CBC mode. * * If padding number is not set, uses PKCS padding. * * @param {Buffer|Uint8Array} data_in - ```Buffer``` or ```Uint8Array``` * @param {number} padding - ```number``` defaults to 0 for PKCS or can use a value * @returns ```Buffer``` or ```Uint8Array``` */ encrypt(data_in, padding = 0) { if (!isBufferOrUint8Array(data_in)) { throw Error("Data must be Buffer or Uint8Array"); } const block_size = 8; if (this.key_set != true) { throw Error("Please set key first"); } var data = data_in; var padd_value = padding; const return_buff = []; if (data.length % block_size != 0) { var to_padd = block_size - (data.length % block_size); if (padding == 0) { padd_value = to_padd; } if (isBuffer(data_in)) { var paddbuffer = Buffer.alloc(to_padd, padd_value & 0xff); data = Buffer.concat([data_in, paddbuffer]); } else { data = extendUint8Array(data_in, data.length + to_padd, padd_value); } } for (let index = 0; index < data.length / block_size; index++) { var block = data.subarray((index * block_size), (index + 1) * block_size); if (this.iv_set == true) { block = xor(block, this.iv); } const return_block = this.run_block(block, true); if (this.iv_set == true) { this.iv = return_block; } return_buff.push(return_block); } var final_buffer; if (isBuffer(data_in)) { final_buffer = Buffer.concat(return_buff); } else { final_buffer = concatenateUint8Arrays(return_buff); } this.iv_set = false; return final_buffer; } ; /** * If IV is not set, runs in ECB mode. * * If IV was set, runs in CBC mode. * * If remove_padding is ``number``, will check the last block and remove padded number. * * If remove_padding is ``true``, will remove PKCS padding on last block. * * @param {Buffer|Uint8Array} data_in - ```Buffer``` or ```Uint8Array``` * @param {boolean|number} remove_padding - Will check the last block and remove padded ``number``. Will remove PKCS if ``true`` * @returns ```Buffer``` or ```Uint8Array``` */ decrypt(data_in, remove_padding = false) { if (!isBufferOrUint8Array(data_in)) { throw Error("Data must be Buffer or Uint8Array"); } const block_size = 8; if (this.key_set != true) { throw Error("Please set key first"); } var data = data_in; var padd_value = align(data.length, block_size); if (typeof remove_padding == 'number') { padd_value = remove_padding & 0xFF; } const return_buff = []; if (data.length % block_size != 0) { var to_padd = block_size - (data.length % block_size); if (isBuffer(data_in)) { var paddbuffer = Buffer.alloc(to_padd, padd_value & 0xFF); data = Buffer.concat([data_in, paddbuffer]); } else { data = extendUint8Array(data_in, data.length + to_padd, padd_value); } } for (let index = 0, amount = Math.ceil(data.length / block_size); index < amount; index++) { var block = data.subarray((index * block_size), (index + 1) * block_size); if (this.iv_set == true) { if (this.previous_block != undefined) { this.iv = this.previous_block; } } this.previous_block = block; var return_block = this.run_block(block, false); if (this.iv_set == true) { return_block = xor(return_block, this.iv); } if ((remove_padding != false) && (index == (amount - 1))) { return_block = removePKCSPadding(return_block, padd_value, remove_padding); return_buff.push(return_block); } else { return_buff.push(return_block); } } var final_buffer; if (isBuffer(data_in)) { final_buffer = Buffer.concat(return_buff); } else { final_buffer = concatenateUint8Arrays(return_buff); } this.iv_set = false; return final_buffer; } ; } exports.DES3 = DES3; //# sourceMappingURL=DES3.js.map