Index: include/apr_crypto.h
===================================================================
--- include/apr_crypto.h	(revision 1627411)
+++ include/apr_crypto.h	(working copy)
@@ -127,6 +127,47 @@
 typedef struct apr_crypto_key_t apr_crypto_key_t;
 typedef struct apr_crypto_block_t apr_crypto_block_t;
 
+typedef struct apr_crypto_block_key_type_t {
+    apr_crypto_block_key_type_e type;
+    int keysize;
+    int blocksize;
+} apr_crypto_block_key_type_t;
+
+typedef struct apr_crypto_block_key_mode_t {
+    apr_crypto_block_key_mode_e mode;
+} apr_crypto_block_key_mode_t;
+
+typedef struct apr_crypto_passphrase_t {
+    const char *pass;
+    apr_size_t passLen;
+    const unsigned char * salt;
+    apr_size_t saltLen;
+    int iterations;
+} apr_crypto_passphrase_t;
+
+typedef struct apr_crypto_secret_t {
+    const unsigned char *secret;
+    apr_size_t secretLen;
+} apr_crypto_secret_t;
+
+typedef enum {
+    /** Key is derived from a passphrase */
+    APR_CRYPTO_KTYPE_PASSPHRASE     = 1,
+    /** Key is derived from a raw key */
+    APR_CRYPTO_KTYPE_SECRET     = 2,
+} apr_crypto_key_type;
+
+typedef struct apr_crypto_key_rec_t {
+    apr_crypto_key_type ktype;
+    apr_crypto_block_key_type_e type;
+    apr_crypto_block_key_mode_e mode;
+    int pad;
+    union {
+        apr_crypto_passphrase_t passphrase;
+        apr_crypto_secret_t secret;
+    } k;
+} apr_crypto_key_rec_t;
+
 /**
  * @brief Perform once-only initialisation. Call once only.
  *
@@ -208,7 +249,7 @@
 
 /**
  * @brief Get a hash table of key types, keyed by the name of the type against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_type_t.
  *
  * @param types - hashtable of key types keyed to constants.
  * @param f - encryption context
@@ -219,7 +260,7 @@
 
 /**
  * @brief Get a hash table of key modes, keyed by the name of the mode against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_mode_t.
  *
  * @param modes - hashtable of key modes keyed to constants.
  * @param f - encryption context
@@ -229,6 +270,28 @@
         const apr_crypto_t *f);
 
 /**
+ * @brief Create a key from the provided secret or passphrase. The key is cleaned
+ *        up when the context is cleaned, and may be reused with multiple encryption
+ *        or decryption operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param rec The key record, from which the key will be derived.
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+APR_DECLARE(apr_status_t) apr_crypto_key(apr_crypto_key_t **key,
+        apr_size_t *ivSize, const apr_crypto_key_rec_t *rec,
+        const apr_crypto_t *f, apr_pool_t *p);
+
+/**
  * @brief Create a key from the given passphrase. By default, the PBKDF2
  *        algorithm is used to generate the key from the passphrase. It is expected
  *        that the same pass phrase will generate the same key, regardless of the
@@ -255,6 +318,7 @@
  *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
  *         not known. APR_EPADDING if padding was requested but is not supported.
  *         APR_ENOTIMPL if not implemented.
+ * @deprecated Replaced by apr_crypto_key().
  */
 APR_DECLARE(apr_status_t) apr_crypto_passphrase(apr_crypto_key_t **key,
         apr_size_t *ivSize, const char *pass, apr_size_t passLen,
Index: include/private/apr_crypto_internal.h
===================================================================
--- include/private/apr_crypto_internal.h	(revision 1627411)
+++ include/private/apr_crypto_internal.h	(working copy)
@@ -59,7 +59,7 @@
 
     /**
      * @brief Get a hash table of key types, keyed by the name of the type against
-     * an integer pointer constant.
+     * a pointer to apr_crypto_block_key_type_t.
      *
      * @param types - hashtable of key types keyed to constants.
      * @param f - encryption context
@@ -70,7 +70,7 @@
 
     /**
      * @brief Get a hash table of key modes, keyed by the name of the mode against
-     * an integer pointer constant.
+     * a pointer to apr_crypto_block_key_mode_t.
      *
      * @param modes - hashtable of key modes keyed to constants.
      * @param f - encryption context
@@ -267,6 +267,28 @@
      */
     apr_status_t (*error)(const apu_err_t **result, const apr_crypto_t *f);
 
+    /**
+     * @brief Create a key from the provided secret or passphrase. The key is cleaned
+     *        up when the context is cleaned, and may be reused with multiple encryption
+     *        or decryption operations.
+     * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+     *       *key is not NULL, *key must point at a previously created structure.
+     * @param key The key returned, see note.
+     * @param ivSize The size of the initialisation vector will be returned, based
+     *               on whether an IV is relevant for this type of crypto.
+     * @param rec The key record, from which the key will be derived.
+     * @param f The context to use.
+     * @param p The pool to use.
+     * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+     *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+     *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+     *         not known. APR_EPADDING if padding was requested but is not supported.
+     *         APR_ENOTIMPL if not implemented.
+     */
+    apr_status_t (*key)(apr_crypto_key_t **key, apr_size_t *ivSize,
+            const apr_crypto_key_rec_t *rec, const apr_crypto_t *f,
+            apr_pool_t *p);
+
 };
 
 #endif
Index: test/testcrypto.c
===================================================================
--- test/testcrypto.c	(revision 1627411)
+++ test/testcrypto.c	(working copy)
@@ -102,6 +102,59 @@
 
 }
 
