--- a/services/crypto/modules/WeaveCrypto.js
+++ b/services/crypto/modules/WeaveCrypto.js
@@ -3,758 +3,264 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ["WeaveCrypto"];
var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/ctypes.jsm");
-Cu.import('resource://gre/modules/AppConstants.jsm');
+Cu.import("resource://services-common/async.js");
+
+Cu.importGlobalProperties(['crypto']);
-/**
- * Shortcuts for some algorithm SEC OIDs. Full list available here:
- * http://lxr.mozilla.org/seamonkey/source/security/nss/lib/util/secoidt.h
- */
-const DES_EDE3_CBC = 156;
-const AES_128_CBC = 184;
-const AES_192_CBC = 186;
-const AES_256_CBC = 188;
+const CRYPT_ALGO = "AES-CBC";
+const CRYPT_ALGO_LENGTH = 256;
+const AES_CBC_IV_SIZE = 16;
+const OPERATIONS = { ENCRYPT: 0, DECRYPT: 1 };
+const UTF_LABEL = "utf-8";
-const ALGORITHM = AES_256_CBC;
-const KEYSIZE_AES_256 = 32;
-const KEY_DERIVATION_ITERATIONS = 4096; // PKCS#5 recommends at least 1000.
-const INITIAL_BUFFER_SIZE = 1024;
+const KEY_DERIVATION_ALGO = "PBKDF2";
+const KEY_DERIVATION_HASHING_ALGO = "SHA-1";
+const KEY_DERIVATION_ITERATIONS = 4096; // PKCS#5 recommends at least 1000.
+const DERIVED_KEY_ALGO = CRYPT_ALGO;
this.WeaveCrypto = function WeaveCrypto() {
this.init();
-}
+};
WeaveCrypto.prototype = {
prefBranch : null,
debug : true, // services.sync.log.cryptoDebug
- nss : null,
- nss_t : null,
observer : {
_self : null,
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
- observe : function (subject, topic, data) {
+ observe(subject, topic, data) {
let self = this._self;
self.log("Observed " + topic + " topic.");
if (topic == "nsPref:changed") {
self.debug = self.prefBranch.getBoolPref("cryptoDebug");
}
}
},
- init : function() {
+ init() {
+ // Preferences. Add observer so we get notified of changes.
+ this.prefBranch = Services.prefs.getBranch("services.sync.log.");
+ this.prefBranch.addObserver("cryptoDebug", this.observer, false);
+ this.observer._self = this;
try {
- // Preferences. Add observer so we get notified of changes.
- this.prefBranch = Services.prefs.getBranch("services.sync.log.");
- this.prefBranch.addObserver("cryptoDebug", this.observer, false);
- this.observer._self = this;
- try {
- this.debug = this.prefBranch.getBoolPref("cryptoDebug");
- } catch (x) {
- this.debug = false;
- }
-
- this.initNSS();
- this.initAlgorithmSettings(); // Depends on NSS.
- this.initIVSECItem();
- this.initSharedInts();
- this.initBuffers(INITIAL_BUFFER_SIZE);
- } catch (e) {
- this.log("init failed: " + e);
- throw e;
+ this.debug = this.prefBranch.getBoolPref("cryptoDebug");
+ } catch (x) {
+ this.debug = false;
}
+ XPCOMUtils.defineLazyGetter(this, 'encoder', () => new TextEncoder(UTF_LABEL));
+ XPCOMUtils.defineLazyGetter(this, 'decoder', () => new TextDecoder(UTF_LABEL, { fatal: true }));
},
- // Avoid allocating new temporary ints on every run of _commonCrypt.
- _commonCryptSignedOutputSize: null,
- _commonCryptSignedOutputSizeAddr: null,
- _commonCryptUnsignedOutputSize: null,
- _commonCryptUnsignedOutputSizeAddr: null,
-
- initSharedInts: function initSharedInts() {
- let signed = new ctypes.int();
- let unsigned = new ctypes.unsigned_int();
- this._commonCryptSignedOutputSize = signed;
- this._commonCryptUnsignedOutputSize = unsigned;
- this._commonCryptSignedOutputSizeAddr = signed.address();
- this._commonCryptUnsignedOutputSizeAddr = unsigned.address();
- },
-
- /**
- * Set a bunch of NSS values once, at init-time. These are:
- * - .blockSize
- * - .mechanism
- * - .keygenMechanism
- * - .padMechanism
- * - .keySize
- *
- * See also the constant ALGORITHM.
- */
- initAlgorithmSettings: function() {
- this.mechanism = this.nss.PK11_AlgtagToMechanism(ALGORITHM);
- this.blockSize = this.nss.PK11_GetBlockSize(this.mechanism, null);
- this.ivLength = this.nss.PK11_GetIVLength(this.mechanism);
- this.keySize = KEYSIZE_AES_256;
- this.keygenMechanism = this.nss.CKM_AES_KEY_GEN; // Always the same!
-
- // Determine which (padded) PKCS#11 mechanism to use.
- // E.g., AES_256_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD
- this.padMechanism = this.nss.PK11_GetPadMechanism(this.mechanism);
- if (this.padMechanism == this.nss.CKM_INVALID_MECHANISM)
- throw Components.Exception("invalid algorithm (can't pad)", Cr.NS_ERROR_FAILURE);
- },
-
- log : function (message) {
- if (!this.debug)
+ log(message) {
+ if (!this.debug) {
return;
+ }
dump("WeaveCrypto: " + message + "\n");
Services.console.logStringMessage("WeaveCrypto: " + message);
},
- initNSS : function() {
- // We use NSS for the crypto ops, which needs to be initialized before
- // use. By convention, PSM is required to be the module that
- // initializes NSS. So, make sure PSM is initialized in order to
- // implicitly initialize NSS.
- Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ // /!\ Only use this for tests! /!\
+ _getCrypto() {
+ return crypto;
+ },
- // Open the NSS library.
- let path = ctypes.libraryName("nss3");
+ encrypt(clearTextUCS2, symmetricKey, iv) {
+ this.log("encrypt() called");
+ let clearTextBuffer = this.encoder.encode(clearTextUCS2).buffer;
+ let encrypted = this._commonCrypt(clearTextBuffer, symmetricKey, iv, OPERATIONS.ENCRYPT);
+ return this.encodeBase64(encrypted);
+ },
+
+ decrypt(cipherText, symmetricKey, iv) {
+ this.log("decrypt() called");
+ if (cipherText.length) {
+ cipherText = atob(cipherText);
+ }
+ let cipherTextBuffer = this.byteCompressInts(cipherText);
+ let decrypted = this._commonCrypt(cipherTextBuffer, symmetricKey, iv, OPERATIONS.DECRYPT);
+ return this.decoder.decode(decrypted);
+ },
- // XXX really want to be able to pass specific dlopen flags here.
- var nsslib;
- if (AppConstants.MOZ_SYSTEM_NSS) {
- // Search platform-dependent library paths for system NSS.
- this.log("Trying NSS library without path");
- nsslib = ctypes.open(path);
- } else {
- let file = Services.dirsvc.get("GreBinD", Ci.nsILocalFile);
- file.append(path);
- this.log("Trying NSS library with path " + file.path);
- nsslib = ctypes.open(file.path);
+ /**
+ * _commonCrypt
+ *
+ * @args
+ * data: data to encrypt/decrypt (ArrayBuffer)
+ * symKeyStr: symmetric key (Base64 String)
+ * ivStr: initialization vector (Base64 String)
+ * operation: operation to apply (either OPERATIONS.ENCRYPT or OPERATIONS.DECRYPT)
+ * @returns
+ * the encrypted/decrypted data (ArrayBuffer)
+ */
+ _commonCrypt(data, symKeyStr, ivStr, operation) {
+ this.log("_commonCrypt() called");
+ ivStr = atob(ivStr);
+
+ if (operation !== OPERATIONS.ENCRYPT && operation !== OPERATIONS.DECRYPT) {
+ throw new Error("Unsupported operation in _commonCrypt.");
+ }
+ // We never want an IV longer than the block size, which is 16 bytes
+ // for AES, neither do we want one smaller; throw in both cases.
+ if (ivStr.length !== AES_CBC_IV_SIZE) {
+ throw "Invalid IV size; must be " + AES_CBC_IV_SIZE + " bytes.";
}
- this.log("Initializing NSS types and function declarations...");
-
- this.nss = {};
- this.nss_t = {};
-
- // nsprpub/pr/include/prtypes.h#435
- // typedef PRIntn PRBool; --> int
- this.nss_t.PRBool = ctypes.int;
- // security/nss/lib/util/seccomon.h#91
- // typedef enum
- this.nss_t.SECStatus = ctypes.int;
- // security/nss/lib/softoken/secmodt.h#59
- // typedef struct PK11SlotInfoStr PK11SlotInfo; (defined in secmodti.h)
- this.nss_t.PK11SlotInfo = ctypes.void_t;
- // security/nss/lib/util/pkcs11t.h
- this.nss_t.CK_MECHANISM_TYPE = ctypes.unsigned_long;
- this.nss_t.CK_ATTRIBUTE_TYPE = ctypes.unsigned_long;
- this.nss_t.CK_KEY_TYPE = ctypes.unsigned_long;
- this.nss_t.CK_OBJECT_HANDLE = ctypes.unsigned_long;
- // security/nss/lib/softoken/secmodt.h#359
- // typedef enum PK11Origin
- this.nss_t.PK11Origin = ctypes.int;
- // PK11Origin enum values...
- this.nss.PK11_OriginUnwrap = 4;
- // security/nss/lib/softoken/secmodt.h#61
- // typedef struct PK11SymKeyStr PK11SymKey; (defined in secmodti.h)
- this.nss_t.PK11SymKey = ctypes.void_t;
- // security/nss/lib/util/secoidt.h#454
- // typedef enum
- this.nss_t.SECOidTag = ctypes.int;
- // security/nss/lib/util/seccomon.h#64
- // typedef enum
- this.nss_t.SECItemType = ctypes.int;
- // SECItemType enum values...
- this.nss.SIBUFFER = 0;
- // security/nss/lib/softoken/secmodt.h#62 (defined in secmodti.h)
- // typedef struct PK11ContextStr PK11Context;
- this.nss_t.PK11Context = ctypes.void_t;
- // Needed for SECKEYPrivateKey struct def'n, but I don't think we need to actually access it.
- this.nss_t.PLArenaPool = ctypes.void_t;
- // security/nss/lib/cryptohi/keythi.h#45
- // typedef enum
- this.nss_t.KeyType = ctypes.int;
- // security/nss/lib/softoken/secmodt.h#201
- // typedef PRUint32 PK11AttrFlags;
- this.nss_t.PK11AttrFlags = ctypes.unsigned_int;
- // security/nss/lib/util/seccomon.h#83
- // typedef struct SECItemStr SECItem; --> SECItemStr defined right below it
- this.nss_t.SECItem = ctypes.StructType(
- "SECItem", [{ type: this.nss_t.SECItemType },
- { data: ctypes.unsigned_char.ptr },
- { len : ctypes.int }]);
- // security/nss/lib/util/secoidt.h#52
- // typedef struct SECAlgorithmIDStr --> def'n right below it
- this.nss_t.SECAlgorithmID = ctypes.StructType(
- "SECAlgorithmID", [{ algorithm: this.nss_t.SECItem },
- { parameters: this.nss_t.SECItem }]);
-
-
- // security/nss/lib/util/pkcs11t.h
- this.nss.CKK_RSA = 0x0;
- this.nss.CKM_RSA_PKCS_KEY_PAIR_GEN = 0x0000;
- this.nss.CKM_AES_KEY_GEN = 0x1080;
- this.nss.CKA_ENCRYPT = 0x104;
- this.nss.CKA_DECRYPT = 0x105;
-
- // security/nss/lib/softoken/secmodt.h
- this.nss.PK11_ATTR_SESSION = 0x02;
- this.nss.PK11_ATTR_PUBLIC = 0x08;
- this.nss.PK11_ATTR_SENSITIVE = 0x40;
-
- // security/nss/lib/util/secoidt.h
- this.nss.SEC_OID_PKCS5_PBKDF2 = 291;
- this.nss.SEC_OID_HMAC_SHA1 = 294;
- this.nss.SEC_OID_PKCS1_RSA_ENCRYPTION = 16;
+ let iv = this.byteCompressInts(ivStr);
+ let symKey = this.importSymKey(symKeyStr, operation);
+ let cryptMethod = (operation === OPERATIONS.ENCRYPT
+ ? crypto.subtle.encrypt
+ : crypto.subtle.decrypt)
+ .bind(crypto.subtle);
+ let algo = { name: CRYPT_ALGO, iv: iv };
- // security/nss/lib/pk11wrap/pk11pub.h#286
- // SECStatus PK11_GenerateRandom(unsigned char *data,int len);
- this.nss.PK11_GenerateRandom = nsslib.declare("PK11_GenerateRandom",
- ctypes.default_abi, this.nss_t.SECStatus,
- ctypes.unsigned_char.ptr, ctypes.int);
- // security/nss/lib/pk11wrap/pk11pub.h#74
- // PK11SlotInfo *PK11_GetInternalSlot(void);
- this.nss.PK11_GetInternalSlot = nsslib.declare("PK11_GetInternalSlot",
- ctypes.default_abi, this.nss_t.PK11SlotInfo.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#73
- // PK11SlotInfo *PK11_GetInternalKeySlot(void);
- this.nss.PK11_GetInternalKeySlot = nsslib.declare("PK11_GetInternalKeySlot",
- ctypes.default_abi, this.nss_t.PK11SlotInfo.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#328
- // PK11SymKey *PK11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, SECItem *param, int keySize,void *wincx);
- this.nss.PK11_KeyGen = nsslib.declare("PK11_KeyGen",
- ctypes.default_abi, this.nss_t.PK11SymKey.ptr,
- this.nss_t.PK11SlotInfo.ptr, this.nss_t.CK_MECHANISM_TYPE,
- this.nss_t.SECItem.ptr, ctypes.int, ctypes.voidptr_t);
- // security/nss/lib/pk11wrap/pk11pub.h#477
- // SECStatus PK11_ExtractKeyValue(PK11SymKey *symKey);
- this.nss.PK11_ExtractKeyValue = nsslib.declare("PK11_ExtractKeyValue",
- ctypes.default_abi, this.nss_t.SECStatus,
- this.nss_t.PK11SymKey.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#478
- // SECItem * PK11_GetKeyData(PK11SymKey *symKey);
- this.nss.PK11_GetKeyData = nsslib.declare("PK11_GetKeyData",
- ctypes.default_abi, this.nss_t.SECItem.ptr,
- this.nss_t.PK11SymKey.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#278
- // CK_MECHANISM_TYPE PK11_AlgtagToMechanism(SECOidTag algTag);
- this.nss.PK11_AlgtagToMechanism = nsslib.declare("PK11_AlgtagToMechanism",
- ctypes.default_abi, this.nss_t.CK_MECHANISM_TYPE,
- this.nss_t.SECOidTag);
- // security/nss/lib/pk11wrap/pk11pub.h#270
- // int PK11_GetIVLength(CK_MECHANISM_TYPE type);
- this.nss.PK11_GetIVLength = nsslib.declare("PK11_GetIVLength",
- ctypes.default_abi, ctypes.int,
- this.nss_t.CK_MECHANISM_TYPE);
- // security/nss/lib/pk11wrap/pk11pub.h#269
- // int PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params);
- this.nss.PK11_GetBlockSize = nsslib.declare("PK11_GetBlockSize",
- ctypes.default_abi, ctypes.int,
- this.nss_t.CK_MECHANISM_TYPE, this.nss_t.SECItem.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#293
- // CK_MECHANISM_TYPE PK11_GetPadMechanism(CK_MECHANISM_TYPE);
- this.nss.PK11_GetPadMechanism = nsslib.declare("PK11_GetPadMechanism",
- ctypes.default_abi, this.nss_t.CK_MECHANISM_TYPE,
- this.nss_t.CK_MECHANISM_TYPE);
- // security/nss/lib/pk11wrap/pk11pub.h#271
- // SECItem *PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv);
- this.nss.PK11_ParamFromIV = nsslib.declare("PK11_ParamFromIV",
- ctypes.default_abi, this.nss_t.SECItem.ptr,
- this.nss_t.CK_MECHANISM_TYPE, this.nss_t.SECItem.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#301
- // PK11SymKey *PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin,
- // CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx);
- this.nss.PK11_ImportSymKey = nsslib.declare("PK11_ImportSymKey",
- ctypes.default_abi, this.nss_t.PK11SymKey.ptr,
- this.nss_t.PK11SlotInfo.ptr, this.nss_t.CK_MECHANISM_TYPE, this.nss_t.PK11Origin,
- this.nss_t.CK_ATTRIBUTE_TYPE, this.nss_t.SECItem.ptr, ctypes.voidptr_t);
- // security/nss/lib/pk11wrap/pk11pub.h#672
- // PK11Context *PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation,
- // PK11SymKey *symKey, SECItem *param);
- this.nss.PK11_CreateContextBySymKey = nsslib.declare("PK11_CreateContextBySymKey",
- ctypes.default_abi, this.nss_t.PK11Context.ptr,
- this.nss_t.CK_MECHANISM_TYPE, this.nss_t.CK_ATTRIBUTE_TYPE,
- this.nss_t.PK11SymKey.ptr, this.nss_t.SECItem.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#685
- // SECStatus PK11_CipherOp(PK11Context *context, unsigned char *out
- // int *outlen, int maxout, unsigned char *in, int inlen);
- this.nss.PK11_CipherOp = nsslib.declare("PK11_CipherOp",
- ctypes.default_abi, this.nss_t.SECStatus,
- this.nss_t.PK11Context.ptr, ctypes.unsigned_char.ptr,
- ctypes.int.ptr, ctypes.int, ctypes.unsigned_char.ptr, ctypes.int);
- // security/nss/lib/pk11wrap/pk11pub.h#688
- // SECStatus PK11_DigestFinal(PK11Context *context, unsigned char *data,
- // unsigned int *outLen, unsigned int length);
- this.nss.PK11_DigestFinal = nsslib.declare("PK11_DigestFinal",
- ctypes.default_abi, this.nss_t.SECStatus,
- this.nss_t.PK11Context.ptr, ctypes.unsigned_char.ptr,
- ctypes.unsigned_int.ptr, ctypes.unsigned_int);
- // security/nss/lib/pk11wrap/pk11pub.h#731
- // SECAlgorithmID * PK11_CreatePBEV2AlgorithmID(SECOidTag pbeAlgTag, SECOidTag cipherAlgTag,
- // SECOidTag prfAlgTag, int keyLength, int iteration,
- // SECItem *salt);
- this.nss.PK11_CreatePBEV2AlgorithmID = nsslib.declare("PK11_CreatePBEV2AlgorithmID",
- ctypes.default_abi, this.nss_t.SECAlgorithmID.ptr,
- this.nss_t.SECOidTag, this.nss_t.SECOidTag, this.nss_t.SECOidTag,
- ctypes.int, ctypes.int, this.nss_t.SECItem.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#736
- // PK11SymKey * PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES, void *wincx);
- this.nss.PK11_PBEKeyGen = nsslib.declare("PK11_PBEKeyGen",
- ctypes.default_abi, this.nss_t.PK11SymKey.ptr,
- this.nss_t.PK11SlotInfo.ptr, this.nss_t.SECAlgorithmID.ptr,
- this.nss_t.SECItem.ptr, this.nss_t.PRBool, ctypes.voidptr_t);
- // security/nss/lib/pk11wrap/pk11pub.h#675
- // void PK11_DestroyContext(PK11Context *context, PRBool freeit);
- this.nss.PK11_DestroyContext = nsslib.declare("PK11_DestroyContext",
- ctypes.default_abi, ctypes.void_t,
- this.nss_t.PK11Context.ptr, this.nss_t.PRBool);
- // security/nss/lib/pk11wrap/pk11pub.h#299
- // void PK11_FreeSymKey(PK11SymKey *key);
- this.nss.PK11_FreeSymKey = nsslib.declare("PK11_FreeSymKey",
- ctypes.default_abi, ctypes.void_t,
- this.nss_t.PK11SymKey.ptr);
- // security/nss/lib/pk11wrap/pk11pub.h#70
- // void PK11_FreeSlot(PK11SlotInfo *slot);
- this.nss.PK11_FreeSlot = nsslib.declare("PK11_FreeSlot",
- ctypes.default_abi, ctypes.void_t,
- this.nss_t.PK11SlotInfo.ptr);
- // security/nss/lib/util/secitem.h#49
- // extern SECItem *SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len);
- this.nss.SECITEM_AllocItem = nsslib.declare("SECITEM_AllocItem",
- ctypes.default_abi, this.nss_t.SECItem.ptr,
- this.nss_t.PLArenaPool.ptr, // Not used.
- this.nss_t.SECItem.ptr, ctypes.unsigned_int);
- // security/nss/lib/util/secitem.h#274
- // extern void SECITEM_ZfreeItem(SECItem *zap, PRBool freeit);
- this.nss.SECITEM_ZfreeItem = nsslib.declare("SECITEM_ZfreeItem",
- ctypes.default_abi, ctypes.void_t,
- this.nss_t.SECItem.ptr, this.nss_t.PRBool);
- // security/nss/lib/util/secitem.h#114
- // extern void SECITEM_FreeItem(SECItem *zap, PRBool freeit);
- this.nss.SECITEM_FreeItem = nsslib.declare("SECITEM_FreeItem",
- ctypes.default_abi, ctypes.void_t,
- this.nss_t.SECItem.ptr, this.nss_t.PRBool);
- // security/nss/lib/util/secoid.h#103
- // extern void SECOID_DestroyAlgorithmID(SECAlgorithmID *aid, PRBool freeit);
- this.nss.SECOID_DestroyAlgorithmID = nsslib.declare("SECOID_DestroyAlgorithmID",
- ctypes.default_abi, ctypes.void_t,
- this.nss_t.SECAlgorithmID.ptr, this.nss_t.PRBool);
+ return Async.promiseSpinningly(
+ cryptMethod(algo, symKey, data)
+ .then(keyBytes => new Uint8Array(keyBytes))
+ );
},
- _sharedInputBuffer: null,
- _sharedInputBufferInts: null,
- _sharedInputBufferSize: 0,
- _sharedOutputBuffer: null,
- _sharedOutputBufferSize: 0,
- _randomByteBuffer: null,
- _randomByteBufferAddr: null,
- _randomByteBufferSize: 0,
-
- _getInputBuffer: function _getInputBuffer(size) {
- if (size > this._sharedInputBufferSize) {
- let b = new ctypes.ArrayType(ctypes.unsigned_char, size)();
- this._sharedInputBuffer = b;
- this._sharedInputBufferInts = ctypes.cast(b, ctypes.uint8_t.array(size));
- this._sharedInputBufferSize = size;
- }
- return this._sharedInputBuffer;
- },
-
- _getOutputBuffer: function _getOutputBuffer(size) {
- if (size > this._sharedOutputBufferSize) {
- let b = new ctypes.ArrayType(ctypes.unsigned_char, size)();
- this._sharedOutputBuffer = b;
- this._sharedOutputBufferSize = size;
- }
- return this._sharedOutputBuffer;
- },
-
- _getRandomByteBuffer: function _getRandomByteBuffer(size) {
- if (size > this._randomByteBufferSize) {
- let b = new ctypes.ArrayType(ctypes.unsigned_char, size)();
- this._randomByteBuffer = b;
- this._randomByteBufferAddr = b.address();
- this._randomByteBufferSize = size;
- }
- return this._randomByteBuffer;
- },
-
- initBuffers: function initBuffers(initialSize) {
- this._getInputBuffer(initialSize);
- this._getOutputBuffer(initialSize);
-
- this._getRandomByteBuffer(this.ivLength);
- },
-
- encrypt : function(clearTextUCS2, symmetricKey, iv) {
- this.log("encrypt() called");
-
- // js-ctypes autoconverts to a UTF8 buffer, but also includes a null
- // at the end which we don't want. Decrement length to skip it.
- let inputBuffer = new ctypes.ArrayType(ctypes.unsigned_char)(clearTextUCS2);
- let inputBufferSize = inputBuffer.length - 1;
-
- // When using CBC padding, the output size is the input size rounded
- // up to the nearest block. If the input size is exactly on a block
- // boundary, the output is 1 extra block long.
- let outputBufferSize = inputBufferSize + this.blockSize;
- let outputBuffer = this._getOutputBuffer(outputBufferSize);
-
- outputBuffer = this._commonCrypt(inputBuffer, inputBufferSize,
- outputBuffer, outputBufferSize,
- symmetricKey, iv, this.nss.CKA_ENCRYPT);
-
- return this.encodeBase64(outputBuffer.address(), outputBuffer.length);
- },
-
-
- decrypt : function(cipherText, symmetricKey, iv) {
- this.log("decrypt() called");
-
- let inputUCS2 = "";
- if (cipherText.length)
- inputUCS2 = atob(cipherText);
-
- // We can't have js-ctypes create the buffer directly from the string
- // (as in encrypt()), because we do _not_ want it to do UTF8
- // conversion... We've got random binary data in the input's low byte.
- //
- // Compress a JS string (2-byte chars) into a normal C string (1-byte chars).
- let len = inputUCS2.length;
- let input = this._getInputBuffer(len);
- this.byteCompressInts(inputUCS2, this._sharedInputBufferInts, len);
-
- let outputBuffer = this._commonCrypt(input, len,
- this._getOutputBuffer(len), len,
- symmetricKey, iv, this.nss.CKA_DECRYPT);
-
- // outputBuffer contains UTF-8 data, let js-ctypes autoconvert that to a JS string.
- // XXX Bug 573842: wrap the string from ctypes to get a new string, so
- // we don't hit bug 573841.
- return "" + outputBuffer.readString() + "";
+ generateRandomKey() {
+ this.log("generateRandomKey() called");
+ let algo = {
+ name: CRYPT_ALGO,
+ length: CRYPT_ALGO_LENGTH
+ };
+ return Async.promiseSpinningly(
+ crypto.subtle.generateKey(algo, true, [])
+ .then(key => crypto.subtle.exportKey("raw", key))
+ .then(keyBytes => {
+ keyBytes = new Uint8Array(keyBytes);
+ return this.encodeBase64(keyBytes);
+ })
+ );
},
- _commonCrypt : function (input, inputLength, output, outputLength, symmetricKey, iv, operation) {
- this.log("_commonCrypt() called");
- iv = atob(iv);
-
- // We never want an IV longer than the block size, which is 16 bytes
- // for AES. Neither do we want one smaller; throw in that case.
- if (iv.length < this.blockSize)
- throw "IV too short; must be " + this.blockSize + " bytes.";
- if (iv.length > this.blockSize)
- iv = iv.slice(0, this.blockSize);
-
- // We use a single IV SECItem for the sake of efficiency. Fill it here.
- this.byteCompressInts(iv, this._ivSECItemContents, iv.length);
-
- let ctx, symKey, ivParam;
- try {
- ivParam = this.nss.PK11_ParamFromIV(this.padMechanism, this._ivSECItem);
- if (ivParam.isNull())
- throw Components.Exception("can't convert IV to param", Cr.NS_ERROR_FAILURE);
-
- symKey = this.importSymKey(symmetricKey, operation);
- ctx = this.nss.PK11_CreateContextBySymKey(this.padMechanism, operation, symKey, ivParam);
- if (ctx.isNull())
- throw Components.Exception("couldn't create context for symkey", Cr.NS_ERROR_FAILURE);
-
- let maxOutputSize = outputLength;
- if (this.nss.PK11_CipherOp(ctx, output, this._commonCryptSignedOutputSize.address(), maxOutputSize, input, inputLength))
- throw Components.Exception("cipher operation failed", Cr.NS_ERROR_FAILURE);
-
- let actualOutputSize = this._commonCryptSignedOutputSize.value;
- let finalOutput = output.addressOfElement(actualOutputSize);
- maxOutputSize -= actualOutputSize;
-
- // PK11_DigestFinal sure sounds like the last step for *hashing*, but it
- // just seems to be an odd name -- NSS uses this to finish the current
- // cipher operation. You'd think it would be called PK11_CipherOpFinal...
- if (this.nss.PK11_DigestFinal(ctx, finalOutput, this._commonCryptUnsignedOutputSizeAddr, maxOutputSize))
- throw Components.Exception("cipher finalize failed", Cr.NS_ERROR_FAILURE);
-
- actualOutputSize += this._commonCryptUnsignedOutputSize.value;
- let newOutput = ctypes.cast(output, ctypes.unsigned_char.array(actualOutputSize));
- return newOutput;
- } catch (e) {
- this.log("_commonCrypt: failed: " + e);
- throw e;
- } finally {
- if (ctx && !ctx.isNull())
- this.nss.PK11_DestroyContext(ctx, true);
- if (ivParam && !ivParam.isNull())
- this.nss.SECITEM_FreeItem(ivParam, true);
-
- // Note that we do not free the IV SECItem; we reuse it.
- // Neither do we free the symKey, because that's memoized.
- }
+ generateRandomIV() {
+ return this.generateRandomBytes(AES_CBC_IV_SIZE);
},
-
- generateRandomKey : function() {
- this.log("generateRandomKey() called");
- let slot, randKey, keydata;
- try {
- slot = this.nss.PK11_GetInternalSlot();
- if (slot.isNull())
- throw Components.Exception("couldn't get internal slot", Cr.NS_ERROR_FAILURE);
-
- randKey = this.nss.PK11_KeyGen(slot, this.keygenMechanism, null, this.keySize, null);
- if (randKey.isNull())
- throw Components.Exception("PK11_KeyGen failed.", Cr.NS_ERROR_FAILURE);
-
- // Slightly odd API, this call just prepares the key value for
- // extraction, we get the actual bits from the call to PK11_GetKeyData().
- if (this.nss.PK11_ExtractKeyValue(randKey))
- throw Components.Exception("PK11_ExtractKeyValue failed.", Cr.NS_ERROR_FAILURE);
-
- keydata = this.nss.PK11_GetKeyData(randKey);
- if (keydata.isNull())
- throw Components.Exception("PK11_GetKeyData failed.", Cr.NS_ERROR_FAILURE);
-
- return this.encodeBase64(keydata.contents.data, keydata.contents.len);
- } catch (e) {
- this.log("generateRandomKey: failed: " + e);
- throw e;
- } finally {
- if (randKey && !randKey.isNull())
- this.nss.PK11_FreeSymKey(randKey);
- if (slot && !slot.isNull())
- this.nss.PK11_FreeSlot(slot);
- }
- },
-
- generateRandomIV : function() {
- return this.generateRandomBytes(this.ivLength);
- },
-
- generateRandomBytes : function(byteCount) {
+ generateRandomBytes(byteCount) {
this.log("generateRandomBytes() called");
- // Temporary buffer to hold the generated data.
- let scratch = this._getRandomByteBuffer(byteCount);
- if (this.nss.PK11_GenerateRandom(scratch, byteCount))
- throw Components.Exception("PK11_GenrateRandom failed", Cr.NS_ERROR_FAILURE);
+ let randBytes = new Uint8Array(byteCount);
+ crypto.getRandomValues(randBytes);
- return this.encodeBase64(this._randomByteBufferAddr, byteCount);
+ return this.encodeBase64(randBytes);
},
//
- // PK11SymKey memoization.
+ // SymKey CryptoKey memoization.
//
- // Memoize the lookup of symmetric keys. We do this by using the base64
- // string itself as a key -- the overhead of SECItem creation during the
- // initial population is negligible, so that phase is not memoized.
+ // Memoize the import of symmetric keys. We do this by using the base64
+ // string itself as a key.
_encryptionSymKeyMemo: {},
_decryptionSymKeyMemo: {},
- importSymKey: function importSymKey(encodedKeyString, operation) {
+ importSymKey(encodedKeyString, operation) {
let memo;
// We use two separate memos for thoroughness: operation is an input to
// key import.
switch (operation) {
- case this.nss.CKA_ENCRYPT:
+ case OPERATIONS.ENCRYPT:
memo = this._encryptionSymKeyMemo;
break;
- case this.nss.CKA_DECRYPT:
+ case OPERATIONS.DECRYPT:
memo = this._decryptionSymKeyMemo;
break;
default:
throw "Unsupported operation in importSymKey.";
}
if (encodedKeyString in memo)
return memo[encodedKeyString];
- let keyItem, slot;
- try {
- keyItem = this.makeSECItem(encodedKeyString, true);
- slot = this.nss.PK11_GetInternalKeySlot();
- if (slot.isNull())
- throw Components.Exception("can't get internal key slot",
- Cr.NS_ERROR_FAILURE);
+ let symmetricKeyBuffer = this.makeUint8Array(encodedKeyString, true);
+ let algo = { name: CRYPT_ALGO };
+ let usages = [operation === OPERATIONS.ENCRYPT ? "encrypt" : "decrypt"];
- let symKey = this.nss.PK11_ImportSymKey(slot, this.padMechanism,
- this.nss.PK11_OriginUnwrap,
- operation, keyItem, null);
- if (!symKey || symKey.isNull())
- throw Components.Exception("symkey import failed",
- Cr.NS_ERROR_FAILURE);
-
- return memo[encodedKeyString] = symKey;
- } finally {
- if (slot && !slot.isNull())
- this.nss.PK11_FreeSlot(slot);
- this.freeSECItem(keyItem);
- }
+ return Async.promiseSpinningly(
+ crypto.subtle.importKey("raw", symmetricKeyBuffer, algo, false, usages)
+ .then(symKey => {
+ memo[encodedKeyString] = symKey;
+ return symKey;
+ })
+ );
},
//
// Utility functions
//
/**
- * Compress a JS string into a C uint8 array. count is the number of
- * elements in the destination array. If the array is smaller than the
- * string, the string is effectively truncated. If the string is smaller
- * than the array, the array is not 0-padded.
+ * Returns an Uint8Array filled with a JS string,
+ * which means we only keep utf-16 characters from 0x00 to 0xFF.
*/
- byteCompressInts : function byteCompressInts (jsString, intArray, count) {
- let len = jsString.length;
- let end = Math.min(len, count);
- for (let i = 0; i < end; i++)
- intArray[i] = jsString.charCodeAt(i) & 0xFF; // convert to bytes.
+ byteCompressInts(str) {
+ let arrayBuffer = new Uint8Array(str.length);
+ for (let i = 0; i < str.length; i++) {
+ arrayBuffer[i] = str.charCodeAt(i) & 0xFF;
+ }
+ return arrayBuffer;
},
- // Expand a normal C string (1-byte chars) into a JS string (2-byte chars)
- // EG, for "ABC", 0x41, 0x42, 0x43 --> 0x0041, 0x0042, 0x0043
- byteExpand : function (charArray) {
+ expandData(data) {
let expanded = "";
- let len = charArray.length;
- let intData = ctypes.cast(charArray, ctypes.uint8_t.array(len));
- for (let i = 0; i < len; i++)
- expanded += String.fromCharCode(intData[i]);
+ for (let i = 0; i < data.length; i++) {
+ expanded += String.fromCharCode(data[i]);
+ }
return expanded;
},
- expandData : function expandData(data, len) {
- // Byte-expand the buffer, so we can treat it as a UCS-2 string
- // consisting of u0000 - u00FF.
- let expanded = "";
- let intData = ctypes.cast(data, ctypes.uint8_t.array(len).ptr).contents;
- for (let i = 0; i < len; i++)
- expanded += String.fromCharCode(intData[i]);
- return expanded;
- },
-
- encodeBase64 : function (data, len) {
- return btoa(this.expandData(data, len));
+ encodeBase64(data) {
+ return btoa(this.expandData(data));
},
- // Returns a filled SECItem *, as returned by SECITEM_AllocItem.
- //
- // Note that this must be released with freeSECItem, which will also
- // deallocate the internal buffer.
- makeSECItem : function(input, isEncoded) {
- if (isEncoded)
+ makeUint8Array(input, isEncoded) {
+ if (isEncoded) {
input = atob(input);
-
- let len = input.length;
- let item = this.nss.SECITEM_AllocItem(null, null, len);
- if (item.isNull())
- throw "SECITEM_AllocItem failed.";
-
- let ptr = ctypes.cast(item.contents.data,
- ctypes.unsigned_char.array(len).ptr);
- let dest = ctypes.cast(ptr.contents, ctypes.uint8_t.array(len));
- this.byteCompressInts(input, dest, len);
- return item;
- },
-
- freeSECItem : function(zap) {
- if (zap && !zap.isNull())
- this.nss.SECITEM_ZfreeItem(zap, true);
- },
-
- // We only ever handle one IV at a time, and they're always different.
- // Consequently, we maintain a single SECItem, and a handy pointer into its
- // contents to avoid repetitive and expensive casts.
- _ivSECItem: null,
- _ivSECItemContents: null,
-
- initIVSECItem: function initIVSECItem() {
- if (this._ivSECItem) {
- this._ivSECItemContents = null;
- this.freeSECItem(this._ivSECItem);
}
-
- let item = this.nss.SECITEM_AllocItem(null, null, this.blockSize);
- if (item.isNull())
- throw "SECITEM_AllocItem failed.";
-
- let ptr = ctypes.cast(item.contents.data,
- ctypes.unsigned_char.array(this.blockSize).ptr);
- let contents = ctypes.cast(ptr.contents,
- ctypes.uint8_t.array(this.blockSize));
- this._ivSECItem = item;
- this._ivSECItemContents = contents;
+ return this.byteCompressInts(input);
},
/**
* Returns the expanded data string for the derived key.
*/
- deriveKeyFromPassphrase : function deriveKeyFromPassphrase(passphrase, salt, keyLength) {
+ deriveKeyFromPassphrase(passphrase, saltStr, keyLength = 32) {
this.log("deriveKeyFromPassphrase() called.");
- let passItem = this.makeSECItem(passphrase, false);
- let saltItem = this.makeSECItem(salt, true);
-
- let pbeAlg = ALGORITHM;
- let cipherAlg = ALGORITHM; // Ignored by callee when pbeAlg != a pkcs5 mech.
-
- // Callee picks if SEC_OID_UNKNOWN, but only SHA1 is supported.
- let prfAlg = this.nss.SEC_OID_HMAC_SHA1;
-
- keyLength = keyLength || 0; // 0 = Callee will pick.
- let iterations = KEY_DERIVATION_ITERATIONS;
-
- let algid, slot, symKey, keyData;
- try {
- algid = this.nss.PK11_CreatePBEV2AlgorithmID(pbeAlg, cipherAlg, prfAlg,
- keyLength, iterations,
- saltItem);
- if (algid.isNull())
- throw Components.Exception("PK11_CreatePBEV2AlgorithmID failed", Cr.NS_ERROR_FAILURE);
-
- slot = this.nss.PK11_GetInternalSlot();
- if (slot.isNull())
- throw Components.Exception("couldn't get internal slot", Cr.NS_ERROR_FAILURE);
-
- symKey = this.nss.PK11_PBEKeyGen(slot, algid, passItem, false, null);
- if (symKey.isNull())
- throw Components.Exception("PK11_PBEKeyGen failed", Cr.NS_ERROR_FAILURE);
-
- // Take the PK11SymKeyStr, returning the extracted key data.
- if (this.nss.PK11_ExtractKeyValue(symKey)) {
- throw this.makeException("PK11_ExtractKeyValue failed.", Cr.NS_ERROR_FAILURE);
- }
-
- keyData = this.nss.PK11_GetKeyData(symKey);
-
- if (keyData.isNull())
- throw Components.Exception("PK11_GetKeyData failed", Cr.NS_ERROR_FAILURE);
-
- // This copies the key contents into a JS string, so we don't leak.
- // The `finally` block below will clean up.
- return this.expandData(keyData.contents.data, keyData.contents.len);
-
- } catch (e) {
- this.log("deriveKeyFromPassphrase: failed: " + e);
- throw e;
- } finally {
- if (algid && !algid.isNull())
- this.nss.SECOID_DestroyAlgorithmID(algid, true);
- if (slot && !slot.isNull())
- this.nss.PK11_FreeSlot(slot);
- if (symKey && !symKey.isNull())
- this.nss.PK11_FreeSymKey(symKey);
-
- this.freeSECItem(passItem);
- this.freeSECItem(saltItem);
- }
+ let keyData = this.makeUint8Array(passphrase, false);
+ let salt = this.makeUint8Array(saltStr, true);
+ let importAlgo = { name: KEY_DERIVATION_ALGO };
+ let deriveAlgo = {
+ name: KEY_DERIVATION_ALGO,
+ salt: salt,
+ iterations: KEY_DERIVATION_ITERATIONS,
+ hash: { name: KEY_DERIVATION_HASHING_ALGO },
+ };
+ let derivedKeyType = {
+ name: DERIVED_KEY_ALGO,
+ length: keyLength * 8,
+ };
+ return Async.promiseSpinningly(
+ crypto.subtle.importKey("raw", keyData, importAlgo, false, ["deriveKey"])
+ .then(key => crypto.subtle.deriveKey(deriveAlgo, key, derivedKeyType, true, []))
+ .then(derivedKey => crypto.subtle.exportKey("raw", derivedKey))
+ .then(keyBytes => {
+ keyBytes = new Uint8Array(keyBytes);
+ return this.expandData(keyBytes);
+ })
+ );
},
};
--- a/services/crypto/tests/unit/test_crypto_crypt.js
+++ b/services/crypto/tests/unit/test_crypto_crypt.js
@@ -1,59 +1,60 @@
Cu.import("resource://services-crypto/WeaveCrypto.js");
+Cu.importGlobalProperties(['crypto']);
var cryptoSvc = new WeaveCrypto();
function run_test() {
-
+
if ("makeSECItem" in cryptoSvc) // Only for js-ctypes WeaveCrypto.
test_makeSECItem();
-
+
if (this.gczeal) {
_("Running crypto tests with gczeal(2).");
gczeal(2);
}
test_bug_617650();
test_encrypt_decrypt();
- test_SECItem_byteCompressInts();
test_key_memoization();
if (this.gczeal)
gczeal(0);
}
function test_key_memoization() {
- let oldImport = cryptoSvc.nss && cryptoSvc.nss.PK11_ImportSymKey;
+ let cryptoGlobal = cryptoSvc._getCrypto();
+ let oldImport = cryptoGlobal.subtle.importKey;
if (!oldImport) {
- _("Couldn't swizzle PK11_ImportSymKey; returning.");
+ _("Couldn't swizzle crypto.subtle.importKey; returning.");
return;
}
let iv = cryptoSvc.generateRandomIV();
let key = cryptoSvc.generateRandomKey();
let c = 0;
- cryptoSvc.nss.PK11_ImportSymKey = function(slot, type, origin, operation, key, wincx) {
+ cryptoGlobal.subtle.importKey = function(format, keyData, algo, extractable, usages) {
c++;
- return oldImport(slot, type, origin, operation, key, wincx);
+ return oldImport.call(cryptoGlobal.subtle, format, keyData, algo, extractable, usages);
}
// Encryption should cause a single counter increment.
do_check_eq(c, 0);
let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv);
do_check_eq(c, 1);
cipherText = cryptoSvc.encrypt("Hello, world.", key, iv);
do_check_eq(c, 1);
// ... as should decryption.
cryptoSvc.decrypt(cipherText, key, iv);
cryptoSvc.decrypt(cipherText, key, iv);
cryptoSvc.decrypt(cipherText, key, iv);
do_check_eq(c, 2);
// Un-swizzle.
- cryptoSvc.nss.PK11_ImportSymKey = oldImport;
+ cryptoGlobal.subtle.importKey = oldImport;
}
function multiple_decrypts(iterations) {
let iv = cryptoSvc.generateRandomIV();
let key = cryptoSvc.generateRandomKey();
let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv);
for (let i = 0; i < iterations; ++i) {
@@ -73,42 +74,23 @@ function test_bug_617650() {
} else {
// We can't use gczeal on non-debug builds, so try lots of reps instead.
_("No gczeal (non-debug build?); attempting 10,000 iterations of multiple_decrypts.");
multiple_decrypts(10000);
}
}
// Just verify that it gets populated with the correct bytes.
-function test_makeSECItem() {
- Components.utils.import("resource://gre/modules/ctypes.jsm");
-
- let item1 = cryptoSvc.makeSECItem("abcdefghi", false);
- do_check_true(!item1.isNull());
- let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents;
- for (let i = 0; i < 8; ++i)
- do_check_eq(intData[i], "abcdefghi".charCodeAt(i));
-}
-
-function test_SECItem_byteCompressInts() {
+function test_makeUint8Array() {
Components.utils.import("resource://gre/modules/ctypes.jsm");
- let item1 = cryptoSvc.makeSECItem("abcdefghi", false);
- do_check_true(!item1.isNull());
- let intData = ctypes.cast(item1.contents.data, ctypes.uint8_t.array(8).ptr).contents;
-
- // Fill it too short.
- cryptoSvc.byteCompressInts("MMM", intData, 8);
- for (let i = 0; i < 3; ++i)
- do_check_eq(intData[i], [77, 77, 77][i]);
-
- // Fill it too much. Doesn't buffer overrun.
- cryptoSvc.byteCompressInts("NNNNNNNNNNNNNNNN", intData, 8);
+ let item1 = cryptoSvc.makeUint8Array("abcdefghi", false);
+ do_check_true(item1);
for (let i = 0; i < 8; ++i)
- do_check_eq(intData[i], "NNNNNNNNNNNNNNNN".charCodeAt(i));
+ do_check_eq(item1[i], "abcdefghi".charCodeAt(i));
}
function test_encrypt_decrypt() {
// First, do a normal run with expected usage... Generate a random key and
// iv, encrypt and decrypt a string.
var iv = cryptoSvc.generateRandomIV();
do_check_eq(iv.length, 24);
@@ -117,37 +99,46 @@ function test_encrypt_decrypt() {
do_check_eq(key.length, 44);
var mySecret = "bacon is a vegetable";
var cipherText = cryptoSvc.encrypt(mySecret, key, iv);
do_check_eq(cipherText.length, 44);
var clearText = cryptoSvc.decrypt(cipherText, key, iv);
do_check_eq(clearText.length, 20);
-
+
// Did the text survive the encryption round-trip?
do_check_eq(clearText, mySecret);
do_check_neq(cipherText, mySecret); // just to be explicit
// Do some more tests with a fixed key/iv, to check for reproducable results.
key = "St1tFCor7vQEJNug/465dQ==";
iv = "oLjkfrLIOnK2bDRvW4kXYA==";
_("Testing small IV.");
mySecret = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=";
- shortiv = "YWJj"; // "abc": Less than 16.
+ let shortiv = "YWJj";
let err;
try {
cryptoSvc.encrypt(mySecret, key, shortiv);
} catch (ex) {
err = ex;
}
do_check_true(!!err);
+ _("Testing long IV.");
+ let longiv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk=";
+ try {
+ cryptoSvc.encrypt(mySecret, key, longiv);
+ } catch (ex) {
+ err = ex;
+ }
+ do_check_true(!!err);
+
// Test small input sizes
mySecret = "";
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
clearText = cryptoSvc.decrypt(cipherText, key, iv);
do_check_eq(cipherText, "OGQjp6mK1a3fs9k9Ml4L3w==");
do_check_eq(clearText, mySecret);
mySecret = "x";
@@ -198,26 +189,26 @@ function test_encrypt_decrypt() {
mySecret = "12345678901234567";
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
clearText = cryptoSvc.decrypt(cipherText, key, iv);
do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP5GvxWJ9+GIAS6lXw+5fHTI=");
do_check_eq(clearText, mySecret);
key = "iz35tuIMq4/H+IYw2KTgow==";
- iv = "TJYrvva2KxvkM8hvOIvWp3xgjTXgq5Ss";
+ iv = "TJYrvva2KxvkM8hvOIvWp3==";
mySecret = "i like pie";
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
clearText = cryptoSvc.decrypt(cipherText, key, iv);
do_check_eq(cipherText, "DLGx8BWqSCLGG7i/xwvvxg==");
do_check_eq(clearText, mySecret);
key = "c5hG3YG+NC61FFy8NOHQak1ZhMEWO79bwiAfar2euzI=";
- iv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk=";
+ iv = "gsgLRDaxWvIfKt75RjuvFW==";
mySecret = "i like pie";
cipherText = cryptoSvc.encrypt(mySecret, key, iv);
clearText = cryptoSvc.decrypt(cipherText, key, iv);
do_check_eq(cipherText, "o+ADtdMd8ubzNWurS6jt0Q==");
do_check_eq(clearText, mySecret);
key = "St1tFCor7vQEJNug/465dQ==";