]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - crypto/testmgr.c
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[mirror_ubuntu-jammy-kernel.git] / crypto / testmgr.c
index feb3ff27e0b319979cf031cbb88e030d7c22c981..c9e67c2bd7257cc98f57e6e5a93efeea16864afd 100644 (file)
@@ -1290,9 +1290,168 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
        return 0;
 }
 
+#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
+/*
+ * Generate a hash test vector from the given implementation.
+ * Assumes the buffers in 'vec' were already allocated.
+ */
+static void generate_random_hash_testvec(struct crypto_shash *tfm,
+                                        struct hash_testvec *vec,
+                                        unsigned int maxkeysize,
+                                        unsigned int maxdatasize,
+                                        char *name, size_t max_namelen)
+{
+       SHASH_DESC_ON_STACK(desc, tfm);
+
+       /* Data */
+       vec->psize = generate_random_length(maxdatasize);
+       generate_random_bytes((u8 *)vec->plaintext, vec->psize);
+
+       /*
+        * Key: length in range [1, maxkeysize], but usually choose maxkeysize.
+        * If algorithm is unkeyed, then maxkeysize == 0 and set ksize = 0.
+        */
+       vec->setkey_error = 0;
+       vec->ksize = 0;
+       if (maxkeysize) {
+               vec->ksize = maxkeysize;
+               if (prandom_u32() % 4 == 0)
+                       vec->ksize = 1 + (prandom_u32() % maxkeysize);
+               generate_random_bytes((u8 *)vec->key, vec->ksize);
+
+               vec->setkey_error = crypto_shash_setkey(tfm, vec->key,
+                                                       vec->ksize);
+               /* If the key couldn't be set, no need to continue to digest. */
+               if (vec->setkey_error)
+                       goto done;
+       }
+
+       /* Digest */
+       desc->tfm = tfm;
+       vec->digest_error = crypto_shash_digest(desc, vec->plaintext,
+                                               vec->psize, (u8 *)vec->digest);
+done:
+       snprintf(name, max_namelen, "\"random: psize=%u ksize=%u\"",
+                vec->psize, vec->ksize);
+}
+
+/*
+ * Test the hash algorithm represented by @req against the corresponding generic
+ * implementation, if one is available.
+ */
+static int test_hash_vs_generic_impl(const char *driver,
+                                    const char *generic_driver,
+                                    unsigned int maxkeysize,
+                                    struct ahash_request *req,
+                                    struct test_sglist *tsgl,
+                                    u8 *hashstate)
+{
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+       const unsigned int digestsize = crypto_ahash_digestsize(tfm);
+       const unsigned int blocksize = crypto_ahash_blocksize(tfm);
+       const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
+       const char *algname = crypto_hash_alg_common(tfm)->base.cra_name;
+       char _generic_driver[CRYPTO_MAX_ALG_NAME];
+       struct crypto_shash *generic_tfm = NULL;
+       unsigned int i;
+       struct hash_testvec vec = { 0 };
+       char vec_name[64];
+       struct testvec_config cfg;
+       char cfgname[TESTVEC_CONFIG_NAMELEN];
+       int err;
+
+       if (noextratests)
+               return 0;
+
+       if (!generic_driver) { /* Use default naming convention? */
+               err = build_generic_driver_name(algname, _generic_driver);
+               if (err)
+                       return err;
+               generic_driver = _generic_driver;
+       }
+
+       if (strcmp(generic_driver, driver) == 0) /* Already the generic impl? */
+               return 0;
+
+       generic_tfm = crypto_alloc_shash(generic_driver, 0, 0);
+       if (IS_ERR(generic_tfm)) {
+               err = PTR_ERR(generic_tfm);
+               if (err == -ENOENT) {
+                       pr_warn("alg: hash: skipping comparison tests for %s because %s is unavailable\n",
+                               driver, generic_driver);
+                       return 0;
+               }
+               pr_err("alg: hash: error allocating %s (generic impl of %s): %d\n",
+                      generic_driver, algname, err);
+               return err;
+       }
+
+       /* Check the algorithm properties for consistency. */
+
+       if (digestsize != crypto_shash_digestsize(generic_tfm)) {
+               pr_err("alg: hash: digestsize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, digestsize,
+                      crypto_shash_digestsize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (blocksize != crypto_shash_blocksize(generic_tfm)) {
+               pr_err("alg: hash: blocksize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, blocksize, crypto_shash_blocksize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * Now generate test vectors using the generic implementation, and test
+        * the other implementation against them.
+        */
+
+       vec.key = kmalloc(maxkeysize, GFP_KERNEL);
+       vec.plaintext = kmalloc(maxdatasize, GFP_KERNEL);
+       vec.digest = kmalloc(digestsize, GFP_KERNEL);
+       if (!vec.key || !vec.plaintext || !vec.digest) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < fuzz_iterations * 8; i++) {
+               generate_random_hash_testvec(generic_tfm, &vec,
+                                            maxkeysize, maxdatasize,
+                                            vec_name, sizeof(vec_name));
+               generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+
+               err = test_hash_vec_cfg(driver, &vec, vec_name, &cfg,
+                                       req, tsgl, hashstate);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       err = 0;
+out:
+       kfree(vec.key);
+       kfree(vec.plaintext);
+       kfree(vec.digest);
+       crypto_free_shash(generic_tfm);
+       return err;
+}
+#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+static int test_hash_vs_generic_impl(const char *driver,
+                                    const char *generic_driver,
+                                    unsigned int maxkeysize,
+                                    struct ahash_request *req,
+                                    struct test_sglist *tsgl,
+                                    u8 *hashstate)
+{
+       return 0;
+}
+#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+
 static int __alg_test_hash(const struct hash_testvec *vecs,
                           unsigned int num_vecs, const char *driver,
-                          u32 type, u32 mask)
+                          u32 type, u32 mask,
+                          const char *generic_driver, unsigned int maxkeysize)
 {
        struct crypto_ahash *tfm;
        struct ahash_request *req = NULL;
@@ -1340,7 +1499,8 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
                if (err)
                        goto out;
        }
-       err = 0;
+       err = test_hash_vs_generic_impl(driver, generic_driver, maxkeysize, req,
+                                       tsgl, hashstate);
 out:
        kfree(hashstate);
        if (tsgl) {
@@ -1358,6 +1518,7 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
        const struct hash_testvec *template = desc->suite.hash.vecs;
        unsigned int tcount = desc->suite.hash.count;
        unsigned int nr_unkeyed, nr_keyed;
+       unsigned int maxkeysize = 0;
        int err;
 
        /*
@@ -1376,16 +1537,20 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
                               "unkeyed ones must come first\n", desc->alg);
                        return -EINVAL;
                }
+               maxkeysize = max_t(unsigned int, maxkeysize,
+                                  template[nr_unkeyed + nr_keyed].ksize);
        }
 
        err = 0;
        if (nr_unkeyed) {
-               err = __alg_test_hash(template, nr_unkeyed, driver, type, mask);
+               err = __alg_test_hash(template, nr_unkeyed, driver, type, mask,
+                                     desc->generic_driver, maxkeysize);
                template += nr_unkeyed;
        }
 
        if (!err && nr_keyed)
-               err = __alg_test_hash(template, nr_keyed, driver, type, mask);
+               err = __alg_test_hash(template, nr_keyed, driver, type, mask,
+                                     desc->generic_driver, maxkeysize);
 
        return err;
 }
@@ -1601,6 +1766,226 @@ static int test_aead_vec(const char *driver, int enc,
        return 0;
 }
 
+#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
+/*
+ * Generate an AEAD test vector from the given implementation.
+ * Assumes the buffers in 'vec' were already allocated.
+ */
+static void generate_random_aead_testvec(struct aead_request *req,
+                                        struct aead_testvec *vec,
+                                        unsigned int maxkeysize,
+                                        unsigned int maxdatasize,
+                                        char *name, size_t max_namelen)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       const unsigned int ivsize = crypto_aead_ivsize(tfm);
+       unsigned int maxauthsize = crypto_aead_alg(tfm)->maxauthsize;
+       unsigned int authsize;
+       unsigned int total_len;
+       int i;
+       struct scatterlist src[2], dst;
+       u8 iv[MAX_IVLEN];
+       DECLARE_CRYPTO_WAIT(wait);
+
+       /* Key: length in [0, maxkeysize], but usually choose maxkeysize */
+       vec->klen = maxkeysize;
+       if (prandom_u32() % 4 == 0)
+               vec->klen = prandom_u32() % (maxkeysize + 1);
+       generate_random_bytes((u8 *)vec->key, vec->klen);
+       vec->setkey_error = crypto_aead_setkey(tfm, vec->key, vec->klen);
+
+       /* IV */
+       generate_random_bytes((u8 *)vec->iv, ivsize);
+
+       /* Tag length: in [0, maxauthsize], but usually choose maxauthsize */
+       authsize = maxauthsize;
+       if (prandom_u32() % 4 == 0)
+               authsize = prandom_u32() % (maxauthsize + 1);
+       if (WARN_ON(authsize > maxdatasize))
+               authsize = maxdatasize;
+       maxdatasize -= authsize;
+       vec->setauthsize_error = crypto_aead_setauthsize(tfm, authsize);
+
+       /* Plaintext and associated data */
+       total_len = generate_random_length(maxdatasize);
+       if (prandom_u32() % 4 == 0)
+               vec->alen = 0;
+       else
+               vec->alen = generate_random_length(total_len);
+       vec->plen = total_len - vec->alen;
+       generate_random_bytes((u8 *)vec->assoc, vec->alen);
+       generate_random_bytes((u8 *)vec->ptext, vec->plen);
+
+       vec->clen = vec->plen + authsize;
+
+       /*
+        * If the key or authentication tag size couldn't be set, no need to
+        * continue to encrypt.
+        */
+       if (vec->setkey_error || vec->setauthsize_error)
+               goto done;
+
+       /* Ciphertext */
+       sg_init_table(src, 2);
+       i = 0;
+       if (vec->alen)
+               sg_set_buf(&src[i++], vec->assoc, vec->alen);
+       if (vec->plen)
+               sg_set_buf(&src[i++], vec->ptext, vec->plen);
+       sg_init_one(&dst, vec->ctext, vec->alen + vec->clen);
+       memcpy(iv, vec->iv, ivsize);
+       aead_request_set_callback(req, 0, crypto_req_done, &wait);
+       aead_request_set_crypt(req, src, &dst, vec->plen, iv);
+       aead_request_set_ad(req, vec->alen);
+       vec->crypt_error = crypto_wait_req(crypto_aead_encrypt(req), &wait);
+       if (vec->crypt_error == 0)
+               memmove((u8 *)vec->ctext, vec->ctext + vec->alen, vec->clen);
+done:
+       snprintf(name, max_namelen,
+                "\"random: alen=%u plen=%u authsize=%u klen=%u\"",
+                vec->alen, vec->plen, authsize, vec->klen);
+}
+
+/*
+ * Test the AEAD algorithm represented by @req against the corresponding generic
+ * implementation, if one is available.
+ */
+static int test_aead_vs_generic_impl(const char *driver,
+                                    const struct alg_test_desc *test_desc,
+                                    struct aead_request *req,
+                                    struct cipher_test_sglists *tsgls)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       const unsigned int ivsize = crypto_aead_ivsize(tfm);
+       const unsigned int maxauthsize = crypto_aead_alg(tfm)->maxauthsize;
+       const unsigned int blocksize = crypto_aead_blocksize(tfm);
+       const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
+       const char *algname = crypto_aead_alg(tfm)->base.cra_name;
+       const char *generic_driver = test_desc->generic_driver;
+       char _generic_driver[CRYPTO_MAX_ALG_NAME];
+       struct crypto_aead *generic_tfm = NULL;
+       struct aead_request *generic_req = NULL;
+       unsigned int maxkeysize;
+       unsigned int i;
+       struct aead_testvec vec = { 0 };
+       char vec_name[64];
+       struct testvec_config cfg;
+       char cfgname[TESTVEC_CONFIG_NAMELEN];
+       int err;
+
+       if (noextratests)
+               return 0;
+
+       if (!generic_driver) { /* Use default naming convention? */
+               err = build_generic_driver_name(algname, _generic_driver);
+               if (err)
+                       return err;
+               generic_driver = _generic_driver;
+       }
+
+       if (strcmp(generic_driver, driver) == 0) /* Already the generic impl? */
+               return 0;
+
+       generic_tfm = crypto_alloc_aead(generic_driver, 0, 0);
+       if (IS_ERR(generic_tfm)) {
+               err = PTR_ERR(generic_tfm);
+               if (err == -ENOENT) {
+                       pr_warn("alg: aead: skipping comparison tests for %s because %s is unavailable\n",
+                               driver, generic_driver);
+                       return 0;
+               }
+               pr_err("alg: aead: error allocating %s (generic impl of %s): %d\n",
+                      generic_driver, algname, err);
+               return err;
+       }
+
+       generic_req = aead_request_alloc(generic_tfm, GFP_KERNEL);
+       if (!generic_req) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Check the algorithm properties for consistency. */
+
+       if (maxauthsize != crypto_aead_alg(generic_tfm)->maxauthsize) {
+               pr_err("alg: aead: maxauthsize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, maxauthsize,
+                      crypto_aead_alg(generic_tfm)->maxauthsize);
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (ivsize != crypto_aead_ivsize(generic_tfm)) {
+               pr_err("alg: aead: ivsize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, ivsize, crypto_aead_ivsize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (blocksize != crypto_aead_blocksize(generic_tfm)) {
+               pr_err("alg: aead: blocksize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, blocksize, crypto_aead_blocksize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * Now generate test vectors using the generic implementation, and test
+        * the other implementation against them.
+        */
+
+       maxkeysize = 0;
+       for (i = 0; i < test_desc->suite.aead.count; i++)
+               maxkeysize = max_t(unsigned int, maxkeysize,
+                                  test_desc->suite.aead.vecs[i].klen);
+
+       vec.key = kmalloc(maxkeysize, GFP_KERNEL);
+       vec.iv = kmalloc(ivsize, GFP_KERNEL);
+       vec.assoc = kmalloc(maxdatasize, GFP_KERNEL);
+       vec.ptext = kmalloc(maxdatasize, GFP_KERNEL);
+       vec.ctext = kmalloc(maxdatasize, GFP_KERNEL);
+       if (!vec.key || !vec.iv || !vec.assoc || !vec.ptext || !vec.ctext) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < fuzz_iterations * 8; i++) {
+               generate_random_aead_testvec(generic_req, &vec,
+                                            maxkeysize, maxdatasize,
+                                            vec_name, sizeof(vec_name));
+               generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+
+               err = test_aead_vec_cfg(driver, ENCRYPT, &vec, vec_name, &cfg,
+                                       req, tsgls);
+               if (err)
+                       goto out;
+               err = test_aead_vec_cfg(driver, DECRYPT, &vec, vec_name, &cfg,
+                                       req, tsgls);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       err = 0;
+out:
+       kfree(vec.key);
+       kfree(vec.iv);
+       kfree(vec.assoc);
+       kfree(vec.ptext);
+       kfree(vec.ctext);
+       crypto_free_aead(generic_tfm);
+       aead_request_free(generic_req);
+       return err;
+}
+#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+static int test_aead_vs_generic_impl(const char *driver,
+                                    const struct alg_test_desc *test_desc,
+                                    struct aead_request *req,
+                                    struct cipher_test_sglists *tsgls)
+{
+       return 0;
+}
+#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+
 static int test_aead(const char *driver, int enc,
                     const struct aead_test_suite *suite,
                     struct aead_request *req,
@@ -1660,6 +2045,10 @@ static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
                goto out;
 
        err = test_aead(driver, DECRYPT, suite, req, tsgls);
+       if (err)
+               goto out;
+
+       err = test_aead_vs_generic_impl(driver, desc, req, tsgls);
 out:
        free_cipher_test_sglists(tsgls);
        aead_request_free(req);
@@ -1958,6 +2347,186 @@ static int test_skcipher_vec(const char *driver, int enc,
        return 0;
 }
 
+#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
+/*
+ * Generate a symmetric cipher test vector from the given implementation.
+ * Assumes the buffers in 'vec' were already allocated.
+ */
+static void generate_random_cipher_testvec(struct skcipher_request *req,
+                                          struct cipher_testvec *vec,
+                                          unsigned int maxdatasize,
+                                          char *name, size_t max_namelen)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const unsigned int maxkeysize = tfm->keysize;
+       const unsigned int ivsize = crypto_skcipher_ivsize(tfm);
+       struct scatterlist src, dst;
+       u8 iv[MAX_IVLEN];
+       DECLARE_CRYPTO_WAIT(wait);
+
+       /* Key: length in [0, maxkeysize], but usually choose maxkeysize */
+       vec->klen = maxkeysize;
+       if (prandom_u32() % 4 == 0)
+               vec->klen = prandom_u32() % (maxkeysize + 1);
+       generate_random_bytes((u8 *)vec->key, vec->klen);
+       vec->setkey_error = crypto_skcipher_setkey(tfm, vec->key, vec->klen);
+
+       /* IV */
+       generate_random_bytes((u8 *)vec->iv, ivsize);
+
+       /* Plaintext */
+       vec->len = generate_random_length(maxdatasize);
+       generate_random_bytes((u8 *)vec->ptext, vec->len);
+
+       /* If the key couldn't be set, no need to continue to encrypt. */
+       if (vec->setkey_error)
+               goto done;
+
+       /* Ciphertext */
+       sg_init_one(&src, vec->ptext, vec->len);
+       sg_init_one(&dst, vec->ctext, vec->len);
+       memcpy(iv, vec->iv, ivsize);
+       skcipher_request_set_callback(req, 0, crypto_req_done, &wait);
+       skcipher_request_set_crypt(req, &src, &dst, vec->len, iv);
+       vec->crypt_error = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
+done:
+       snprintf(name, max_namelen, "\"random: len=%u klen=%u\"",
+                vec->len, vec->klen);
+}
+
+/*
+ * Test the skcipher algorithm represented by @req against the corresponding
+ * generic implementation, if one is available.
+ */
+static int test_skcipher_vs_generic_impl(const char *driver,
+                                        const char *generic_driver,
+                                        struct skcipher_request *req,
+                                        struct cipher_test_sglists *tsgls)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const unsigned int ivsize = crypto_skcipher_ivsize(tfm);
+       const unsigned int blocksize = crypto_skcipher_blocksize(tfm);
+       const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
+       const char *algname = crypto_skcipher_alg(tfm)->base.cra_name;
+       char _generic_driver[CRYPTO_MAX_ALG_NAME];
+       struct crypto_skcipher *generic_tfm = NULL;
+       struct skcipher_request *generic_req = NULL;
+       unsigned int i;
+       struct cipher_testvec vec = { 0 };
+       char vec_name[64];
+       struct testvec_config cfg;
+       char cfgname[TESTVEC_CONFIG_NAMELEN];
+       int err;
+
+       if (noextratests)
+               return 0;
+
+       /* Keywrap isn't supported here yet as it handles its IV differently. */
+       if (strncmp(algname, "kw(", 3) == 0)
+               return 0;
+
+       if (!generic_driver) { /* Use default naming convention? */
+               err = build_generic_driver_name(algname, _generic_driver);
+               if (err)
+                       return err;
+               generic_driver = _generic_driver;
+       }
+
+       if (strcmp(generic_driver, driver) == 0) /* Already the generic impl? */
+               return 0;
+
+       generic_tfm = crypto_alloc_skcipher(generic_driver, 0, 0);
+       if (IS_ERR(generic_tfm)) {
+               err = PTR_ERR(generic_tfm);
+               if (err == -ENOENT) {
+                       pr_warn("alg: skcipher: skipping comparison tests for %s because %s is unavailable\n",
+                               driver, generic_driver);
+                       return 0;
+               }
+               pr_err("alg: skcipher: error allocating %s (generic impl of %s): %d\n",
+                      generic_driver, algname, err);
+               return err;
+       }
+
+       generic_req = skcipher_request_alloc(generic_tfm, GFP_KERNEL);
+       if (!generic_req) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Check the algorithm properties for consistency. */
+
+       if (tfm->keysize != generic_tfm->keysize) {
+               pr_err("alg: skcipher: max keysize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, tfm->keysize, generic_tfm->keysize);
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (ivsize != crypto_skcipher_ivsize(generic_tfm)) {
+               pr_err("alg: skcipher: ivsize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, ivsize, crypto_skcipher_ivsize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (blocksize != crypto_skcipher_blocksize(generic_tfm)) {
+               pr_err("alg: skcipher: blocksize for %s (%u) doesn't match generic impl (%u)\n",
+                      driver, blocksize,
+                      crypto_skcipher_blocksize(generic_tfm));
+               err = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * Now generate test vectors using the generic implementation, and test
+        * the other implementation against them.
+        */
+
+       vec.key = kmalloc(tfm->keysize, GFP_KERNEL);
+       vec.iv = kmalloc(ivsize, GFP_KERNEL);
+       vec.ptext = kmalloc(maxdatasize, GFP_KERNEL);
+       vec.ctext = kmalloc(maxdatasize, GFP_KERNEL);
+       if (!vec.key || !vec.iv || !vec.ptext || !vec.ctext) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < fuzz_iterations * 8; i++) {
+               generate_random_cipher_testvec(generic_req, &vec, maxdatasize,
+                                              vec_name, sizeof(vec_name));
+               generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+
+               err = test_skcipher_vec_cfg(driver, ENCRYPT, &vec, vec_name,
+                                           &cfg, req, tsgls);
+               if (err)
+                       goto out;
+               err = test_skcipher_vec_cfg(driver, DECRYPT, &vec, vec_name,
+                                           &cfg, req, tsgls);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       err = 0;
+out:
+       kfree(vec.key);
+       kfree(vec.iv);
+       kfree(vec.ptext);
+       kfree(vec.ctext);
+       crypto_free_skcipher(generic_tfm);
+       skcipher_request_free(generic_req);
+       return err;
+}
+#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+static int test_skcipher_vs_generic_impl(const char *driver,
+                                        const char *generic_driver,
+                                        struct skcipher_request *req,
+                                        struct cipher_test_sglists *tsgls)
+{
+       return 0;
+}
+#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+
 static int test_skcipher(const char *driver, int enc,
                         const struct cipher_test_suite *suite,
                         struct skcipher_request *req,
@@ -2017,6 +2586,11 @@ static int alg_test_skcipher(const struct alg_test_desc *desc,
                goto out;
 
        err = test_skcipher(driver, DECRYPT, suite, req, tsgls);
+       if (err)
+               goto out;
+
+       err = test_skcipher_vs_generic_impl(driver, desc->generic_driver, req,
+                                           tsgls);
 out:
        free_cipher_test_sglists(tsgls);
        skcipher_request_free(req);
@@ -2452,7 +3026,6 @@ static int alg_test_crc32c(const struct alg_test_desc *desc,
                u32 *ctx = (u32 *)shash_desc_ctx(shash);
 
                shash->tfm = tfm;
-               shash->flags = 0;
 
                *ctx = 420553207;
                err = crypto_shash_final(shash, (u8 *)&val);
@@ -2998,12 +3571,14 @@ static int alg_test_null(const struct alg_test_desc *desc,
 static const struct alg_test_desc alg_test_descs[] = {
        {
                .alg = "adiantum(xchacha12,aes)",
+               .generic_driver = "adiantum(xchacha12-generic,aes-generic,nhpoly1305-generic)",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(adiantum_xchacha12_aes_tv_template)
                },
        }, {
                .alg = "adiantum(xchacha20,aes)",
+               .generic_driver = "adiantum(xchacha20-generic,aes-generic,nhpoly1305-generic)",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(adiantum_xchacha20_aes_tv_template)
@@ -3219,6 +3794,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                .alg = "cbc(paes)",
                .test = alg_test_null,
                .fips_allowed = 1,
+       }, {
+               /* Same as cbc(sm4) except the key is stored in
+                * hardware secure memory which we reference by index
+                */
+               .alg = "cbc(psm4)",
+               .test = alg_test_null,
        }, {
                .alg = "cbc(serpent)",
                .test = alg_test_skcipher,
@@ -3246,6 +3827,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "ccm(aes)",
+               .generic_driver = "ccm_base(ctr(aes-generic),cbcmac(aes-generic))",
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
@@ -3354,6 +3936,13 @@ static const struct alg_test_desc alg_test_descs[] = {
                .test = alg_test_null,
                .fips_allowed = 1,
        }, {
+
+               /* Same as ctr(sm4) except the key is stored in
+                * hardware secure memory which we reference by index
+                */
+               .alg = "ctr(psm4)",
+               .test = alg_test_null,
+       }, {
                .alg = "ctr(serpent)",
                .test = alg_test_skcipher,
                .suite = {
@@ -3378,6 +3967,13 @@ static const struct alg_test_desc alg_test_descs[] = {
                .suite = {
                        .cipher = __VECS(cts_mode_tv_template)
                }
+       }, {
+               /* Same as cts(cbc((aes)) except the key is stored in
+                * hardware secure memory which we reference by index
+                */
+               .alg = "cts(cbc(paes))",
+               .test = alg_test_null,
+               .fips_allowed = 1,
        }, {
                .alg = "deflate",
                .test = alg_test_comp,
@@ -3664,6 +4260,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "gcm(aes)",
+               .generic_driver = "gcm_base(ctr(aes-generic),ghash-generic)",
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
@@ -3782,30 +4379,35 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "lrw(aes)",
+               .generic_driver = "lrw(ecb(aes-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(aes_lrw_tv_template)
                }
        }, {
                .alg = "lrw(camellia)",
+               .generic_driver = "lrw(ecb(camellia-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(camellia_lrw_tv_template)
                }
        }, {
                .alg = "lrw(cast6)",
+               .generic_driver = "lrw(ecb(cast6-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(cast6_lrw_tv_template)
                }
        }, {
                .alg = "lrw(serpent)",
+               .generic_driver = "lrw(ecb(serpent-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(serpent_lrw_tv_template)
                }
        }, {
                .alg = "lrw(twofish)",
+               .generic_driver = "lrw(ecb(twofish-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(tf_lrw_tv_template)
@@ -3930,6 +4532,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "rfc4106(gcm(aes))",
+               .generic_driver = "rfc4106(gcm_base(ctr(aes-generic),ghash-generic))",
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
@@ -3937,6 +4540,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "rfc4309(ccm(aes))",
+               .generic_driver = "rfc4309(ccm_base(ctr(aes-generic),cbcmac(aes-generic)))",
                .test = alg_test_aead,
                .fips_allowed = 1,
                .suite = {
@@ -3944,6 +4548,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "rfc4543(gcm(aes))",
+               .generic_driver = "rfc4543(gcm_base(ctr(aes-generic),ghash-generic))",
                .test = alg_test_aead,
                .suite = {
                        .aead = __VECS(aes_gcm_rfc4543_tv_template)
@@ -4140,6 +4745,7 @@ static const struct alg_test_desc alg_test_descs[] = {
                },
        }, {
                .alg = "xts(aes)",
+               .generic_driver = "xts(ecb(aes-generic))",
                .test = alg_test_skcipher,
                .fips_allowed = 1,
                .suite = {
@@ -4147,12 +4753,14 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
                .alg = "xts(camellia)",
+               .generic_driver = "xts(ecb(camellia-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(camellia_xts_tv_template)
                }
        }, {
                .alg = "xts(cast6)",
+               .generic_driver = "xts(ecb(cast6-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(cast6_xts_tv_template)
@@ -4166,12 +4774,14 @@ static const struct alg_test_desc alg_test_descs[] = {
                .fips_allowed = 1,
        }, {
                .alg = "xts(serpent)",
+               .generic_driver = "xts(ecb(serpent-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(serpent_xts_tv_template)
                }
        }, {
                .alg = "xts(twofish)",
+               .generic_driver = "xts(ecb(twofish-generic))",
                .test = alg_test_skcipher,
                .suite = {
                        .cipher = __VECS(tf_xts_tv_template)