+static const apr_crypto_key_t *keysecret(abts_case *tc, apr_pool_t *pool,
+        const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+        apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
+        int doPad, apr_size_t secretLen, const char *description)
+{
+    apr_crypto_key_t *key = NULL;
+    const apu_err_t *result = NULL;
+    apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t));
+    apr_status_t rv;
+
+    if (!f) {
+        return NULL;
+    }
+
+    rec->ktype = APR_CRYPTO_KTYPE_SECRET;
+    rec->type = type;
+    rec->mode = mode;
+    rec->pad = doPad;
+    rec->k.secret.secret = apr_pcalloc(pool, secretLen);
+    rec->k.secret.secretLen = secretLen;
+
+    /* init the passphrase */
+    rv = apr_crypto_key(&key, NULL, rec, f, pool);
+    if (APR_ENOCIPHER == rv) {
+        apr_crypto_error(&result, f);
+        ABTS_NOT_IMPL(tc,
+                apr_psprintf(pool, "skipped: %s %s key return APR_ENOCIPHER: error %d: %s (%s)\n", description, apr_crypto_driver_name(driver), result->rc, result->reason ? result->reason : "", result->msg ? result->msg : ""));
+        return NULL;
+    }
+    else {
+        if (APR_SUCCESS != rv) {
+            apr_crypto_error(&result, f);
+            fprintf(stderr, "key: %s %s apr error %d / native error %d: %s (%s)\n",
+                    description, apr_crypto_driver_name(driver), rv, result->rc,
+                    result->reason ? result->reason : "",
+                    result->msg ? result->msg : "");
+        }
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH);
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY);
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING",
+                rv != APR_EPADDING);
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE",
+                rv != APR_EKEYTYPE);
+        ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS);
+        ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL);
+    }
+    if (rv) {
+        return NULL;
+    }
+    return key;
+
+}
+
 static const apr_crypto_key_t *passphrase(abts_case *tc, apr_pool_t *pool,
         const apr_crypto_driver_t *driver, const apr_crypto_t *f,
         apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
@@ -133,8 +186,8 @@
     else {
         if (APR_SUCCESS != rv) {
             apr_crypto_error(&result, f);
-            fprintf(stderr, "passphrase: %s %s native error %d: %s (%s)\n",
-                    description, apr_crypto_driver_name(driver), result->rc,
+            fprintf(stderr, "passphrase: %s %s apr error %d / native error %d: %s (%s)\n",
+                    description, apr_crypto_driver_name(driver), rv, result->rc,
                     result->reason ? result->reason : "",
                     result->msg ? result->msg : "");
         }
@@ -151,6 +204,64 @@
 
 }
 
+static const apr_crypto_key_t *keypassphrase(abts_case *tc, apr_pool_t *pool,
+        const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+        apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
+        int doPad, const char *description)
+{
+
+    apr_crypto_key_t *key = NULL;
+    const apu_err_t *result = NULL;
+    const char *pass = "secret";
+    const char *salt = "salt";
+    apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t));
+    apr_status_t rv;
+
+    if (!f) {
+        return NULL;
+    }
+
+    rec->ktype = APR_CRYPTO_KTYPE_PASSPHRASE;
+    rec->type = type;
+    rec->mode = mode;
+    rec->pad = doPad;
+    rec->k.passphrase.pass = pass;
+    rec->k.passphrase.passLen = strlen(pass);
+    rec->k.passphrase.salt = (unsigned char *)salt;
+    rec->k.passphrase.saltLen = strlen(salt);
+    rec->k.passphrase.iterations = 4096;
+
+    /* init the passphrase */
+    rv = apr_crypto_key(&key, NULL, rec, f, pool);
+    if (APR_ENOCIPHER == rv) {
+        apr_crypto_error(&result, f);
+        ABTS_NOT_IMPL(tc, apr_psprintf(pool,
+                        "skipped: %s %s key passphrase return APR_ENOCIPHER: error %d: %s (%s)\n",
+                        description, apr_crypto_driver_name(driver), result->rc,
+                        result->reason ? result->reason : "", result->msg ? result->msg : ""));
+        return NULL;
+    }
+    else {
+        if (APR_SUCCESS != rv) {
+            apr_crypto_error(&result, f);
+            fprintf(stderr, "key passphrase: %s %s apr error %d / native error %d: %s (%s)\n",
+                    description, apr_crypto_driver_name(driver), rv, result->rc,
+                    result->reason ? result->reason : "",
+                    result->msg ? result->msg : "");
+        }
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY);
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING", rv != APR_EPADDING);
+        ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE", rv != APR_EKEYTYPE);
+        ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS);
+        ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL);
+    }
+    if (rv) {
+        return NULL;
+    }
+    return key;
+
+}
+
 static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool,
         const apr_crypto_driver_t *driver, const apr_crypto_t *f,
         const apr_crypto_key_t *key, const unsigned char *in,
@@ -340,7 +451,8 @@
         const apr_crypto_driver_t **drivers,
         const apr_crypto_block_key_type_e type,
         const apr_crypto_block_key_mode_e mode, int doPad,
