PubNub is a HIPAA-compliant instant messaging platform that supports message and file encryption using AES-256-CBC.
The provided encryption is flawed, it drops half of the entropy from the encrpytion key, effectively half of the encrpytion key is constant.
The getKey function does an SHA-256 on the provided key string to make it the required 256bit (32byte) length for the AES-256. Then it's hex encoded, doubling the length in bytes then trimmed to 32 bytes. Due to hex encoding and trimming half of the bits in the key are always the same for every encoded message or file.
https://github.com/pubnub/javascript/blob/master/src/crypto/modules/web.js#L70
async getKey(key) {
const bKey = Buffer.from(key);
const abHash = await crypto.subtle.digest('SHA-256', bKey.buffer);
const abKey = Buffer.from(Buffer.from(abHash).toString('hex').slice(0, 32), 'utf8').buffer;
return crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt']);
}
digest
function generates the same output with each call.half of the encryption key is known
– who knows about the key, attacker? How would they know the key, by probing payload (with altering content and checking provided output with random IV changed all the time)?The generated key can be known by someone from outside, if they will inject code into an existing function.
It is pretty unsafe to hardcode secrets / cipher keys into applications for which source code can be checked with a debugger. Most of the users of PubNub has concept of accounts, so those credentials can be sent only after authorization from the user's server and don't stay in the code.
but half of the encryption key is constant
– even if we used the whole key generated bydigest
, it still will be constant.As for HIPAA compliance it will be better to invite people from PubNub, who worked on HIPAA (if you want) to share more information about compliance.