Hi,
While reading and testing the AeroGear JS crypto library, I came up with some questions/findings. Before opening JIRAs I'd like to discuss them with you.
a) The KeyPair function which creates a pair of cryptographic keys for assymetric encryption is using the SJCL ECC library [1] to generate keys if no keys are provided.
sjcl.ecc.elGamal.generateKeys( 192,0 )
If I understand well, the first argument (192) is the elliptic curve and the second argument (0) is the paranoia. These values are hardcoded inside aerogear.crypto.js. Is there any specific reason for which the values are 192 and 0? According the BSI recommendations [3] and NSA suite cryptography sheet [2]], the elliptic curve is recommended to be 256 for secret level or 384 for top secret. The SJCL source code shows that if paranoia is set to be 0 then the random value generator [7] is called with paranoia value 0 and the consequence is that the SCJL randomWords is called with paranoia value 0. According the SCJL author's comments [6], calling the randomWords with paranoia value 0 is explicitly warned against, and is for use only in unit tests where entropy may not be available. Maybe we should consider increasing the elliptic curve and paranoia values or allow the user to set his desired values by passing them when creating the keys. The same applies for digital signatures support ECDSA [8].
Below you can see some performance results for sjcl.ecc.elGamal.generateKeys(elliptic curve). Unfortunately I'm facing issues when trying to measure the performance on Safari and Chrome browsers. If I manage to resolve them, I'll let you know their performance statistics.
b) The getRandomValue method [4] which creates cryptographically pseudo random values is using the window.crypto.getRandomValues of the WebCryptoAPI [9]. The browser compatibility map for this method, according [5] is:
Regarding the Android browser support, the crypto.getRandomValue is supported in Android versions >= 4.0. In previous Android versions, I receive an exception on line aerogear.crypto.js line 86. This means that the crypto.getRandomValue is not supported in Android versions < 4.0. Shouldn't we add a check to verify whether WebCryptoAPI is supported on the browser? Something like if (window.crypto && window.crypto.getRandomValue) {....} else { //handle the case }. My first thought is to use to SJCL random to produce cryptographically pseudo-random values in the cases where the WebCryptoAPI is not supported by the browser. There are some vulnerabilities [6] if SJCL randomWords is called without calling startCollectors() to start the entropy collector on page load and paranoia is set to 0. SJCL startCollectors() needs to be called on page load so that entropy collector is started and the random values produced from SJCL are strong. To be honest this solution seems to me as quite dirty. Should we add an alternative pseudo-random values generator in the cases where the WebCryptoAPI is not supported by the browser?
[1]: https://github.com/aerogear/aerogear-js/blob/master/src/crypto/aerogear.crypto.js#L238
[2]: http://www.keylength.com/en/6/
[3]: http://www.keylength.com/en/8/
[4]: https://github.com/aerogear/aerogear-js/blob/master/src/crypto/aerogear.crypto.js#L84
[5]: https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues?redirectlocale=en-US&redirectslug=DOM%2Fwindow.crypto.getRandomValues#Browser_Compatibility
[6]: https://github.com/bitwiseshiftleft/sjcl/issues/77
[7]: https://github.com/bitwiseshiftleft/sjcl/blob/master/core/ecc.js#L385
[8]: https://github.com/aerogear/aerogear-js/blob/master/src/crypto/aerogear.crypto.js#L194
[9]: http://www.w3.org/TR/2013/WD-WebCryptoAPI-20130625/#RandomSource-method-getRandomValues