-        const unsigned char *in, apr_size_t inlen, const char *description)
+        const unsigned char *in, apr_size_t inlen, apr_size_t secretLen,
+        const char *description)
 {
     const apr_crypto_driver_t *driver1 = drivers[0];
     const apr_crypto_driver_t *driver2 = drivers[1];
@@ -348,6 +460,10 @@
     apr_crypto_t *f2 = NULL;
     const apr_crypto_key_t *key1 = NULL;
     const apr_crypto_key_t *key2 = NULL;
+    const apr_crypto_key_t *key3 = NULL;
+    const apr_crypto_key_t *key4 = NULL;
+    const apr_crypto_key_t *key5 = NULL;
+    const apr_crypto_key_t *key6 = NULL;
 
     unsigned char *cipherText = NULL;
     apr_size_t cipherTextLen = 0;
@@ -369,13 +485,49 @@
 
     if (cipherText && plainText) {
         if (memcmp(in, plainText, inlen)) {
-            fprintf(stderr, "cross mismatch: %s %s/%s\n", description,
+            fprintf(stderr, "passphrase cross mismatch: %s %s/%s\n", description,
                     apr_crypto_driver_name(driver1), apr_crypto_driver_name(
                             driver2));
         }
         ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText);
     }
 
+    key3 = keysecret(tc, pool, driver1, f1, type, mode, doPad, secretLen, description);
+    key4 = keysecret(tc, pool, driver2, f2, type, mode, doPad, secretLen, description);
+
+    cipherText = encrypt_block(tc, pool, driver1, f1, key3, in, inlen,
+            &cipherText, &cipherTextLen, &iv, &blockSize, description);
+    plainText = decrypt_block(tc, pool, driver2, f2, key4, cipherText,
+            cipherTextLen, &plainText, &plainTextLen, iv, &blockSize,
+            description);
+
+    if (cipherText && plainText) {
+        if (memcmp(in, plainText, inlen)) {
+            fprintf(stderr, "key secret cross mismatch: %s %s/%s\n", description,
+                    apr_crypto_driver_name(driver1), apr_crypto_driver_name(
+                            driver2));
+        }
+        ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText);
+    }
+
+    key5 = keypassphrase(tc, pool, driver1, f1, type, mode, doPad, description);
+    key6 = keypassphrase(tc, pool, driver2, f2, type, mode, doPad, description);
+
+    cipherText = encrypt_block(tc, pool, driver1, f1, key3, in, inlen,
+            &cipherText, &cipherTextLen, &iv, &blockSize, description);
+    plainText = decrypt_block(tc, pool, driver2, f2, key4, cipherText,
+            cipherTextLen, &plainText, &plainTextLen, iv, &blockSize,
+            description);
+
+    if (cipherText && plainText) {
+        if (memcmp(in, plainText, inlen)) {
+            fprintf(stderr, "key passphrase cross mismatch: %s %s/%s\n", description,
+                    apr_crypto_driver_name(driver1), apr_crypto_driver_name(
+                            driver2));
+        }
+        ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText);
+    }
+
 }
 
 /**
@@ -396,6 +548,63 @@
 }
 
 /**
+ * Simple test of OpenSSL key.
+ */
+static void test_crypto_key_openssl(abts_case *tc, void *data)
+{
+    apr_pool_t *pool = NULL;
+    const apr_crypto_driver_t *driver;
+    apr_crypto_t *f = NULL;
+
+    apr_pool_create(&pool, NULL);
+    driver = get_openssl_driver(tc, pool);
+
+    f = make(tc, pool, driver);
+    keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32,
+            "KEY_AES_256/MODE_CBC");
+    apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of NSS key.
+ */
+static void test_crypto_key_nss(abts_case *tc, void *data)
+{
+    apr_pool_t *pool = NULL;
+    const apr_crypto_driver_t *driver;
+    apr_crypto_t *f = NULL;
+
+    apr_pool_create(&pool, NULL);
+    driver = get_nss_driver(tc, pool);
+
+    f = make(tc, pool, driver);
+    keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32,
+            "KEY_AES_256/MODE_CBC");
+    apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of CommonCrypto key.
+ */
+static void test_crypto_key_commoncrypto(abts_case *tc, void *data)
+{
+    apr_pool_t *pool = NULL;
+    const apr_crypto_driver_t *driver;
+    apr_crypto_t *f = NULL;
+
+    apr_pool_create(&pool, NULL);
+    driver = get_commoncrypto_driver(tc, pool);
+
+    f = make(tc, pool, driver);
+    keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32,
+            "KEY_AES_256/MODE_CBC");
+    apr_pool_destroy(pool);
+
+}
+
+/**
  * Simple test of OpenSSL block crypt.
  */
 static void test_crypto_block_openssl(abts_case *tc, void *data)
@@ -410,21 +619,21 @@
     drivers[0] = get_openssl_driver(tc, pool);
     drivers[1] = get_openssl_driver(tc, pool);
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0,
-            in, inlen, "KEY_3DES_192/MODE_ECB");
+            in, inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -444,21 +653,21 @@
     drivers[0] = get_nss_driver(tc, pool);
     drivers[1] = get_nss_driver(tc, pool);
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
     /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
     /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -478,21 +687,21 @@
     drivers[0] = get_commoncrypto_driver(tc, pool);
     drivers[1] = get_commoncrypto_driver(tc, pool);
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0,
-            in, inlen, "KEY_3DES_192/MODE_ECB");
+            in, inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -513,22 +722,22 @@
     drivers[1] = get_openssl_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
 
     /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
-    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -548,23 +757,23 @@
     drivers[0] = get_openssl_driver(tc, pool);
     drivers[1] = get_nss_driver(tc, pool);
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
 
     /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
-    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -586,21 +795,21 @@
     drivers[1] = get_commoncrypto_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_3DES_192/MODE_CBC");
+            inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_3DES_192/MODE_ECB");
+            inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -622,21 +831,21 @@
     drivers[1] = get_openssl_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_3DES_192/MODE_CBC");
+            inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_3DES_192/MODE_ECB");
+            inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
     apr_pool_destroy(pool);
 
 }
@@ -657,21 +866,21 @@
     drivers[1] = get_openssl_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1,
-            in, inlen, "KEY_3DES_192/MODE_ECB");
+            in, inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
 
     apr_pool_destroy(pool);
 
@@ -694,27 +903,27 @@
     drivers[1] = get_nss_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
     /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
-    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
 
     /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
-    /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, "KEY_AES_256/MODE_ECB");*/
+    /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
 
     /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
-    /*crypto_block_cross(tc, pool, drivers, KEY_AES_192, MODE_ECB, 1, in, inlen, "KEY_AES_192/MODE_ECB");*/
+    /*crypto_block_cross(tc, pool, drivers, KEY_AES_192, MODE_ECB, 1, in, inlen, 24, "KEY_AES_192/MODE_ECB");*/
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
 
     /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
-    /*crypto_block_cross(tc, pool, drivers, KEY_AES_128, MODE_ECB, 1, in, inlen, "KEY_AES_128/MODE_ECB");*/
+    /*crypto_block_cross(tc, pool, drivers, KEY_AES_128, MODE_ECB, 1, in, inlen, 16, "KEY_AES_128/MODE_ECB");*/
 
     apr_pool_destroy(pool);
 
@@ -736,21 +945,21 @@
     drivers[1] = get_commoncrypto_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1,
-            in, inlen, "KEY_3DES_192/MODE_ECB");
+            in, inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
 
     apr_pool_destroy(pool);
 
@@ -772,30 +981,30 @@
     drivers[1] = get_openssl_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
 
     /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
-    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
 
     /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
-    /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, "KEY_AES_256/MODE_ECB");*/
+    /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
 
     /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */
     /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_192/MODE_ECB");*/
+            inlen, 24, "KEY_AES_192/MODE_ECB");*/
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
 
     /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */
     /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_128/MODE_ECB");*/
+            inlen, 16, "KEY_AES_128/MODE_ECB");*/
 
     apr_pool_destroy(pool);
 
@@ -816,30 +1025,30 @@
     drivers[0] = get_openssl_driver(tc, pool);
     drivers[1] = get_nss_driver(tc, pool);
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
-            in, inlen, "KEY_3DES_192/MODE_CBC");
+            in, inlen, 24, "KEY_3DES_192/MODE_CBC");
 
     /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
-    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+    /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
 
     /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
-    /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, "KEY_AES_256/MODE_ECB");*/
+    /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, inlen,
-            "KEY_AES_192/MODE_CBC");
+            24, "KEY_AES_192/MODE_CBC");
 
     /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */
     /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, inlen,
