Skip to content

Instantly share code, notes, and snippets.

@jordanbtucker
Last active February 16, 2017 06:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jordanbtucker/56c5c3b39101307e0ff026aaea614412 to your computer and use it in GitHub Desktop.
Save jordanbtucker/56c5c3b39101307e0ff026aaea614412 to your computer and use it in GitHub Desktop.
/**
* ThingWorx EncryptionServices.DecryptWithKey.
* @module thingworx-decrypt
* @author Jordan Tucker <jordanbtucker@gmail.com>
*/
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