+static void test_aead(char *algo, int enc, struct aead_testvec *template,
+ unsigned int tcount)
+{
+ unsigned int ret, i, j, k, temp;
+ unsigned int tsize;
+ char *q;
+ struct crypto_aead *tfm;
+ char *key;
+ struct aead_testvec *aead_tv;
+ struct aead_request *req;
+ struct scatterlist sg[8];
+ struct scatterlist asg[8];
+ const char *e;
+ struct tcrypt_result result;
+ unsigned int authsize;
+
+ if (enc == ENCRYPT)
+ e = "encryption";
+ else
+ e = "decryption";
+
+ printk(KERN_INFO "\ntesting %s %s\n", algo, e);
+
+ tsize = sizeof(struct aead_testvec);
+ tsize *= tcount;
+
+ if (tsize > TVMEMSIZE) {
+ printk(KERN_INFO "template (%u) too big for tvmem (%u)\n",
+ tsize, TVMEMSIZE);
+ return;
+ }
+
+ memcpy(tvmem, template, tsize);
+ aead_tv = (void *)tvmem;
+
+ init_completion(&result.completion);
+
+ tfm = crypto_alloc_aead(algo, 0, 0);
+
+ if (IS_ERR(tfm)) {
+ printk(KERN_INFO "failed to load transform for %s: %ld\n",
+ algo, PTR_ERR(tfm));
+ return;
+ }
+
+ req = aead_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ printk(KERN_INFO "failed to allocate request for %s\n", 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 (!aead_tv[i].np) {
+ printk(KERN_INFO "test %u (%d bit key):\n",
+ ++j, aead_tv[i].klen * 8);
+
+ crypto_aead_clear_flags(tfm, ~0);
+ if (aead_tv[i].wk)
+ crypto_aead_set_flags(
+ tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+ key = aead_tv[i].key;
+
+ ret = crypto_aead_setkey(tfm, key,
+ aead_tv[i].klen);
+ if (ret) {
+ printk(KERN_INFO "setkey() failed flags=%x\n",
+ crypto_aead_get_flags(tfm));
+
+ if (!aead_tv[i].fail)
+ goto out;
+ }
+
+ authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen);
+ ret = crypto_aead_setauthsize(tfm, authsize);
+ if (ret) {
+ printk(KERN_INFO
+ "failed to set authsize = %u\n",
+ authsize);
+ goto out;
+ }
+
+ sg_init_one(&sg[0], aead_tv[i].input,
+ aead_tv[i].ilen + (enc ? authsize : 0));
+
+ sg_init_one(&asg[0], aead_tv[i].assoc,
+ aead_tv[i].alen);
+
+ aead_request_set_crypt(req, sg, sg,
+ aead_tv[i].ilen,
+ aead_tv[i].iv);
+
+ aead_request_set_assoc(req, asg, aead_tv[i].alen);
+
+ ret = enc ?
+ crypto_aead_encrypt(req) :
+ crypto_aead_decrypt(req);
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret && !(ret = result.err)) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk(KERN_INFO "%s () failed err=%d\n",
+ e, -ret);
+ goto out;
+ }
+
+ q = kmap(sg_page(&sg[0])) + sg[0].offset;
+ hexdump(q, aead_tv[i].rlen);
+
+ printk(KERN_INFO "enc/dec: %s\n",
+ memcmp(q, aead_tv[i].result,
+ aead_tv[i].rlen) ? "fail" : "pass");
+ }
+ }
+
+ printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
+ memset(xbuf, 0, XBUFSIZE);
+ memset(axbuf, 0, XBUFSIZE);
+
+ for (i = 0, j = 0; i < tcount; i++) {
+ if (aead_tv[i].np) {
+ printk(KERN_INFO "test %u (%d bit key):\n",
+ ++j, aead_tv[i].klen * 8);
+
+ crypto_aead_clear_flags(tfm, ~0);
+ if (aead_tv[i].wk)
+ crypto_aead_set_flags(
+ tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+ key = aead_tv[i].key;
+
+ ret = crypto_aead_setkey(tfm, key, aead_tv[i].klen);
+ if (ret) {
+ printk(KERN_INFO "setkey() failed flags=%x\n",
+ crypto_aead_get_flags(tfm));
+
+ if (!aead_tv[i].fail)
+ goto out;
+ }
+
+ sg_init_table(sg, aead_tv[i].np);
+ for (k = 0, temp = 0; k < aead_tv[i].np; k++) {
+ memcpy(&xbuf[IDX[k]],
+ aead_tv[i].input + temp,
+ aead_tv[i].tap[k]);
+ temp += aead_tv[i].tap[k];
+ sg_set_buf(&sg[k], &xbuf[IDX[k]],
+ aead_tv[i].tap[k]);
+ }
+
+ authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen);
+ ret = crypto_aead_setauthsize(tfm, authsize);
+ if (ret) {
+ printk(KERN_INFO
+ "failed to set authsize = %u\n",
+ authsize);
+ goto out;
+ }
+
+ if (enc)
+ sg[k - 1].length += authsize;
+
+ sg_init_table(asg, aead_tv[i].anp);
+ for (k = 0, temp = 0; k < aead_tv[i].anp; k++) {
+ memcpy(&axbuf[IDX[k]],
+ aead_tv[i].assoc + temp,
+ aead_tv[i].atap[k]);
+ temp += aead_tv[i].atap[k];
+ sg_set_buf(&asg[k], &axbuf[IDX[k]],
+ aead_tv[i].atap[k]);
+ }
+
+ aead_request_set_crypt(req, sg, sg,
+ aead_tv[i].ilen,
+ aead_tv[i].iv);
+
+ aead_request_set_assoc(req, asg, aead_tv[i].alen);
+
+ ret = enc ?
+ crypto_aead_encrypt(req) :
+ crypto_aead_decrypt(req);
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret && !(ret = result.err)) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk(KERN_INFO "%s () failed err=%d\n",
+ e, -ret);
+ goto out;
+ }
+
+ for (k = 0, temp = 0; k < aead_tv[i].np; k++) {
+ printk(KERN_INFO "page %u\n", k);
+ q = kmap(sg_page(&sg[k])) + sg[k].offset;
+ hexdump(q, aead_tv[i].tap[k]);
+ printk(KERN_INFO "%s\n",
+ memcmp(q, aead_tv[i].result + temp,
+ aead_tv[i].tap[k] -
+ (k < aead_tv[i].np - 1 || enc ?
+ 0 : authsize)) ?
+ "fail" : "pass");
+
+ temp += aead_tv[i].tap[k];
+ }
+ }
+ }
+
+out:
+ crypto_free_aead(tfm);
+ aead_request_free(req);
+}
+