-            "KEY_AES_192/MODE_ECB");*/
+            24, "KEY_AES_192/MODE_ECB");*/
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, inlen,
-            "KEY_AES_128/MODE_CBC");
+            16, "KEY_AES_128/MODE_CBC");
 
     /* KEY_AES_128 / MODE_ECB doesn't support padding on NSS */
     /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, inlen,
-            "KEY_AES_128/MODE_ECB");*/
+            16, "KEY_AES_128/MODE_ECB");*/
 
     apr_pool_destroy(pool);
 
@@ -863,21 +1072,21 @@
     drivers[1] = get_openssl_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_3DES_192/MODE_CBC");
+            inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_3DES_192/MODE_ECB");
+            inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
 
     apr_pool_destroy(pool);
 
@@ -901,21 +1110,21 @@
     drivers[1] = get_commoncrypto_driver(tc, pool);
 
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_3DES_192/MODE_CBC");
+            inlen, 24, "KEY_3DES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_3DES_192/MODE_ECB");
+            inlen, 24, "KEY_3DES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_256/MODE_CBC");
+            inlen, 32, "KEY_AES_256/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_256/MODE_ECB");
+            inlen, 32, "KEY_AES_256/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_192/MODE_CBC");
+            inlen, 24, "KEY_AES_192/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_192/MODE_ECB");
+            inlen, 24, "KEY_AES_192/MODE_ECB");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
-            inlen, "KEY_AES_128/MODE_CBC");
+            inlen, 16, "KEY_AES_128/MODE_CBC");
     crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
-            inlen, "KEY_AES_128/MODE_ECB");
+            inlen, 16, "KEY_AES_128/MODE_ECB");
 
     apr_pool_destroy(pool);
 
@@ -1156,6 +1365,15 @@
     /* test simple init and shutdown */
     abts_run_test(suite, test_crypto_init, NULL);
 
+    /* test key parsing - openssl */
+    abts_run_test(suite, test_crypto_key_openssl, NULL);
+
+    /* test key parsing - nss */
+    abts_run_test(suite, test_crypto_key_nss, NULL);
+
+    /* test key parsing - commoncrypto */
+    abts_run_test(suite, test_crypto_key_commoncrypto, NULL);
+
     /* test a simple encrypt / decrypt operation - openssl */
     abts_run_test(suite, test_crypto_block_openssl, NULL);
 
Index: crypto/apr_crypto.c
===================================================================
--- crypto/apr_crypto.c	(revision 1627411)
+++ crypto/apr_crypto.c	(working copy)
@@ -286,7 +286,7 @@
 
 /**
  * @brief Get a hash table of key types, keyed by the name of the type against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_type_t.
  *
  * @param types - hashtable of key types keyed to constants.
  * @param f - encryption context
@@ -300,7 +300,7 @@
 
 /**
  * @brief Get a hash table of key modes, keyed by the name of the mode against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_mode_t.
  *
  * @param modes - hashtable of key modes keyed to constants.
  * @param f - encryption context
@@ -313,6 +313,31 @@
 }
 
 /**
+ * @brief Create a key from the provided secret or passphrase. The key is cleaned
+ *        up when the context is cleaned, and may be reused with multiple encryption
+ *        or decryption operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param rec The key record, from which the key will be derived.
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+APR_DECLARE(apr_status_t) apr_crypto_key(apr_crypto_key_t **key,
+        apr_size_t *ivSize, const apr_crypto_key_rec_t *rec,
+        const apr_crypto_t *f, apr_pool_t *p)
+{
+    return f->provider->key(key, ivSize, rec, f, p);
+}
+
+/**
  * @brief Create a key from the given passphrase. By default, the PBKDF2
  *        algorithm is used to generate the key from the passphrase. It is expected
  *        that the same pass phrase will generate the same key, regardless of the
Index: crypto/apr_crypto_commoncrypto.c
===================================================================
--- crypto/apr_crypto_commoncrypto.c	(revision 1627411)
+++ crypto/apr_crypto_commoncrypto.c	(working copy)
@@ -69,13 +69,17 @@
     CCCryptorRef ref;
 };
 
-static int key_3des_192 = APR_KEY_3DES_192;
-static int key_aes_128 = APR_KEY_AES_128;
-static int key_aes_192 = APR_KEY_AES_192;
-static int key_aes_256 = APR_KEY_AES_256;
+static struct apr_crypto_block_key_type_t key_types[] =
+{
+{ APR_KEY_3DES_192, 24, 8 },
+{ APR_KEY_AES_128, 16, 16 },
+{ APR_KEY_AES_192, 24, 16 },
+{ APR_KEY_AES_256, 32, 16 } };
 
-static int mode_ecb = APR_MODE_ECB;
-static int mode_cbc = APR_MODE_CBC;
+static struct apr_crypto_block_key_mode_t key_modes[] =
+{
+{ APR_MODE_ECB },
+{ APR_MODE_CBC } };
 
 /**
  * Fetch the most recent error from this driver.
@@ -211,17 +215,17 @@
     if (!f->types) {
         return APR_ENOMEM;
     }
-    apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_3des_192));
-    apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_aes_128));
-    apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_aes_192));
-    apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_aes_256));
+    apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0]));
+    apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1]));
+    apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2]));
+    apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3]));
 
     f->modes = apr_hash_make(pool);
     if (!f->modes) {
         return APR_ENOMEM;
     }
-    apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(mode_ecb));
-    apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(mode_cbc));
+    apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0]));
+    apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1]));
 
     apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
             apr_pool_cleanup_null);
@@ -232,7 +236,7 @@
 
 /**
  * @brief Get a hash table of key types, keyed by the name of the type against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_type_t.
  *
  * @param types - hashtable of key types keyed to constants.
  * @param f - encryption context
@@ -247,7 +251,7 @@
 
 /**
  * @brief Get a hash table of key modes, keyed by the name of the mode against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_mode_t.
  *
  * @param modes - hashtable of key modes keyed to constants.
  * @param f - encryption context
@@ -260,52 +264,13 @@
     return APR_SUCCESS;
 }
 
-/**
- * @brief Create a key from the given passphrase. By default, the PBKDF2
- *        algorithm is used to generate the key from the passphrase. It is expected
- *        that the same pass phrase will generate the same key, regardless of the
- *        backend crypto platform used. The key is cleaned up when the context
- *        is cleaned, and may be reused with multiple encryption or decryption
- *        operations.
- * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
- *       *key is not NULL, *key must point at a previously created structure.
- * @param key The key returned, see note.
- * @param ivSize The size of the initialisation vector will be returned, based
- *               on whether an IV is relevant for this type of crypto.
- * @param pass The passphrase to use.
- * @param passLen The passphrase length in bytes
- * @param salt The salt to use.
- * @param saltLen The salt length in bytes
- * @param type 3DES_192, AES_128, AES_192, AES_256.
- * @param mode Electronic Code Book / Cipher Block Chaining.
- * @param doPad Pad if necessary.
- * @param iterations Iteration count
- * @param f The context to use.
- * @param p The pool to use.
- * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
- *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
- *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
- *         not known. APR_EPADDING if padding was requested but is not supported.
- *         APR_ENOTIMPL if not implemented.
+/*
+ * Work out which mechanism to use.
  */
