Last active
February 16, 2017 06:27
-
-
Save jordanbtucker/56c5c3b39101307e0ff026aaea614412 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ThingWorx EncryptionServices.DecryptWithKey. | |
* @module thingworx-decrypt | |
* @author Jordan Tucker <[email protected]> | |
*/ | |
var crypto = require('crypto') | |
/** | |
* Decrypts data encrypted using ThingWorx's EncryptionServices.EncryptWithKey | |
* service. | |
* @param {string} key - A 56 hex digit string containing the encryption key | |
* and IV. | |
* @param {string} ciphertext - The Base64 encoded ciphertext returned by | |
* EncryptWithKey. | |
* @returns {string} The decrypted data. | |
*/ | |
function decrypt(key, ciphertext) { | |
// The key material is derived by Base64 encoding the given 56 hex digit | |
// key. Note that this is the UTF-8 representation of the key, not the | |
// binary representation, because reasons. This also means the key is | |
// case-sensitive. | |
var keyMaterial = Buffer.from(key).toString('base64') | |
// This will always result in a 76 byte string, but ThingWorx only uses the | |
// first and last 16 bytes, and so only 40% of the key is actually used. | |
// The first 16 bytes are used for the IV and the last 16 bytes are used | |
// for the content encryption key. Since 16 bytes of Base64 encoded data | |
// only represents 12 bytes of original data, and each of the 12 bytes can | |
// only represent 22 unique values [0-9A-Fa-f], the resulting IV has a | |
// strength of only ~53.5 bits instead of 128. | |
var iv = Buffer.from(keyMaterial.substr(0, 16)) | |
// Since the Base64 encoded key material always ends with a '=', the last | |
// byte is always the same, and the resulting CEK only has a strength of | |
// ~49 bits instead of 128. | |
var cek = Buffer.from(keyMaterial.substr(keyMaterial.length - 16, 16)) | |
// The rest is straight forward. Decrypt the data using AES-128-CBC with | |
// PKCS#7 padding, and return the result as a UTF-8 encoded string. | |
var ciphertextBuf = Buffer.from(ciphertext, 'base64') | |
var decipher = crypto.createDecipheriv('aes-128-cbc', cek, iv) | |
decipher.setAutoPadding(true) | |
var plaintextBuf1 = decipher.update(ciphertextBuf) | |
var plaintextBuf2 = decipher.final() | |
var plaintextBuf = Buffer.concat([plaintextBuf1, plaintextBuf2]) | |
var plaintext = plaintextBuf.toString('utf8') | |
return plaintext | |
} | |
module.exports = decrypt | |
// Uncomment the following lines to test. The result should be 'Hello, World!' twice. | |
// console.log(decrypt('12345678901234567890123456789012345678901234567890123456', 'Yr/N7G+REPDWrp6DWc67/g==')) | |
// console.log(decrypt('12345678901200000000000000000000000000000000067890123456', 'Yr/N7G+REPDWrp6DWc67/g==')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment