From 318733d1cbe7ef35fa9c94c67afc14095c7a6d0a Mon Sep 17 00:00:00 2001 From: ramon18 Date: Thu, 18 Aug 2022 09:13:49 +0100 Subject: [PATCH] Added port to node (Node-SmartCrypto) --- Node-SmartCrypto/aes.js | 506 ++++++++++++++++++++++++++++++++ Node-SmartCrypto/keys.js | 7 + Node-SmartCrypto/smartCrypto.js | 374 +++++++++++++++++++++++ README.md | 2 +- 4 files changed, 888 insertions(+), 1 deletion(-) create mode 100644 Node-SmartCrypto/aes.js create mode 100644 Node-SmartCrypto/keys.js create mode 100644 Node-SmartCrypto/smartCrypto.js diff --git a/Node-SmartCrypto/aes.js b/Node-SmartCrypto/aes.js new file mode 100644 index 0000000..af4cebc --- /dev/null +++ b/Node-SmartCrypto/aes.js @@ -0,0 +1,506 @@ +// This code comes from https://github.com/Ape/samsungctl/issues/22#issuecomment-359063253 +// Ported to js by ramon18 + +/** + * @param {Uint8Array} pt + * @param {number} offset + * @return {number} + * @constructor + */ +function GetU32(pt, offset) { + return (((pt)[offset] << 24) ^ ((pt)[1 + offset] << 16) ^ ((pt)[2 + offset] << 8) ^ ((pt)[3 + offset])); +} + +/** + * @param {Uint8Array} ct + * @param {number} offset + * @param {number} st + * @return {number} + * @constructor + */ +function PutU32(ct, offset, st) { + const b0 = ((st) >>> 24); + const b1 = ((st) >>> 16); + const b2 = ((st) >>> 8); + const b3 = ((st)); + + ct[offset] = b0; + ct[offset + 1] = b1; + ct[offset + 2] = b2; + ct[offset + 3] = b3; +} + +/** + * Expand the cipher key into the encryption key schedule. + * @param {number} nr + * @param {Uint32Array} rk + * @param {Uint8Array} cipherKey + * @param {number} keyBits + * @return {number} the number of rounds for the given cipher key size. + */ +function rijndaelKeySetupEncTransform(nr, rk, cipherKey, keyBits) { + let i = 0; + let temp; + + rk[0] = GetU32(cipherKey, 0); + rk[1] = GetU32(cipherKey, 4); + rk[2] = GetU32(cipherKey, 8); + rk[3] = GetU32(cipherKey, 12); + + let offset = 0; + if (keyBits === 128) { + for (;;) { + temp = rk[3 + offset]; + rk[4 + offset] = rk[offset] ^ + (Te4[(temp >>> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >>> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >>> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5 + offset] = rk[1 + offset] ^ rk[4 + offset]; + rk[6 + offset] = rk[2 + offset] ^ rk[5 + offset]; + rk[7 + offset] = rk[3 + offset] ^ rk[6 + offset]; + if (++i === nr) { + return nr; + } + offset += 4; + } + } + return 0; +} + +/** + * @param {Uint32Array} rk + * @param {number} nr + * @param {Uint8Array} pt - Plain text + * @param {Uint8Array} ct - Cipher text + */ +function rijndaelEncrypt(rk, nr, pt, ct) { + // Offset into rk + let off = 0; + + let s0 = GetU32(pt, 0) ^ rk[off]; + let s1 = GetU32(pt, 4) ^ rk[off + 1]; + let s2 = GetU32(pt, 8) ^ rk[off + 2]; + let s3 = GetU32(pt, 12) ^ rk[off + 3]; + + // Round 1 + let t0 = Te0[s0 >>> 24] ^ Te1[(s1 >>> 16) & 0xff] ^ Te2[(s2 >>> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[off + 4]; + let t1 = Te0[s1 >>> 24] ^ Te1[(s2 >>> 16) & 0xff] ^ Te2[(s3 >>> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[off + 5]; + let t2 = Te0[s2 >>> 24] ^ Te1[(s3 >>> 16) & 0xff] ^ Te2[(s0 >>> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[off + 6]; + let t3 = Te0[s3 >>> 24] ^ Te1[(s0 >>> 16) & 0xff] ^ Te2[(s1 >>> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[off + 7]; + + // Round 2 + s0 = Te0[t0 >>> 24] ^ Te1[(t1 >>> 16) & 0xff] ^ Te2[(t2 >>> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[off + 8]; + s1 = Te0[t1 >>> 24] ^ Te1[(t2 >>> 16) & 0xff] ^ Te2[(t3 >>> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[off + 9]; + s2 = Te0[t2 >>> 24] ^ Te1[(t3 >>> 16) & 0xff] ^ Te2[(t0 >>> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[off + 10]; + s3 = Te0[t3 >>> 24] ^ Te1[(t0 >>> 16) & 0xff] ^ Te2[(t1 >>> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[off + 11]; + + // Omitted + // if (nr > 3) { + // ... + // } + + // Omitted + // if (nr > 10) { + // ... + // } + + off += nr << 2; + + // apply last round and + // map cipher state to byte array block: + + // if (nr === 3) + { + t0 = + (Te4[(s0 >>> 24) ] & 0xff000000) ^ + (Te4[(s1 >>> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(s2 >>> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(s3 ) & 0xff] & 0x000000ff) ^ + rk[off]; + PutU32(ct, 0, t0); + t1 = + (Te4[(s1 >>> 24) ] & 0xff000000) ^ + (Te4[(s2 >>> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(s3 >>> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(s0 ) & 0xff] & 0x000000ff) ^ + rk[off+1]; + PutU32(ct, 4, t1); + t2 = + (Te4[(s2 >>> 24) ] & 0xff000000) ^ + (Te4[(s3 >>> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(s0 >>> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(s1 ) & 0xff] & 0x000000ff) ^ + rk[off+2]; + PutU32(ct, 8, t2); + t3 = + (Te4[(s3 >>> 24) ] & 0xff000000) ^ + (Te4[(s0 >>> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(s1 >>> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(s2 ) & 0xff] & 0x000000ff) ^ + rk[off+3]; + PutU32(ct, 12, t3); + } +} + +/** + * @param {number} nr + * @param {Uint8Array} key + * @param {Uint8Array} plainText + * @param {Uint8Array} cipherText + * @return {Uint8Array} + */ +export function AES_128_Transform(nr, key, plainText, cipherText) { + + const aes128rounds = 10; + + const len = 4 * (aes128rounds + 1); + const rk = new Uint32Array(len); + + rijndaelKeySetupEncTransform(nr, rk, key, 128); + rijndaelEncrypt(rk, nr, plainText, cipherText); + + for (let i = 0; i < len; i++) { + rk[i] = 0; + } +} + +// Some pre-calculated tables + +const Te0 = [ + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, + 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, + 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, + 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, + 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, + 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, + 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, + 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, + 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, + 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, + 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, + 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, + 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, + 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, + 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, + 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, + 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, + 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, + 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, + 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, + 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, + 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, + 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, + 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, + 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, + 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, + 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, + 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, + 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, + 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, + 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, + 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, + 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, + 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, + 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, + 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, + 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, + 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, + 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, + 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, + 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, + 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, + 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, + 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, + 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, + 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, + 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, +]; +const Te1 = [ + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, + 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, + 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, + 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, + 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, + 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, + 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, + 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, + 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, + 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, + 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, + 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, + 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, + 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, + 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, + 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, + 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, + 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, + 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, + 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, + 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, + 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, + 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, + 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, + 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, + 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, + 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, + 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, + 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, + 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, + 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, + 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, + 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 +]; +const Te2 = [ + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, + 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, + 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, + 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, + 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, + 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, + 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, + 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, + 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, + 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, + 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, + 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, + 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, + 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, + 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, + 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, + 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, + 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, + 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, + 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, + 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, + 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, + 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, + 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, + 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, + 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, + 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, + 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, + 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, + 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, + 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, + 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, + 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, +]; +const Te3 = [ + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, + 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, + 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, + 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, + 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, + 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, + 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, + 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, + 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, + 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, + 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, + 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, + 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, + 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, + 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, + 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, + 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, + 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, + 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, + 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, + 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, + 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, + 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, + 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, + 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, + 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, + 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, + 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, + 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, + 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, + 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, + 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, + 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, +]; +const Te4 = [ + 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, + 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, + 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, + 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, + 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, + 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, + 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, + 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, + 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, + 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, + 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, + 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515, + 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, + 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, + 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, + 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, + 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, + 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, + 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, + 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, + 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, + 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, + 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, + 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, + 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, + 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, + 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, + 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8, + 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, + 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, + 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, + 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, + 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, + 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, + 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, + 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, + 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, + 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, + 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, + 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, + 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, + 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, + 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, + 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979, + 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, + 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, + 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, + 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, + 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, + 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, + 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, + 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, + 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, + 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, + 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, + 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, + 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, + 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, + 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, + 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf, + 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, + 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, + 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, + 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616, +]; + +const rcon = [ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +]; diff --git a/Node-SmartCrypto/keys.js b/Node-SmartCrypto/keys.js new file mode 100644 index 0000000..7a37f96 --- /dev/null +++ b/Node-SmartCrypto/keys.js @@ -0,0 +1,7 @@ +export const keys = { + publicKey: '2cb12bb2cbf7cec713c0fff7b59ae68a96784ae517f41d259a45d20556177c0ffe951ca60ec03a990c9412619d1bee30adc7773088c5721664cffcedacf6d251cb4b76e2fd7aef09b3ae9f9496ac8d94ed2b262eee37291c8b237e880cc7c021fb1be0881f3d0bffa4234d3b8e6a61530c00473ce169c025f47fcc001d9b8051', + privateKey: '2fd6334713816fae018cdee4656c5033a8d6b00e8eaea07b3624999242e96247112dcd019c4191f4643c3ce1605002b2e506e7f1d1ef8d9b8044e46d37c0d5263216a87cd783aa185490436c4a0cb2c524e15bc1bfeae703bcbc4b74a0540202e8d79cadaae85c6f9c218bc1107d1f5b4b9bd87160e782f4e436eeb17485ab4d', + wbKey: 'abbb120c09e7114243d1fa0102163b27', + prime: 'b361eb0ab01c3439f2c16ffda7b05e3e320701ebee3e249123c3586765fd5bf6c1dfa88bb6bb5da3fde74737cd88b6a26c5ca31d81d18e3515533d08df619317063224cf0943a2f29a5fe60c1c31ddf28334ed76a6478a1122fb24c4a94c8711617ddfe90cf02e643cd82d4748d6d4a7ca2f47d88563aa2baf6482e124acd7dd', + transKey: "6c9474469ddf7578f3e5ad8a4c703d99" +} diff --git a/Node-SmartCrypto/smartCrypto.js b/Node-SmartCrypto/smartCrypto.js new file mode 100644 index 0000000..02de858 --- /dev/null +++ b/Node-SmartCrypto/smartCrypto.js @@ -0,0 +1,374 @@ +import crypto from 'crypto'; +// YOU need to "npm install bn.js" +import BN from 'bn.js'; +import {AES_128_Transform} from "./aes.js"; +import {keys} from "./keys"; + +// Inspirations: +// https://github.com/sectroyer/SmartCrypto/blob/master/SmartCrypto/crypto.c +// https://github.com/McKael/smartcrypto/blob/736f9f22e25502a5d9680001fbb2f4ee9c6a5d8d/smartcrypto.go + +const null_iv = Buffer.from('00000000000000000000000000000000', 'hex'); + +function encryptHex(key, data, mode, iv, padding) { + const keyBytes = typeof key === 'string' ? Buffer.from(key, 'hex') : key; + const dataBytes = typeof data === 'string' ? Buffer.from(data, 'hex') : data; + const cipher = crypto.createCipheriv(mode, keyBytes, iv); + if (padding === false) { + cipher.setAutoPadding(false); + } + cipher.write(dataBytes); + cipher.end(); + return cipher.read(); +} + +export function encryptHexCbc(key, data, padding) { + return encryptHex(key, data, 'aes-128-cbc', null_iv, padding); +} + +export function encryptHexEcb(key, data) { + return encryptHex(key, data, 'aes-128-ecb', null); +} + +function decryptHex(key, data, mode, iv, padding) { + const keyBytes = typeof key === 'string' ? Buffer.from(key, 'hex') : key; + const dataBytes = typeof data === 'string' ? Buffer.from(data, 'hex') : data; + const decipher = crypto.createDecipheriv(mode, keyBytes, iv); + if (padding === false) { + decipher.setAutoPadding(false); + } + decipher.write(dataBytes); + decipher.end(); + return decipher.read(); +} + +export function decryptHexCbc(key, data, padding) { + return decryptHex(key, data, 'aes-128-cbc', null_iv, padding); +} + +export function decryptHexEcb(key, data, padding) { + return decryptHex(key, data, 'aes-128-ecb', null, padding); +} + +function bufferAppendUInt32BE(data, value) { + const temp = Buffer.alloc(4); + temp.writeUInt32BE(value, 0); + return Buffer.concat([data, temp]); +} + +function bufferAppendHex(data, bin) { + const dataBytes = typeof bin === 'string' ? Buffer.from(bin, 'hex') : bin; + return Buffer.concat([data, dataBytes]); +} + +function bufferAppendString(data, str) { + const temp = Buffer.alloc(str.length); + temp.write(str, 0); + return Buffer.concat([data, temp]); +} + +/** + * Calculates the SHA1 digest from an input buffer + * @param buffer {Buffer|Uint8Array} + * @returns {Uint8Array} + */ +export function sha1Digest(buffer) { + const hash = crypto.createHash('sha1'); + hash.write(buffer); + hash.end(); + return hash.digest(); +} + +/** + * Generates a server Hello + * @param {string} userId + * @param {string} pin + * @returns {{ userId: string, hash: string, generator: string, key: string }} + */ +export function generateServerHello(userId, pin) { + if (!userId || userId.length < 1 || userId.length > 96) { + throw new Error(`invalid userID size (${(userId || 0).length})`); + } + + if (!pin || pin.length !== 4) { + throw new Error(`Invalid pin size (${(pin || 0).length})`); + } + + const pinHash = sha1Digest(Buffer.from(pin, 'utf8')); + const key = pinHash.subarray(0, 16); + const encrypted = encryptHexCbc(key, keys.publicKey); + const swapped = encryptHexEcb(keys.wbKey, encrypted).subarray(0, 128); + + let dataBuf = Buffer.alloc(0); + dataBuf = bufferAppendUInt32BE(dataBuf, userId.length); + dataBuf = bufferAppendString(dataBuf, userId); + dataBuf = bufferAppendHex(dataBuf, swapped); + + const hash = bytesToHex(sha1Digest(dataBuf)); + + let serverHelloBuf = Buffer.alloc(0); + serverHelloBuf = bufferAppendHex(serverHelloBuf, '01020000000000'); + serverHelloBuf = bufferAppendUInt32BE(serverHelloBuf, dataBuf.length); + serverHelloBuf = bufferAppendHex(serverHelloBuf, dataBuf); + serverHelloBuf = bufferAppendHex(serverHelloBuf, '0000000000'); + + const expectedLength = 10 + 1 + (4 + userId.length + 128) + 5; + if (serverHelloBuf.length !== expectedLength) { + throw new Error(`Generated invalid server hello`); + } + + const generator = serverHelloBuf.toString('hex').toUpperCase(); + return { + userId, + generator, + hash, + key: bytesToHex(key) + }; +} + +class DataReader { + + /** + * Creates a new reader + * @param {Uint8Array} bytes + */ + constructor(bytes) { + /** + * @type {Buffer} + * @private + */ + this.buffer = bytesToBuffer(bytes); + + /** + * @type {number} + * @private + */ + this.offset = 0; + } + + get length() { + return this.buffer.length; + } + + /** + * @param {number} count + * @return {Uint8Array} + */ + readBytes(count) { + this.ensure(count); + const result = bufferToBytes(this.buffer, this.offset, count); + this.offset += count; + return result; + } + + /** + * Reads a BigEndian number + * @return {number} + */ + readUInt32BE() { + this.ensure(4); + const result = this.buffer.readUInt32BE(this.offset); + this.offset += 4; + return result; + } + + readByte() { + this.ensure(1); + const byte = this.buffer.readUInt8(this.offset); + this.offset++; + return byte; + } + + /** + * Ensure has N available bytes to read + * @private + * @param {number} count + */ + ensure(count) { + const remaining = this.length - this.offset; + if (remaining < count) { + throw new Error('EOS'); + } + } +} + +/** + * Parses a client hello and returns a ctx + * @param data {String} + * @param serverHello {{hash: string, userId: string, key: string}} + * @returns {{skPrime: Uint8Array, ctx: string, skPrimeHash: string}|null} + */ +export function parseClientHelloNew(data, serverHello) { + const gxSize = 0x80; + const reader = new DataReader(hexToBytes(data)); + + if (reader.length < 164) { + console.log("ClientHello string looks too short"); + return null; + } + + const header = reader.readBytes(7); + if (bytesToHex(header) !== '01010000000000') { + console.log("ClientHello has invalid header"); + return null; + } + + const payloadSize = reader.readUInt32BE(); + const length = reader.readUInt32BE(); + if (length + 152 !== payloadSize) { + console.log("ClientHello has invalid client ID lenght"); + return null; + } + + const clientUserId = bytesToStr(reader.readBytes(length)); + if (clientUserId !== serverHello.userId) { + console.log("ClientHello has invalid client ID value"); + return null; + } + + const encWBGx = reader.readBytes(gxSize); + const encGx = decryptHexEcb(keys.wbKey, encWBGx, false); + const gx = decryptHexCbc(serverHello.key, encGx, false); + + const bnGx = new BN(bytesToHex(gx), 16); + const bnPrivate = new BN(keys.privateKey, 16); + const bnPrime = new BN(keys.prime, 16); + const secret = new Uint8Array(bnGx.toRed(BN.red(bnPrime)).redPow(bnPrivate).fromRed().toArray()); + + const clientHash = bytesToHex(reader.readBytes(20)); + const flag1 = reader.readByte(); + if (flag1 !== 0) { + console.log('Client Hello parsing failed: flag #1 is not null'); + return null; + } + + const flag2 = reader.readUInt32BE(); + if (flag2 !== 0) { + console.log('Client Hello parsing failed: flag #2 is not null'); + return null; + } + + const clientIdBytes = strToBytes(serverHello.userId); + const dataX = Buffer.concat([clientIdBytes, secret]); + const calculatedHash = bytesToHex(sha1Digest(dataX)); + if (calculatedHash !== clientHash) { + console.log('Bad PIN'); + return null; + } + + const skPrime = sha1Digest(Buffer.concat([ + clientIdBytes, + clientIdBytes, + gx, + hexToBytes(keys.publicKey), + secret + ])); + + // Append byte 0x00 and hash + const skPrimeHash = sha1Digest(Buffer.concat([skPrime, hexToBytes('00')])); + bytesToHex(skPrimeHash) + + const ctx = new Uint8Array(16); + AES_128_Transform(3, hexToBytes(keys.transKey), skPrimeHash, ctx); + + return { + skPrime, + ctx: bytesToHex(ctx), + skPrimeHash: bytesToHex(skPrimeHash) + } +} + +/** + * Converts a hex string into a buffer + * @param hexString {String} + * @returns {Uint8Array} + */ +export function hexToBytes(hexString) { + return bufferToBytes(Buffer.from(hexString, 'hex')); +} + +/** + * Converts a buffer into a byte array + * @param {Buffer} buffer + * @param {number?} offset + * @param {number?} count + * @return {Uint8Array} + */ +export function bufferToBytes(buffer, offset, count) { + if (typeof offset === 'undefined') { + offset = 0; + } + if (typeof count === 'undefined') { + count = buffer.length; + } + const array = new Uint8Array(count); + for (let i = 0; i < count; i++) { + array[i] = buffer[i + offset]; + } + return array; +} + +/** + * Converts a buffer into a byte array + * @param {Uint8Array} bytes + * @return {Buffer} + */ +export function bytesToBuffer(bytes) { + return Buffer.from(bytes); +} + +/** + * Converts a utf-8 string into a buffer + * @param str {String} + * @returns {Uint8Array} + */ +export function strToBytes(str) { + return bufferToBytes(Buffer.from(str, 'utf8')); +} + +/** + * Converts a buffer into an hex string + * @param bytes {Uint8Array} + * @returns {string} + */ +export function bytesToHex(bytes) { + return bytesToBuffer(bytes).toString('hex'); +} + +/** + * Converts a buffer into an utf-8 string + * @param buffer {Buffer|Uint8Array} + * @returns {string} + */ +export function bytesToStr(buffer) { + if (buffer instanceof Uint8Array) { + buffer = bytesToBuffer(buffer); + } + return buffer.toString('utf8'); +} + +/** + * Generate a server acknowledge + * @param skPrime {Uint8Array} + * @returns {string} + */ +export function generateServerAcknowledge(skPrime) { + const prefix = '0103000000000000000014'; + const hash = bytesToHex(sha1Digest(Buffer.concat([skPrime, hexToBytes('01')]))); + const suffix = '0000000000'; + return `${prefix}${hash}${suffix}`.toUpperCase(); +} + +/** + * Parses a client acknowledge data + * @param clientAck {string} + * @param skPrime {Uint8Array} + * @returns {boolean} + */ +export function parseClientAcknowledge(clientAck, skPrime) { + if (clientAck.length < 72) { + throw new Error("incorrect client acknowledge length"); + } + const expectedClientAckData = bytesToHex(sha1Digest(Buffer.concat([skPrime, hexToBytes('02')]))) + "0000000000"; + return expectedClientAckData === clientAck.substring(22).toLowerCase(); +} diff --git a/README.md b/README.md index d81b097..468a013 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SmartCrypto SmartView2 Handshake API implementation -Samsung Smart TV H/J (2014/2015) models SmartView2 Crypto Handshake C/Python implementation. +Samsung Smart TV H/J (2014/2015) models SmartView2 Crypto Handshake C/Python/Node implementation. The responsibility for the damage caused by the use of that code is on the user him/herself. In particular, Samsung has nothing to do with the code and does not guarantee anything.