-static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
-        const char *pass, apr_size_t passLen, const unsigned char * salt,
-        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
-        const apr_crypto_block_key_mode_e mode, const int doPad,
-        const int iterations, const apr_crypto_t *f, apr_pool_t *p)
+static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key,
+        const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad, apr_pool_t *p)
 {
-    apr_crypto_key_t *key = *k;
-
-    if (!key) {
-        *k = key = apr_array_push(f->keys);
-    }
-    if (!key) {
-        return APR_ENOMEM;
-    }
-
-    key->f = f;
-    key->provider = f->provider;
-
     /* handle padding */
     key->options = doPad ? kCCOptionPKCS7Padding : 0;
 
@@ -391,12 +356,151 @@
     }
 
     /* make space for the key */
-    key->key = apr_pcalloc(p, key->keyLen);
+    key->key = apr_palloc(p, key->keyLen);
     if (!key->key) {
         return APR_ENOMEM;
     }
     apr_crypto_clear(p, key->key, key->keyLen);
 
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Create a key from the provided secret or passphrase. The key is cleaned
+ *        up when the context is cleaned, and may be reused with multiple encryption
+ *        or decryption operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param rec The key record, from which the key will be derived.
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_key(apr_crypto_key_t **k, apr_size_t *ivSize,
+        const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p)
+{
+    apr_status_t rv;
+    apr_crypto_key_t *key = *k;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    key->f = f;
+    key->provider = f->provider;
+
+    /* decide on what cipher mechanism we will be using */
+    rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+
+    switch (rec->ktype) {
+
+    case APR_CRYPTO_KTYPE_PASSPHRASE: {
+
+        /* generate the key */
+        if ((f->result->rc = CCKeyDerivationPBKDF(kCCPBKDF2,
+                rec->k.passphrase.pass, rec->k.passphrase.passLen,
+                rec->k.passphrase.salt, rec->k.passphrase.saltLen,
+                kCCPRFHmacAlgSHA1, rec->k.passphrase.iterations, key->key,
+                key->keyLen)) == kCCParamError) {
+            return APR_ENOKEY;
+        }
+
+        break;
+    }
+
+    case APR_CRYPTO_KTYPE_SECRET: {
+
+        /* sanity check - key correct size? */
+        if (rec->k.secret.secretLen != key->keyLen) {
+            return APR_EKEYLENGTH;
+        }
+
+        /* copy the key */
+        memcpy(key->key, rec->k.secret.secret, rec->k.secret.secretLen);
+
+        break;
+    }
+
+    default: {
+
+        return APR_ENOKEY;
+
+    }
+    }
+
+    if (ivSize) {
+        *ivSize = key->ivSize;
+    }
+
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Create a key from the given passphrase. By default, the PBKDF2
+ *        algorithm is used to generate the key from the passphrase. It is expected
+ *        that the same pass phrase will generate the same key, regardless of the
+ *        backend crypto platform used. The key is cleaned up when the context
+ *        is cleaned, and may be reused with multiple encryption or decryption
+ *        operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param pass The passphrase to use.
+ * @param passLen The passphrase length in bytes
+ * @param salt The salt to use.
+ * @param saltLen The salt length in bytes
+ * @param type 3DES_192, AES_128, AES_192, AES_256.
+ * @param mode Electronic Code Book / Cipher Block Chaining.
+ * @param doPad Pad if necessary.
+ * @param iterations Iteration count
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
+        const char *pass, apr_size_t passLen, const unsigned char * salt,
+        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad,
+        const int iterations, const apr_crypto_t *f, apr_pool_t *p)
+{
+    apr_status_t rv;
+    apr_crypto_key_t *key = *k;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    key->f = f;
+    key->provider = f->provider;
+
+    /* decide on what cipher mechanism we will be using */
+    rv = crypto_cipher_mechanism(key, type, mode, doPad, p);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+
     /* generate the key */
     if ((f->result->rc = CCKeyDerivationPBKDF(kCCPBKDF2, pass, passLen, salt,
             saltLen, kCCPRFHmacAlgSHA1, iterations, key->key, key->keyLen))
@@ -808,7 +912,7 @@
         crypto_block_encrypt_init, crypto_block_encrypt,
         crypto_block_encrypt_finish, crypto_block_decrypt_init,
         crypto_block_decrypt, crypto_block_decrypt_finish, crypto_block_cleanup,
-        crypto_cleanup, crypto_shutdown, crypto_error
+        crypto_cleanup, crypto_shutdown, crypto_error, crypto_key
 };
 
 #endif
Index: crypto/apr_crypto_nss.c
===================================================================
--- crypto/apr_crypto_nss.c	(revision 1627411)
+++ crypto/apr_crypto_nss.c	(working copy)
@@ -80,14 +80,21 @@
     int blockSize;
 };
 
-static int key_3des_192 = APR_KEY_3DES_192;
-static int key_aes_128 = APR_KEY_AES_128;
-static int key_aes_192 = APR_KEY_AES_192;
-static int key_aes_256 = APR_KEY_AES_256;
+static struct apr_crypto_block_key_type_t key_types[] =
+{
+{ APR_KEY_3DES_192, 24, 8 },
+{ APR_KEY_AES_128, 16, 16 },
+{ APR_KEY_AES_192, 24, 16 },
+{ APR_KEY_AES_256, 32, 16 } };
 
-static int mode_ecb = APR_MODE_ECB;
-static int mode_cbc = APR_MODE_CBC;
+static struct apr_crypto_block_key_mode_t key_modes[] =
+{
+{ APR_MODE_ECB },
+{ APR_MODE_CBC } };
 
+/* sufficient space to wrap a key */
+#define BUFFER_SIZE 128
+
 /**
  * Fetch the most recent error from this driver.
  */
