Browse Source

Initial version that encrypts and decrypts

Rob Napier 10 years ago
parent
commit
de63291b75
2 changed files with 93 additions and 0 deletions
  1. 84 0
      rncryptor.js
  2. 9 0
      tests/rncryptor-test.js

+ 84 - 0
rncryptor.js

@@ -1,5 +1,61 @@
 var RNCryptor = {};
 
+CryptoJS.enc.u8array = {
+        /**
+         * Converts a word array to a Uint8Array.
+         *
+         * @param {WordArray} wordArray The word array.
+         *
+         * @return {Uint8Array} The Uint8Array.
+         *
+         * @static
+         *
+         * @example
+         *
+         *     var u8arr = CryptoJS.enc.u8array.stringify(wordArray);
+         */
+        stringify: function (wordArray) {
+            // Shortcuts
+            var words = wordArray.words;
+            var sigBytes = wordArray.sigBytes;
+
+            // Convert
+            var u8 = new Uint8Array(sigBytes);
+            for (var i = 0; i < sigBytes; i++) {
+                var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+                u8[i]=byte;
+            }
+
+            return u8;
+        },
+
+        /**
+         * Converts a Uint8Array to a word array.
+         *
+         * @param {string} u8Str The Uint8Array.
+         *
+         * @return {WordArray} The word array.
+         *
+         * @static
+         *
+         * @example
+         *
+         *     var wordArray = CryptoJS.enc.u8array.parse(u8arr);
+         */
+        parse: function (u8arr) {
+            // Shortcut
+            var len = u8arr.length;
+
+            // Convert
+            var words = [];
+            for (var i = 0; i < len; i++) {
+                words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8);
+            }
+
+            return CryptoJS.lib.WordArray.create(words, len);
+        }
+    };
+
 /*
     Takes password string and salt WordArray
     Returns key WordArray
@@ -43,4 +99,32 @@ RNCryptor.Encrypt = function(password, plaintext, options) {
   message.concat(hmac);
 
   return message;
+}
+
+RNCryptor.Decrypt = function(password, ciphertext, options) {
+  options = options || {}
+
+  var message = ciphertext.toString(CryptoJS.enc.u8array);
+
+  var version = message[0];
+  var options = message[1];
+
+  var encryption_salt = CryptoJS.enc.u8array.parse(message.subarray(2, 10));
+  var encryption_key = RNCryptor.KeyForPassword(password, encryption_salt);
+
+  var hmac_salt = CryptoJS.enc.u8array.parse(message.subarray(10, 18));
+  var hmac_key = RNCryptor.KeyForPassword(password, hmac_salt);
+
+  var iv = CryptoJS.enc.u8array.parse(message.subarray(18, 34));
+
+  var ciphertext = CryptoJS.enc.u8array.parse(message.subarray(34, -32));
+
+  var hmac = CryptoJS.enc.u8array.parse(message.subarray(-32));
+
+  // Docs say you can pass a WordArray, but it actually has to be Base64.
+  var decrypted = CryptoJS.AES.decrypt(ciphertext.toString(CryptoJS.enc.Base64), encryption_key, {iv: iv});
+
+  // FIXME: Check HMAC
+
+  return decrypted;
 }

+ 9 - 0
tests/rncryptor-test.js

@@ -12,4 +12,13 @@ var verify_password_short = function(vector) {
                                      });
 
   equal(ciphertext.toString(), vector["ciphertext_hex"].replace(/\s/g,''));
+
+  var plaintext = RNCryptor.Decrypt(vector["password"],
+                                    CryptoJS.enc.Hex.parse(vector["ciphertext_hex"].replace(/\s/g,'')), 
+                                     { "encryption_salt": CryptoJS.enc.Hex.parse(vector["enc_salt_hex"].replace(/\s/g,'')),
+                                       "hmac_salt": CryptoJS.enc.Hex.parse(vector["hmac_salt_hex"].replace(/\s/g,'')),
+                                       "iv": CryptoJS.enc.Hex.parse(vector["iv_hex"].replace(/\s/g,''))
+                                     });
+
+    equal(plaintext.toString(), vector["plaintext_hex"].replace(/\s/g,''));
 }