AES-CTR - progressive ciphering does not work
Opened this issue · 6 comments
GoogleCodeExporter commented
The result is OK if you use CryptoJS.AES.encrypt
({mode:CryptoJS.mode.CTR,iv:iv}) but is not correct if you use
CryptoJS.algo.AES.createEncryptor with the same parameters.
The test case is :
K='546c9ee039c8acf804405bf02970ee8b';
IV='00000000000000000000000000000000';
text='2800000000e0ba377e00267777772e66343131366133306335386661336664303639363232
39366363313431362e636f6d00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000'
This should return :
9796e768cbae5b839e55e7310fed0e31e60d4252f8633884d2aa82bb829562e66dbcbf1783fafd37
cae510d962e0c4b1ee77f4dca2ac7327397ce442631beb2596d4ecb5d703842dec2ff65c4014defe
9c69f16628ddb490a123c602d69b9f2044702f36b8778da3def0c20cef91a7049e5e1ca679c69bd8
6966876801a6bfae21d4546d6b6a3c59b851b58a5d75baf7a7a5d8e0216c50c32469df6d23b9fafe
ffe9f8d1a733657cbd9984dd49155f0eac6d026401d9aca767ee25d46a9a402c4971f7849bf2a4e7
04f87b343154b586dde70317abe06641e43ebbbac31b139ba4adab43da017add9ed6a5bf73aaf06c
efd92989553e7672403afc430b158fd1b1f0496c6c3c04cbd6fe333bdd5d4a905efe9eaf42411519
f24889beb32c4c084da1efa4461b5c0f2e65ff3a4557e39899079ed28a9c15d16d7611a16874cc03
3a1d0403de0e61d7c4d99f43656f42e303b612c75ce29f63063c96da3bbd48408c06dda385c01e3a
fa40e44c1e3e0030fec8a619b41568e7b742a3c7ea8d53496b1b3e5052c462b9e620c54d59ae96ab
52257a49deaa3f2fc968401afeec038afd4b309a8a124df3627db5612fbb39dadccf867da0e9dc5e
fdafd654ad4272afe60e93db5643c7ba73cf69cbb6285402f83135b2700fa25380f7b94c6d701804
afb808cc032a0d2238f5bcf5a40bfd0247b297bd5f7c8221c9419bdbf9
But does return :
(first process)
9796e768cbae5b839e55e7310fed0e31e60d4252f8633884d2aa82bb829562e66dbcbf1783fafd37
cae510d962e0c4b1ee77f4dca2ac7327397ce442631beb2596d4ecb5d703842dec2ff65c4014defe
9c69f16628ddb490a123c602d69b9f2044702f36b8778da3def0c20cef91a7049e5e1ca679c69bd8
6966876801a6bfae21d4546d6b6a3c59b851b58a5d75baf7a7a5d8e0216c50c32469df6d23b9fafe
ffe9f8d1a733657cbd9984dd49155f0eac6d026401d9aca767ee25d46a9a402c4971f7849bf2a4e7
04f87b343154b586dde70317abe06641e43ebbbac31b139ba4adab43da017add9ed6a5bf73aaf06c
efd92989553e7672403afc430b158fd1b1f0496c6c3c04cbd6fe333bdd5d4a905efe9eaf42411519
f24889beb32c4c084da1efa4461b5c0f2e65ff3a4557e39899079ed28a9c15d16d7611a16874cc03
3a1d0403de0e61d7c4d99f43656f42e303b612c75ce29f63063c96da3bbd48408c06dda385c01e3a
fa40e44c1e3e0030fec8a619b41568e7b742a3c7ea8d53496b1b3e5052c462b9e620c54d59ae96ab
52257a49deaa3f2fc968401afeec038afd4b309a8a124df3627db5612fbb39dadccf867da0e9dc5e
fdafd654ad4272afe60e93db5643c7ba73cf69cbb6285402f83135b2700fa25380f7b94c6d701804
afb808cc032a0d2238f5bcf5a40bfd02
+
(final)
47b297bd5f7c8221c9419bdbf9a89a57
There are 3 bytes 'a89a57' added and we should expect the first process to
return the complete result.
Regards,
Original issue reported on code.google.com by vitteaym...@gmail.com
on 5 Feb 2013 at 9:26
GoogleCodeExporter commented
I get the same result using both methods. Here is the code I ran.
<!doctype html>
<script
src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></scri
pt>
<script
src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/mode-ctr-mi
n.js"></script>
<script>
var K = CryptoJS.enc.Hex.parse('546c9ee039c8acf804405bf02970ee8b');
var IV = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
var text =
CryptoJS.enc.Hex.parse('2800000000e0ba377e00267777772e66343131366133306335386661
33666430363936323239366363313431362e636f6d00000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00');
var singlePart = CryptoJS.AES.encrypt(text, K, { mode: CryptoJS.mode.CTR, iv:
IV }).ciphertext.toString()
var aes = CryptoJS.algo.AES.createEncryptor(K, { mode: CryptoJS.mode.CTR, iv:
IV });
var multiPart1 = aes.process(text).toString();
var multiPart2 = aes.finalize().toString();
console.log(singlePart === multiPart1 + multiPart2);
console.log(singlePart);
console.log(multiPart1 + multiPart2);
</script>
Original comment by Jeff.Mott.OR
on 5 Feb 2013 at 11:31
GoogleCodeExporter commented
Original comment by Jeff.Mott.OR
on 6 Feb 2013 at 4:40
- Changed state: Invalid
GoogleCodeExporter commented
Yes indeed...probably a mismatch in my tests, sorry.
But that did not return the expected result. Adding the option
padding:CryptoJS.pad.NoPadding does return the expected result.
Now, there might still be an issue for progressive ciphering : cryptoJS
implementation does return multiPart1 first and multiPart2 after final, where
multiPart1+multiPart2 is the encryption of "text", which is logical, but other
implementations I know (at least node.js's one, so probably openssl too) return
multiPart1+multiPart2 on update (still mysterious for me, maybe you know why).
So, during streaming, if I want to do :
1- sending party :
Enc=createEncryptor(key,params)
encrypt Buffer1 --> Enc.update(Buffer1)=final for Buffer1
encrypt Buffer2 --> Enc.update(Buffer2)=Buffer2 part of final for
Buffer2+Buffer1
etc
2- receiving party :
Dec=createDecryptor(key,params)
Dec.update(Buffer1) --> decoded Buffer1
Dec.update(Buffer2) --> Buffer2 decoded part of decoded (Buffer2+Buffer1)
etc
The rational might be unclear to do this, but as far as I see (and have
experienced with node-Tor) this is how the Tor protocol is working.
I don't see how to do this since final does end the encryptor. I have tried :
crypto.createCipheriv=function(algo,key,iv) {
algo=algo.split('-');
key=abv2wa(key);
var params={mode:CryptoJS.mode[algo[2].toUpperCase()],iv:abv2wa(iv),padding:CryptoJS.pad.NoPadding};
var enc=CryptoJS.algo.AES.createEncryptor(key,params);
enc.update=function(data) {
var m=this._data.sigBytes*2;
var tmp=this.process(abv2wa(data)).toString(CryptoJS.enc.Hex);
return [tmp.substr(m),this.clone().finalize().toString(CryptoJS.enc.Hex)].join('');
};
enc.final=function() {return this.finalize().toString(CryptoJS.enc.Hex);};
return enc;
};
Normally this should work but does not, it seems tha this.clone().finalize is
modifying something (object in common between clone and cloned?) that affects
the cloned encryptor but I can't find out what for now.
Original comment by vitteaym...@gmail.com
on 6 Feb 2013 at 4:44
GoogleCodeExporter commented
> But that did not return the expected result. Adding the option
padding:CryptoJS.pad.NoPadding does return the expected result.
The default padding is PKCS5, so you'll have to explicitly specify if you want
to use a different padding or no padding.
> other implementations I know (at least node.js's one, so probably openssl
too) return multiPart1+multiPart2 on update
Since CryptoJS might need to apply a padding, it can't encrypt any partial
blocks until it knows whether it's the last block. Calling finalize() is how
CryptoJS knows there are no more blocks coming, and it can then process the
remaining partial block.
> So, during streaming, if I want to do :
Is the issue that another library expects exactly two message parts? No more,
no less?
Original comment by Jeff.Mott.OR
on 6 Feb 2013 at 7:10
GoogleCodeExporter commented
> Since CryptoJS might need to apply a padding, it can't encrypt any partial
blocks until it knows whether it's the last block. Calling finalize() is how
CryptoJS knows there are no more blocks coming, and it can then process the
remaining partial block.
Then why the processing is not different if we explicitly asked for no padding ?
> Is the issue that another library expects exactly two message parts? No more,
no less?
Not sure to understand the question but the expectation is what I described, so
probably the answer is yes
Original comment by vitteaym...@gmail.com
on 6 Feb 2013 at 10:21
GoogleCodeExporter commented
I'll accept that CryptoJS could -- and probably should -- adjust its block
processing depending on how many bits a padding might add or remove, which in
the case of no padding would be zero.
Original comment by Jeff.Mott.OR
on 7 Feb 2013 at 7:06
- Changed state: Accepted