@@ -315,17 +322,17 @@
     if (!f->types) {
         return APR_ENOMEM;
     }
-    apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_3des_192));
-    apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_aes_128));
-    apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_aes_192));
-    apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_aes_256));
+    apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0]));
+    apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1]));
+    apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2]));
+    apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3]));
 
     f->modes = apr_hash_make(pool);
     if (!f->modes) {
         return APR_ENOMEM;
     }
-    apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(mode_ecb));
-    apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(mode_cbc));
+    apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0]));
+    apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1]));
 
     apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
             apr_pool_cleanup_null);
@@ -336,7 +343,7 @@
 
 /**
  * @brief Get a hash table of key types, keyed by the name of the type against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_type_t.
  *
  * @param types - hashtable of key types keyed to constants.
  * @param f - encryption context
@@ -351,7 +358,7 @@
 
 /**
  * @brief Get a hash table of key modes, keyed by the name of the mode against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_mode_t.
  *
  * @param modes - hashtable of key modes keyed to constants.
  * @param f - encryption context
@@ -364,58 +371,14 @@
     return APR_SUCCESS;
 }
 
-/**
- * @brief Create a key from the given passphrase. By default, the PBKDF2
- *        algorithm is used to generate the key from the passphrase. It is expected
- *        that the same pass phrase will generate the same key, regardless of the
- *        backend crypto platform used. The key is cleaned up when the context
- *        is cleaned, and may be reused with multiple encryption or decryption
- *        operations.
- * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
- *       *key is not NULL, *key must point at a previously created structure.
- * @param key The key returned, see note.
- * @param ivSize The size of the initialisation vector will be returned, based
- *               on whether an IV is relevant for this type of crypto.
- * @param pass The passphrase to use.
- * @param passLen The passphrase length in bytes
- * @param salt The salt to use.
- * @param saltLen The salt length in bytes
- * @param type 3DES_192, AES_128, AES_192, AES_256.
- * @param mode Electronic Code Book / Cipher Block Chaining.
- * @param doPad Pad if necessary.
- * @param iterations Iteration count
- * @param f The context to use.
- * @param p The pool to use.
- * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
- *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
- *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
- *         not known. APR_EPADDING if padding was requested but is not supported.
- *         APR_ENOTIMPL if not implemented.
+/*
+ * Work out which mechanism to use.
  */
