AES-CTR does not decrypt encrypted bytes
Reported by
julianga...@juliangautier.com,
Apr 15 2016
|
|||||
Issue descriptionChrome Version : 49.0.2623.110 OS Version: OS X 10.11.4 URLs (if applicable) : https://jsbin.com/tevaruwiza/edit?js,output Other browsers tested: Add OK or FAIL after other browsers where you have tested this issue: Safari 5: Firefox 4.x: IE 7/8/9: What steps will reproduce the problem? 1. Run JSBin code. What is the expected result? That I can encrypt chunks of data, and then combine them and decrypt them all at once use AES-CTR. What happens instead of that? Unable to decrypte all chunks ta once. Please provide any additional information below. Attach a screenshot if possible. UserAgentString: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36
,
Apr 15 2016
,
Apr 15 2016
Thanks for looking into this. Just to give you an idea of the use case here is I am capturing data from a microphone and encrypting each chunk using a script processor node and sending that data down web sockets to other users which can play the audio live. At the same time as other users are getting the audio I am also storing the encrypted chunks on the server. Afterwards the clients would like to be able to fetch all of the bytes at once and decrypt it all at once. I can work around this by decrypting the file in chunks but it seems like other platforms support this. Take a look at this code in node:
var crypto = require("crypto");
var cipher = crypto.createCipher("aes-256-ctr", "test");
var decipher = crypto.createDecipher("aes-256-ctr", "test");
var rawString = "hello world";
var encryptedBuffers = [];
for (var i = 0; i < rawString.length; i++) {
encryptedBuffers.push(cipher.update(rawString[i]));
console.log(decipher.update(encryptedBuffers[i]).toString("utf8"));
}
var decipher = crypto.createDecipher("aes-256-ctr", "test");
console.log(decipher.update(Buffer.concat(encryptedBuffers)).toString("utf8"));
See how it can encrypt/decrypt chunks and then also decrypt them combined? Also AES-CTR is suppose to make AES work as a stream cipher: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29 which I thought would enable this functionality, but maybe I am misunderstanding. Additionally I have colleagues who are working on iOS and Android who are using AES-CTR in a similar fashion encrypting/decrypting chunks and then decrypting them combined.
Thoughts?
,
Apr 16 2016
Thank you for providing more feedback. Adding requester "ranjitkan@chromium.org" for another review and adding "Needs-Review" label for tracking. For more details visit https://sites.google.com/a/chromium.org/dev/issue-tracking/autotriage - Your friendly Sheriffbot
,
Apr 18 2016
,
Apr 18 2016
In short, the WebCrypto API does not support this. WebCrypto provides only a one-shot interface for encryption/decryption. You can raise the issue to the WebCrypto Working Group [1], however this was already discussed and rejected. I agree that unfortunately using AES-CTR in WebCrypto is fairly unwieldly (can't stream data to it, and also the incremented counter is not exposed) If you wanted you could in theory layer your own stream interface on top of the existing primitive, by varying the "counter" parameter manually. To do this efficiently (at least with what WebCrypto exposes) you would want to buffer a block worth of data, encrypt it, and then update the counter. There are other hacks you could do to recover the pad and then encipher byte by byte, but the amount of effort isn't worth it (might as well just re-implement AES-CTR outside of WebCrypto at that point). As described your protocol does sound a bit sketchy. Are you varying the counter? Are you providing integrity through some other means? I am afraid I don't have a better answer than that. Sending an email to the W3C WebCrypto working group is probably your best recourse. [1] https://www.w3.org/2012/webcrypto/
,
Apr 18 2016
Thanks for looking into it. At least now I know its a limitation of the API and not something that I was doing incorrectly. |
|||||
►
Sign in to add a comment |
|||||
Comment 1 by dtapu...@chromium.org
, Apr 15 2016aes-ctr is a block cipher. For any given crypt operation you are creating a block. You're encrypt op is creating 11 blocks and you decrypt those 11 blocks but when you pack it all into one it doesn't because the one block isn't the same as 11 blocks combined. I suggest you just pack the data into one block and send it into the crypt routine. Something like: var buf = new ArrayBuffer(22); var bufView = new Uint16Array(buf); for (var i=0; i < 11; ++i) { bufView[i] = rawString.charCodeAt(i); } window.crypto.subtle.encrypt({ "name": "AES-CTR", "counter": new Uint8Array(16), "length": 128 }, aesKey, buf).then(function (encrypted) { \ window.crypto.subtle.decrypt({ "name": "AES-CTR", "counter": new Uint8Array(16), "length": 128 }, aesKey, encrypted).then(function (decrypted) { var decryptedChar = new Uint16Array(decrypted); document.write(String.fromCharCode.apply(null, decryptedChar)); }