/* * Algorithm testing framework and tests. * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> * Copyright (c) 2007 Nokia Siemens Networks * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au> * * Updated RFC4106 AES-GCM testing. * Authors: Aidan O'Mahony (aidan.o.mahony@intel.com) * Adrian Hoban <adrian.hoban@intel.com> * Gabriele Paoloni <gabriele.paoloni@intel.com> * Tadeusz Struk (tadeusz.struk@intel.com) * Copyright (c) 2010, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * */ #include <crypto/hash.h>#include <linux/err.h>#include <linux/module.h>#include <linux/scatterlist.h>#include <linux/slab.h>#include <linux/string.h>#include <crypto/rng.h> #include "internal.h" #ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS /* a perfect nop */int alg_test(const char *driver, const char *alg, u32 type, u32 mask){ return 0;} #else #include "testmgr.h" /* * Need slab memory for testing (size in number of pages). */#define XBUFSIZE 8 /* * Indexes into the xbuf to simulate cross-page access. */#define IDX1 32#define IDX2 32400#define IDX3 1#define IDX4 8193#define IDX5 22222#define IDX6 17101#define IDX7 27333#define IDX8 3000 /** Used by test_cipher()*/#define ENCRYPT 1#define DECRYPT 0 struct tcrypt_result { struct completion completion; int err;}; struct aead_test_suite { struct { struct aead_testvec *vecs; unsigned int count; } enc, dec;}; struct cipher_test_suite { struct { struct cipher_testvec *vecs; unsigned int count; } enc, dec;}; struct comp_test_suite { struct { struct comp_testvec *vecs; unsigned int count; } comp, decomp;}; struct pcomp_test_suite { struct { struct pcomp_testvec *vecs; unsigned int count; } comp, decomp;}; struct hash_test_suite { struct hash_testvec *vecs; unsigned int count;}; struct cprng_test_suite { struct cprng_testvec *vecs; unsigned int count;}; struct alg_test_desc { const char *alg; int (*test)(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask); int fips_allowed; /* set if alg is allowed in fips mode */ union { struct aead_test_suite aead; struct cipher_test_suite cipher; struct comp_test_suite comp; struct pcomp_test_suite pcomp; struct hash_test_suite hash; struct cprng_test_suite cprng; } suite;}; static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; static void hexdump(unsigned char *buf, unsigned int len){ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);} static void tcrypt_complete(struct crypto_async_request *req, int err){ struct tcrypt_result *res = req->data; if (err == -EINPROGRESS) return; res->err = err; complete(&res->completion);} static int testmgr_alloc_buf(char *buf[XBUFSIZE]){ int i; for (i = 0; i < XBUFSIZE; i++) { buf[i] = (void *)__get_free_page(GFP_KERNEL); if (!buf[i]) goto err_free_buf; } return 0; err_free_buf: while (i-- > 0) free_page((unsigned long)buf[i]); return -ENOMEM;} static void testmgr_free_buf(char *buf[XBUFSIZE]){ int i; for (i = 0; i < XBUFSIZE; i++) free_page((unsigned long)buf[i]);} static int do_one_async_hash_op(struct ahash_request *req, struct tcrypt_result *tr, int ret){ if (ret == -EINPROGRESS || ret == -EBUSY) { ret = wait_for_completion_interruptible(&tr->completion); if (!ret) ret = tr->err; reinit_completion(&tr->completion); } return ret;} static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, unsigned int tcount, bool use_digest, const int align_offset){ const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); unsigned int i, j, k, temp; struct scatterlist sg[8]; char result[64]; struct ahash_request *req; struct tcrypt_result tresult; void *hash_buff; char *xbuf[XBUFSIZE]; int ret = -ENOMEM; if (testmgr_alloc_buf(xbuf)) goto out_nobuf; init_completion(&tresult.completion); req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) { printk(KERN_ERR "alg: hash: Failed to allocate request for " "%s\n", algo); goto out_noreq; } ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &tresult); j = 0; for (i = 0; i < tcount; i++) { if (template[i].np) continue; ret = -EINVAL; if (WARN_ON(align_offset + template[i].psize > PAGE_SIZE)) goto out; j++; memset(result, 0, 64); hash_buff = xbuf[0]; hash_buff += align_offset; memcpy(hash_buff, template[i].plaintext, template[i].psize); sg_init_one(&sg[0], hash_buff, template[i].psize); if (template[i].ksize) { crypto_ahash_clear_flags(tfm, ~0); ret = crypto_ahash_setkey(tfm, template[i].key, template[i].ksize); if (ret) { printk(KERN_ERR "alg: hash: setkey failed on " "test %d for %s: ret=%d\n", j, algo, -ret); goto out; } } ahash_request_set_crypt(req, sg, result, template[i].psize); if (use_digest) { ret = do_one_async_hash_op(req, &tresult, crypto_ahash_digest(req)); if (ret) { pr_err("alg: hash: digest failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } } else { ret = do_one_async_hash_op(req, &tresult, crypto_ahash_init(req)); if (ret) { pr_err("alt: hash: init failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } ret = do_one_async_hash_op(req, &tresult, crypto_ahash_update(req)); if (ret) { pr_err("alt: hash: update failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } ret = do_one_async_hash_op(req, &tresult, crypto_ahash_final(req)); if (ret) { pr_err("alt: hash: final failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } } if (memcmp(result, template[i].digest, crypto_ahash_digestsize(tfm))) { printk(KERN_ERR "alg: hash: Test %d failed for %s\n", j, algo); hexdump(result, crypto_ahash_digestsize(tfm)); ret = -EINVAL; goto out; } } j = 0; for (i = 0; i < tcount; i++) { /* alignment tests are only done with continuous buffers */ if (align_offset != 0) break; if (template[i].np) { j++; memset(result, 0, 64); temp = 0; sg_init_table(sg, template[i].np); ret = -EINVAL; for (k = 0; k < template[i].np; k++) { if (WARN_ON(offset_in_page(IDX[k]) + template[i].tap[k] > PAGE_SIZE)) goto out; sg_set_buf(&sg[k], memcpy(xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]), template[i].plaintext + temp, template[i].tap[k]), template[i].tap[k]); temp += template[i].tap[k]; } if (template[i].ksize) { crypto_ahash_clear_flags(tfm, ~0); ret = crypto_ahash_setkey(tfm, template[i].key, template[i].ksize); if (ret) { printk(KERN_ERR "alg: hash: setkey " "failed on chunking test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } } ahash_request_set_crypt(req, sg, result, template[i].psize); ret = crypto_ahash_digest(req); switch (ret) { case 0: break; case -EINPROGRESS: case -EBUSY: ret = wait_for_completion_interruptible( &tresult.completion); if (!ret && !(ret = tresult.err)) { reinit_completion(&tresult.completion); break; } /* fall through */ default: printk(KERN_ERR "alg: hash: digest failed " "on chunking test %d for %s: " "ret=%d\n", j, algo, -ret); goto out; } if (memcmp(result, template[i].digest, crypto_ahash_digestsize(tfm))) { printk(KERN_ERR "alg: hash: Chunking test %d " "failed for %s\n", j, algo); hexdump(result, crypto_ahash_digestsize(tfm)); ret = -EINVAL; goto out; } } } ret = 0; out: ahash_request_free(req);out_noreq: testmgr_free_buf(xbuf);out_nobuf: return ret;} static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, unsigned int tcount, bool use_digest){ unsigned int alignmask; int ret; ret = __test_hash(tfm, template, tcount, use_digest, 0); if (ret) return ret; /* test unaligned buffers, check with one byte offset */ ret = __test_hash(tfm, template, tcount, use_digest, 1); if (ret) return ret; alignmask = crypto_tfm_alg_alignmask(&tfm->base); if (alignmask) { /* Check if alignment mask for tfm is correctly set. */ ret = __test_hash(tfm, template, tcount, use_digest, alignmask + 1); if (ret) return ret; } return 0;} static int __test_aead(struct crypto_aead *tfm, int enc, struct aead_testvec *template, unsigned int tcount, const bool diff_dst, const int align_offset){ const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); unsigned int i, j, k, n, temp; int ret = -ENOMEM; char *q; char *key; struct aead_request *req; struct scatterlist *sg; struct scatterlist *asg; struct scatterlist *sgout; const char *e, *d; struct tcrypt_result result; unsigned int authsize; void *input; void *output; void *assoc; char iv[MAX_IVLEN]; char *xbuf[XBUFSIZE]; char *xoutbuf[XBUFSIZE]; char *axbuf[XBUFSIZE]; if (testmgr_alloc_buf(xbuf)) goto out_noxbuf; if (testmgr_alloc_buf(axbuf)) goto out_noaxbuf; if (diff_dst && testmgr_alloc_buf(xoutbuf)) goto out_nooutbuf; /* avoid "the frame size is larger than 1024 bytes" compiler warning */ sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL); if (!sg) goto out_nosg; asg = &sg[8]; sgout = &asg[8]; if (diff_dst) d = "-ddst"; else d = ""; if (enc == ENCRYPT) e = "encryption"; else e = "decryption"; init_completion(&result.completion); req = aead_request_alloc(tfm, GFP_KERNEL); if (!req) { pr_err("alg: aead%s: Failed to allocate request for %s\n", d, algo); goto out; } aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &result); for (i = 0, j = 0; i < tcount; i++) { if (!template[i].np) { j++; /* some templates have no input data but they will * touch input */ input = xbuf[0]; input += align_offset; assoc = axbuf[0]; ret = -EINVAL; if (WARN_ON(align_offset + template[i].ilen > PAGE_SIZE || template[i].alen > PAGE_SIZE)) goto out; memcpy(input, template[i].input, template[i].ilen); memcpy(assoc, template[i].assoc, template[i].alen); if (template[i].iv) memcpy(iv, template[i].iv, MAX_IVLEN); else memset(iv, 0, MAX_IVLEN); crypto_aead_clear_flags(tfm, ~0); if (template[i].wk) crypto_aead_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); key = template[i].key; ret = crypto_aead_setkey(tfm, key, template[i].klen); if (!ret == template[i].fail) { pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n", d, j, algo, crypto_aead_get_flags(tfm)); goto out; } else if (ret) continue; authsize = abs(template[i].rlen - template[i].ilen); ret = crypto_aead_setauthsize(tfm, authsize); if (ret) {Lines 1–500 of 3258. Load more
/* * Algorithm testing framework and tests. * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> * Copyright (c) 2007 Nokia Siemens Networks * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au> * * Updated RFC4106 AES-GCM testing. * Authors: Aidan O'Mahony (aidan.o.mahony@intel.com) * Adrian Hoban <adrian.hoban@intel.com> * Gabriele Paoloni <gabriele.paoloni@intel.com> * Tadeusz Struk (tadeusz.struk@intel.com) * Copyright (c) 2010, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * */ #include <crypto/hash.h> #include <linux/err.h> #include <linux/module.h> #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/string.h> #include <crypto/rng.h> #include "internal.h" #ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS /* a perfect nop */ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) { return 0; } #else #include "testmgr.h" /* * Need slab memory for testing (size in number of pages). */ #define XBUFSIZE 8 /* * Indexes into the xbuf to simulate cross-page access. */ #define IDX1 32 #define IDX2 32400 #define IDX3 1 #define IDX4 8193 #define IDX5 22222 #define IDX6 17101 #define IDX7 27333 #define IDX8 3000 /* * Used by test_cipher() */ #define ENCRYPT 1 #define DECRYPT 0 struct tcrypt_result { struct completion completion; int err; }; struct aead_test_suite { struct { struct aead_testvec *vecs; unsigned int count; } enc, dec; }; struct cipher_test_suite { struct { struct cipher_testvec *vecs; unsigned int count; } enc, dec; }; struct comp_test_suite { struct { struct comp_testvec *vecs; unsigned int count; } comp, decomp; }; struct pcomp_test_suite { struct { struct pcomp_testvec *vecs; unsigned int count; } comp, decomp; }; struct hash_test_suite { struct hash_testvec *vecs; unsigned int count; }; struct cprng_test_suite { struct cprng_testvec *vecs; unsigned int count; }; struct alg_test_desc { const char *alg; int (*test)(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask); int fips_allowed; /* set if alg is allowed in fips mode */ union { struct aead_test_suite aead; struct cipher_test_suite cipher; struct comp_test_suite comp; struct pcomp_test_suite pcomp; struct hash_test_suite hash; struct cprng_test_suite cprng; } suite; }; static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; static void hexdump(unsigned char *buf, unsigned int len) { print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); } static void tcrypt_complete(struct crypto_async_request *req, int err) { struct tcrypt_result *res = req->data; if (err == -EINPROGRESS) return; res->err = err; complete(&res->completion); } static int testmgr_alloc_buf(char *buf[XBUFSIZE]) { int i; for (i = 0; i < XBUFSIZE; i++) { buf[i] = (void *)__get_free_page(GFP_KERNEL); if (!buf[i]) goto err_free_buf; } return 0; err_free_buf: while (i-- > 0) free_page((unsigned long)buf[i]); return -ENOMEM; } static void testmgr_free_buf(char *buf[XBUFSIZE]) { int i; for (i = 0; i < XBUFSIZE; i++) free_page((unsigned long)buf[i]); } static int do_one_async_hash_op(struct ahash_request *req, struct tcrypt_result *tr, int ret) { if (ret == -EINPROGRESS || ret == -EBUSY) { ret = wait_for_completion_interruptible(&tr->completion); if (!ret) ret = tr->err; reinit_completion(&tr->completion); } return ret; } static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, unsigned int tcount, bool use_digest, const int align_offset) { const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); unsigned int i, j, k, temp; struct scatterlist sg[8]; char result[64]; struct ahash_request *req; struct tcrypt_result tresult; void *hash_buff; char *xbuf[XBUFSIZE]; int ret = -ENOMEM; if (testmgr_alloc_buf(xbuf)) goto out_nobuf; init_completion(&tresult.completion); req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) { printk(KERN_ERR "alg: hash: Failed to allocate request for " "%s\n", algo); goto out_noreq; } ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &tresult); j = 0; for (i = 0; i < tcount; i++) { if (template[i].np) continue; ret = -EINVAL; if (WARN_ON(align_offset + template[i].psize > PAGE_SIZE)) goto out; j++; memset(result, 0, 64); hash_buff = xbuf[0]; hash_buff += align_offset; memcpy(hash_buff, template[i].plaintext, template[i].psize); sg_init_one(&sg[0], hash_buff, template[i].psize); if (template[i].ksize) { crypto_ahash_clear_flags(tfm, ~0); ret = crypto_ahash_setkey(tfm, template[i].key, template[i].ksize); if (ret) { printk(KERN_ERR "alg: hash: setkey failed on " "test %d for %s: ret=%d\n", j, algo, -ret); goto out; } } ahash_request_set_crypt(req, sg, result, template[i].psize); if (use_digest) { ret = do_one_async_hash_op(req, &tresult, crypto_ahash_digest(req)); if (ret) { pr_err("alg: hash: digest failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } } else { ret = do_one_async_hash_op(req, &tresult, crypto_ahash_init(req)); if (ret) { pr_err("alt: hash: init failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } ret = do_one_async_hash_op(req, &tresult, crypto_ahash_update(req)); if (ret) { pr_err("alt: hash: update failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } ret = do_one_async_hash_op(req, &tresult, crypto_ahash_final(req)); if (ret) { pr_err("alt: hash: final failed on test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } } if (memcmp(result, template[i].digest, crypto_ahash_digestsize(tfm))) { printk(KERN_ERR "alg: hash: Test %d failed for %s\n", j, algo); hexdump(result, crypto_ahash_digestsize(tfm)); ret = -EINVAL; goto out; } } j = 0; for (i = 0; i < tcount; i++) { /* alignment tests are only done with continuous buffers */ if (align_offset != 0) break; if (template[i].np) { j++; memset(result, 0, 64); temp = 0; sg_init_table(sg, template[i].np); ret = -EINVAL; for (k = 0; k < template[i].np; k++) { if (WARN_ON(offset_in_page(IDX[k]) + template[i].tap[k] > PAGE_SIZE)) goto out; sg_set_buf(&sg[k], memcpy(xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]), template[i].plaintext + temp, template[i].tap[k]), template[i].tap[k]); temp += template[i].tap[k]; } if (template[i].ksize) { crypto_ahash_clear_flags(tfm, ~0); ret = crypto_ahash_setkey(tfm, template[i].key, template[i].ksize); if (ret) { printk(KERN_ERR "alg: hash: setkey " "failed on chunking test %d " "for %s: ret=%d\n", j, algo, -ret); goto out; } } ahash_request_set_crypt(req, sg, result, template[i].psize); ret = crypto_ahash_digest(req); switch (ret) { case 0: break; case -EINPROGRESS: case -EBUSY: ret = wait_for_completion_interruptible( &tresult.completion); if (!ret && !(ret = tresult.err)) { reinit_completion(&tresult.completion); break; } /* fall through */ default: printk(KERN_ERR "alg: hash: digest failed " "on chunking test %d for %s: " "ret=%d\n", j, algo, -ret); goto out; } if (memcmp(result, template[i].digest, crypto_ahash_digestsize(tfm))) { printk(KERN_ERR "alg: hash: Chunking test %d " "failed for %s\n", j, algo); hexdump(result, crypto_ahash_digestsize(tfm)); ret = -EINVAL; goto out; } } } ret = 0; out: ahash_request_free(req); out_noreq: testmgr_free_buf(xbuf); out_nobuf: return ret; } static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, unsigned int tcount, bool use_digest) { unsigned int alignmask; int ret; ret = __test_hash(tfm, template, tcount, use_digest, 0); if (ret) return ret; /* test unaligned buffers, check with one byte offset */ ret = __test_hash(tfm, template, tcount, use_digest, 1); if (ret) return ret; alignmask = crypto_tfm_alg_alignmask(&tfm->base); if (alignmask) { /* Check if alignment mask for tfm is correctly set. */ ret = __test_hash(tfm, template, tcount, use_digest, alignmask + 1); if (ret) return ret; } return 0; } static int __test_aead(struct crypto_aead *tfm, int enc, struct aead_testvec *template, unsigned int tcount, const bool diff_dst, const int align_offset) { const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); unsigned int i, j, k, n, temp; int ret = -ENOMEM; char *q; char *key; struct aead_request *req; struct scatterlist *sg; struct scatterlist *asg; struct scatterlist *sgout; const char *e, *d; struct tcrypt_result result; unsigned int authsize; void *input; void *output; void *assoc; char iv[MAX_IVLEN]; char *xbuf[XBUFSIZE]; char *xoutbuf[XBUFSIZE]; char *axbuf[XBUFSIZE]; if (testmgr_alloc_buf(xbuf)) goto out_noxbuf; if (testmgr_alloc_buf(axbuf)) goto out_noaxbuf; if (diff_dst && testmgr_alloc_buf(xoutbuf)) goto out_nooutbuf; /* avoid "the frame size is larger than 1024 bytes" compiler warning */ sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL); if (!sg) goto out_nosg; asg = &sg[8]; sgout = &asg[8]; if (diff_dst) d = "-ddst"; else d = ""; if (enc == ENCRYPT) e = "encryption"; else e = "decryption"; init_completion(&result.completion); req = aead_request_alloc(tfm, GFP_KERNEL); if (!req) { pr_err("alg: aead%s: Failed to allocate request for %s\n", d, algo); goto out; } aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &result); for (i = 0, j = 0; i < tcount; i++) { if (!template[i].np) { j++; /* some templates have no input data but they will * touch input */ input = xbuf[0]; input += align_offset; assoc = axbuf[0]; ret = -EINVAL; if (WARN_ON(align_offset + template[i].ilen > PAGE_SIZE || template[i].alen > PAGE_SIZE)) goto out; memcpy(input, template[i].input, template[i].ilen); memcpy(assoc, template[i].assoc, template[i].alen); if (template[i].iv) memcpy(iv, template[i].iv, MAX_IVLEN); else memset(iv, 0, MAX_IVLEN); crypto_aead_clear_flags(tfm, ~0); if (template[i].wk) crypto_aead_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); key = template[i].key; ret = crypto_aead_setkey(tfm, key, template[i].klen); if (!ret == template[i].fail) { pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n", d, j, algo, crypto_aead_get_flags(tfm)); goto out; } else if (ret) continue; authsize = abs(template[i].rlen - template[i].ilen); ret = crypto_aead_setauthsize(tfm, authsize); if (ret) {