-static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
-        const char *pass, apr_size_t passLen, const unsigned char * salt,
-        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
-        const apr_crypto_block_key_mode_e mode, const int doPad,
-        const int iterations, const apr_crypto_t *f, apr_pool_t *p)
+static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key,
+        const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad)
 {
-    apr_status_t rv = APR_SUCCESS;
-    PK11SlotInfo * slot;
-    SECItem passItem;
-    SECItem saltItem;
-    SECAlgorithmID *algid;
-    void *wincx = NULL; /* what is wincx? */
-    apr_crypto_key_t *key = *k;
 
-    if (!key) {
-        *k = key = apr_array_push(f->keys);
-    }
-    if (!key) {
-        return APR_ENOMEM;
-    }
-
-    key->f = f;
-    key->provider = f->provider;
-
     /* decide on what cipher mechanism we will be using */
     switch (type) {
 
@@ -469,13 +432,266 @@
     if (doPad) {
         CK_MECHANISM_TYPE paddedMech;
         paddedMech = PK11_GetPadMechanism(key->cipherMech);
-        if (CKM_INVALID_MECHANISM == paddedMech || key->cipherMech
-                == paddedMech) {
+        if (CKM_INVALID_MECHANISM == paddedMech
+                || key->cipherMech == paddedMech) {
             return APR_EPADDING;
         }
         key->cipherMech = paddedMech;
     }
 
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Create a key from the provided secret or passphrase. The key is cleaned
+ *        up when the context is cleaned, and may be reused with multiple encryption
+ *        or decryption operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param rec The key record, from which the key will be derived.
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_key(apr_crypto_key_t **k, apr_size_t *ivSize,
+        const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p)
+{
+    apr_status_t rv = APR_SUCCESS;
+    PK11SlotInfo *slot, *tslot;
+    PK11SymKey *tkey;
+    SECItem secretItem;
+    SECItem wrappedItem;
+    SECItem *secParam;
+    PK11Context *ctx;
+    SECStatus s;
+    SECItem passItem;
+    SECItem saltItem;
+    SECAlgorithmID *algid;
+    void *wincx = NULL; /* what is wincx? */
+    apr_crypto_key_t *key;
+    int blockSize;
+    int remainder;
+
+    key = *k;
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    key->f = f;
+    key->provider = f->provider;
+
+    /* decide on what cipher mechanism we will be using */
+    rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+
+    switch (rec->ktype) {
+
+    case APR_CRYPTO_KTYPE_PASSPHRASE: {
+
+        /* Turn the raw passphrase and salt into SECItems */
+        passItem.data = (unsigned char*) rec->k.passphrase.pass;
+        passItem.len = rec->k.passphrase.passLen;
+        saltItem.data = (unsigned char*) rec->k.passphrase.salt;
+        saltItem.len = rec->k.passphrase.saltLen;
+
+        /* generate the key */
+        /* pbeAlg and cipherAlg are the same. */
+        algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid,
+                SEC_OID_HMAC_SHA1, key->keyLength,
+                rec->k.passphrase.iterations, &saltItem);
+        if (algid) {
+            slot = PK11_GetBestSlot(key->cipherMech, wincx);
+            if (slot) {
+                key->symKey = PK11_PBEKeyGen(slot, algid, &passItem, PR_FALSE,
+                        wincx);
+                PK11_FreeSlot(slot);
+            }
+            SECOID_DestroyAlgorithmID(algid, PR_TRUE);
+        }
+
+        break;
+    }
+
+    case APR_CRYPTO_KTYPE_SECRET: {
+
+        /*
+         * NSS is by default in FIPS mode, which disallows the use of unencrypted
+         * symmetrical keys. As per http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947
+         * we do the following:
+         *
+         * 1. Generate a (temporary) symmetric key in NSS.
+         * 2. Use that symmetric key to encrypt your symmetric key as data.
+         * 3. Unwrap your wrapped symmetric key, using the symmetric key
+         * you generated in Step 1 as the unwrapping key.
+         *
+         * http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947
+         */
+
+        /* generate the key */
+        slot = PK11_GetBestSlot(key->cipherMech, NULL);
+        if (slot) {
+            unsigned char data[BUFFER_SIZE];
+
+            /* sanity check - key correct size? */
+            if (rec->k.secret.secretLen != key->keyLength) {
+                PK11_FreeSlot(slot);
+                return APR_EKEYLENGTH;
+            }
+
+            tslot = PK11_GetBestSlot(CKM_AES_ECB, NULL);
+            if (tslot) {
+
+                /* generate a temporary wrapping key */
+                tkey = PK11_KeyGen(tslot, CKM_AES_ECB, 0, key->keyLength, 0);
+
+                /* prepare the key to wrap */
+                secretItem.data = (unsigned char *) rec->k.secret.secret;
+                secretItem.len = rec->k.secret.secretLen;
+
+                /* ensure our key matches the blocksize */
+                secParam = PK11_GenerateNewParam(CKM_AES_ECB, tkey);
+                blockSize = PK11_GetBlockSize(CKM_AES_ECB, secParam);
+                remainder = rec->k.secret.secretLen % blockSize;
+                if (remainder) {
+                    secretItem.data =
+                            apr_pcalloc(p, rec->k.secret.secretLen + remainder);
+                    apr_crypto_clear(p, secretItem.data,
+                            rec->k.secret.secretLen);
+                    memcpy(secretItem.data, rec->k.secret.secret,
+                            rec->k.secret.secretLen);
+                    secretItem.len += remainder;
+                }
+
+                /* prepare a space for the wrapped key */
+                wrappedItem.data = data;
+
+                /* wrap the key */
+                ctx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, tkey,
+                        secParam);
+                if (ctx) {
+                    s = PK11_CipherOp(ctx, wrappedItem.data,
+                            (int *) (&wrappedItem.len), BUFFER_SIZE,
+                            secretItem.data, secretItem.len);
+                    if (s == SECSuccess) {
+
+                        /* unwrap the key again */
+                        key->symKey = PK11_UnwrapSymKeyWithFlags(tkey,
+                                CKM_AES_ECB, NULL, &wrappedItem,
+                                key->cipherMech, CKA_ENCRYPT,
+                                rec->k.secret.secretLen, 0);
+
+                    }
+
+                    PK11_DestroyContext(ctx, PR_TRUE);
+                }
+
+                /* clean up */
+                PK11_FreeSymKey(tkey);
+                PK11_FreeSlot(tslot);
+
+            }
+
+            PK11_FreeSlot(slot);
+        }
+
+        break;
+    }
+
+    default: {
+
+        return APR_ENOKEY;
+
+    }
+    }
+
+    /* sanity check? */
+    if (!key->symKey) {
+        PRErrorCode perr = PORT_GetError();
+        if (perr) {
+            f->result->rc = perr;
+            f->result->msg = PR_ErrorToName(perr);
+            rv = APR_ENOKEY;
+        }
+    }
+
+    key->ivSize = PK11_GetIVLength(key->cipherMech);
+    if (ivSize) {
+        *ivSize = key->ivSize;
+    }
+
+    return rv;
+}
+
+/**
+ * @brief Create a key from the given passphrase. By default, the PBKDF2
+ *        algorithm is used to generate the key from the passphrase. It is expected
+ *        that the same pass phrase will generate the same key, regardless of the
+ *        backend crypto platform used. The key is cleaned up when the context
+ *        is cleaned, and may be reused with multiple encryption or decryption
+ *        operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param pass The passphrase to use.
+ * @param passLen The passphrase length in bytes
+ * @param salt The salt to use.
+ * @param saltLen The salt length in bytes
+ * @param type 3DES_192, AES_128, AES_192, AES_256.
+ * @param mode Electronic Code Book / Cipher Block Chaining.
+ * @param doPad Pad if necessary.
+ * @param iterations Iteration count
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
+        const char *pass, apr_size_t passLen, const unsigned char * salt,
+        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad,
+        const int iterations, const apr_crypto_t *f, apr_pool_t *p)
+{
+    apr_status_t rv = APR_SUCCESS;
+    PK11SlotInfo * slot;
+    SECItem passItem;
+    SECItem saltItem;
+    SECAlgorithmID *algid;
+    void *wincx = NULL; /* what is wincx? */
+    apr_crypto_key_t *key = *k;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    key->f = f;
+    key->provider = f->provider;
+
+    /* decide on what cipher mechanism we will be using */
+    rv = crypto_cipher_mechanism(key, type, mode, doPad);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+
     /* Turn the raw passphrase and salt into SECItems */
     passItem.data = (unsigned char*) pass;
     passItem.len = passLen;
@@ -869,7 +1085,8 @@
     crypto_block_encrypt_init, crypto_block_encrypt,
     crypto_block_encrypt_finish, crypto_block_decrypt_init,
     crypto_block_decrypt, crypto_block_decrypt_finish,
-    crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error
+    crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error,
+    crypto_key
 };
 
 #endif
Index: crypto/apr_crypto_openssl.c
===================================================================
--- crypto/apr_crypto_openssl.c	(revision 1627411)
+++ crypto/apr_crypto_openssl.c	(working copy)
@@ -72,14 +72,21 @@
     int doPad;
 };
 
-static int key_3des_192 = APR_KEY_3DES_192;
-static int key_aes_128 = APR_KEY_AES_128;
-static int key_aes_192 = APR_KEY_AES_192;
-static int key_aes_256 = APR_KEY_AES_256;
+static struct apr_crypto_block_key_type_t key_types[] =
+{
+{ APR_KEY_3DES_192, 24, 8 },
+{ APR_KEY_AES_128, 16, 16 },
+{ APR_KEY_AES_192, 24, 16 },
+{ APR_KEY_AES_256, 32, 16 } };
 
-static int mode_ecb = APR_MODE_ECB;
-static int mode_cbc = APR_MODE_CBC;
+static struct apr_crypto_block_key_mode_t key_modes[] =
+{
+{ APR_MODE_ECB },
+{ APR_MODE_CBC } };
 
+/* sufficient space to wrap a key */
+#define BUFFER_SIZE 128
+
 /**
  * Fetch the most recent error from this driver.
  */
@@ -266,17 +273,17 @@
     if (!f->types) {
         return APR_ENOMEM;
     }
-    apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_3des_192));
-    apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_aes_128));
-    apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_aes_192));
-    apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_aes_256));
+    apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0]));
+    apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1]));
+    apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2]));
+    apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3]));
 
     f->modes = apr_hash_make(pool);
     if (!f->modes) {
         return APR_ENOMEM;
     }
