Encryption and decryption
If safe mode (encryption) is enabled, Group Messaging pushes the encrypted message to your external system. Group Messaging also expects an encrypted response from your external system.
When encryption is enabled, the following two parameters are added to the URL request.
- msg_signature -- The message signature. signature = sha1(sort(token, timestamp, nonce))
- encypted – If this parameter is true, the message is encrypted
Group Messaging uses AES-CBC-256 to encrypt and decrypt messages.
Message encryption and decryption requires the EncodingAESKey, which you can obtain on the Manage Account page, in the Conversational messaging configuration section.
Signature, encryption, and decryption example
The following example is for nodejs.
var crypto = require('crypto');
var PKCS7Encoder = {};
PKCS7Encoder.decode = function (text) {
var pad = text[text.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return text.slice(0, text.length - pad);
};
PKCS7Encoder.encode = function (text) {
var blockSize = 32;
var textLength = text.length;
var amountToPad = blockSize - (textLength % blockSize);
var result = new Buffer(amountToPad);
result.fill(amountToPad);
return Buffer.concat([text, result]);
};
var MessageCrypto = function (token, encodingAESKey, id) {
if (!token || !encodingAESKey || !id) {
throw new Error('please check arguments');
}
this.token = token;
this.id = id;
var AESKey = new Buffer(encodingAESKey + '=', 'base64');
if (AESKey.length !== 32) {
throw new Error('encodingAESKey invalid');
}
this.key = AESKey;
this.iv = AESKey.slice(0, 16);
};
MessageCrypto.prototype.getTimestamp = function() {
return new Date().getTime();
};
MessageCrypto.prototype.getNonce = function() {
return parseInt((Math.random() * 100000000000), 10);
};
MessageCrypto.prototype.getSignature = function(timestamp, nonce, encrypt) {
var shasum = crypto.createHash('sha1');
var arr = [this.token, timestamp, nonce, encrypt];
if (encrypt){
arr.push(encrypt);
}
arr = arr.sort();
shasum.update(arr.join(''));
return shasum.digest('hex');
};
MessageCrypto.prototype.decrypt = function(text) {
var decipher = crypto.createDecipheriv('aes-256-cbc', this.key, this.iv);
decipher.setAutoPadding(false);
var deciphered = Buffer.concat([decipher.update(text, 'base64'), decipher.final()]);
deciphered = PKCS7Encoder.decode(deciphered);
var content = deciphered.slice(16);
var length = content.slice(0, 4).readUInt32BE(0);
return {
message: content.slice(4, length + 4).toString(),
id: content.slice(length + 4).toString()
};
};
MessageCrypto.prototype.encrypt = function (text) {
var randomString = crypto.pseudoRandomBytes(16);
var msg = new Buffer(text);
var msgLength = new Buffer(4);
msgLength.writeUInt32BE(msg.length, 0);
var id = new Buffer(this.id);
var bufMsg = Buffer.concat([randomString, msgLength, msg, id]);
var encoded = PKCS7Encoder.encode(bufMsg);
var cipher = crypto.createCipheriv('aes-256-cbc', this.key, this.iv);
cipher.setAutoPadding(false);
var cipheredMsg = Buffer.concat([cipher.update(encoded), cipher.final()]);
return cipheredMsg.toString('base64');
};
module.exports = MessageCrypto;