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']);
}
Yes, users should not hard code the key, then nothing will save them.
The problem isn't with digest, but the hex encoding and then dropping half of the resulting string. You should use the output of digest directly and please do not hex encode.
After the hex encoding certain bits are fixed no matter what was the input to hex encode. Other bits are more likely to be
0
or1
. Because of this even if the user does a perfect job, gives a proper, securely generated key, stored correctly, PubNub's decode drops half the entropy and now the key is way less secure than it should be.