-    apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(mode_ecb));
-    apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(mode_cbc));
+    apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0]));
+    apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1]));
 
     apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
             apr_pool_cleanup_null);
@@ -299,7 +306,7 @@
 
 /**
  * @brief Get a hash table of key types, keyed by the name of the type against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_type_t.
  *
  * @param types - hashtable of key types keyed to constants.
  * @param f - encryption context
@@ -314,7 +321,7 @@
 
 /**
  * @brief Get a hash table of key modes, keyed by the name of the mode against
- * an integer pointer constant.
+ * a pointer to apr_crypto_block_key_mode_t.
  *
  * @param modes - hashtable of key modes keyed to constants.
  * @param f - encryption context
@@ -327,52 +334,13 @@
     return APR_SUCCESS;
 }
 
-/**
- * @brief Create a key from the given passphrase. By default, the PBKDF2
- *        algorithm is used to generate the key from the passphrase. It is expected
- *        that the same pass phrase will generate the same key, regardless of the
- *        backend crypto platform used. The key is cleaned up when the context
- *        is cleaned, and may be reused with multiple encryption or decryption
- *        operations.
- * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
- *       *key is not NULL, *key must point at a previously created structure.
- * @param key The key returned, see note.
- * @param ivSize The size of the initialisation vector will be returned, based
- *               on whether an IV is relevant for this type of crypto.
- * @param pass The passphrase to use.
- * @param passLen The passphrase length in bytes
- * @param salt The salt to use.
- * @param saltLen The salt length in bytes
- * @param type 3DES_192, AES_128, AES_192, AES_256.
- * @param mode Electronic Code Book / Cipher Block Chaining.
- * @param doPad Pad if necessary.
- * @param iterations Iteration count
- * @param f The context to use.
- * @param p The pool to use.
- * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
- *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
- *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
- *         not known. APR_EPADDING if padding was requested but is not supported.
- *         APR_ENOTIMPL if not implemented.
+/*
+ * Work out which mechanism to use.
  */
-static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
-        const char *pass, apr_size_t passLen, const unsigned char * salt,
-        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
-        const apr_crypto_block_key_mode_e mode, const int doPad,
-        const int iterations, const apr_crypto_t *f, apr_pool_t *p)
+static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key,
+        const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad, apr_pool_t *p)
 {
-    apr_crypto_key_t *key = *k;
-
-    if (!key) {
-        *k = key = apr_array_push(f->keys);
-    }
-    if (!key) {
-        return APR_ENOMEM;
-    }
-
-    key->f = f;
-    key->provider = f->provider;
-
     /* determine the cipher to be used */
     switch (type) {
 
@@ -434,6 +402,153 @@
     }
     apr_crypto_clear(p, key->key, key->keyLen);
 
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Create a key from the provided secret or passphrase. The key is cleaned
+ *        up when the context is cleaned, and may be reused with multiple encryption
+ *        or decryption operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param rec The key record, from which the key will be derived.
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_key(apr_crypto_key_t **k, apr_size_t *ivSize,
+        const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p)
+{
+    apr_crypto_key_t *key = *k;
+    apr_status_t rv;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    key->f = f;
+    key->provider = f->provider;
+
+    /* decide on what cipher mechanism we will be using */
+    rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+
+    switch (rec->ktype) {
+
+    case APR_CRYPTO_KTYPE_PASSPHRASE: {
+
+        /* generate the key */
+        if (PKCS5_PBKDF2_HMAC_SHA1(rec->k.passphrase.pass,
+                rec->k.passphrase.passLen,
+                (unsigned char *) rec->k.passphrase.salt,
+                rec->k.passphrase.saltLen, rec->k.passphrase.iterations,
+                key->keyLen, key->key) == 0) {
+            return APR_ENOKEY;
+        }
+
+        break;
+    }
+
+    case APR_CRYPTO_KTYPE_SECRET: {
+
+        /* sanity check - key correct size? */
+        if (rec->k.secret.secretLen != key->keyLen) {
+            return APR_EKEYLENGTH;
+        }
+
+        /* copy the key */
+        memcpy(key->key, rec->k.secret.secret, rec->k.secret.secretLen);
+
+        break;
+    }
+
+    default: {
+
+        return APR_ENOKEY;
+
+    }
+    }
+
+    key->doPad = rec->pad;
+
+    /* note: openssl incorrectly returns non zero IV size values for ECB
+     * algorithms, so work around this by ignoring the IV size.
+     */
+    if (APR_MODE_ECB != rec->mode) {
+        key->ivSize = EVP_CIPHER_iv_length(key->cipher);
+    }
+    if (ivSize) {
+        *ivSize = key->ivSize;
+    }
+
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Create a key from the given passphrase. By default, the PBKDF2
+ *        algorithm is used to generate the key from the passphrase. It is expected
+ *        that the same pass phrase will generate the same key, regardless of the
+ *        backend crypto platform used. The key is cleaned up when the context
+ *        is cleaned, and may be reused with multiple encryption or decryption
+ *        operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @param pass The passphrase to use.
+ * @param passLen The passphrase length in bytes
+ * @param salt The salt to use.
+ * @param saltLen The salt length in bytes
+ * @param type 3DES_192, AES_128, AES_192, AES_256.
+ * @param mode Electronic Code Book / Cipher Block Chaining.
+ * @param doPad Pad if necessary.
+ * @param iterations Iteration count
+ * @param f The context to use.
+ * @param p The pool to use.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize,
+        const char *pass, apr_size_t passLen, const unsigned char * salt,
+        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad,
+        const int iterations, const apr_crypto_t *f, apr_pool_t *p)
+{
+    apr_crypto_key_t *key = *k;
+    apr_status_t rv;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    key->f = f;
+    key->provider = f->provider;
+
+    /* decide on what cipher mechanism we will be using */
+    rv = crypto_cipher_mechanism(key, type, mode, doPad, p);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+
     /* generate the key */
     if (PKCS5_PBKDF2_HMAC_SHA1(pass, passLen, (unsigned char *) salt, saltLen,
             iterations, key->keyLen, key->key) == 0) {
@@ -793,7 +908,8 @@
     crypto_block_encrypt_init, crypto_block_encrypt,
     crypto_block_encrypt_finish, crypto_block_decrypt_init,
     crypto_block_decrypt, crypto_block_decrypt_finish,
-    crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error
+    crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error,
+    crypto_key
 };
 
 #endif
