Hello i'm trying to use the authenc module and i wrote a small kernel module that simply encrypts/decrypts a fixed data using the hmac(sha1) as authentication algorithm and cbc(aes) as encryption algorithm. The used platform is a KVM quest with Fedora 12 i686 and the latest kernel 2.6.33. I have taken the code from the testmgr and from net/ipv4/esp4.c. But, when testing the code, attached in this mail, the crypto_aead_decrypt() function always replies -EBADMSG. I tried the same code in a 64-bit machine (user mode kernel and Fedora 12) and the decryption was successful. I noted, when comparing the auth portion in both systems, that this computed during the encryption from the 32bit KVM guest, was different and with no fixed value. I investigated in the code of authenc and i recorded some partial result of the encryption operation. That is the log: --------- testing authenc: encrypt --------------- assoc: 495C501F1D94CC81BAB7B603AFA5C1A1D85C4268E06CDA8905AC56AC1B2AD386 alg: No test for authenc(hmac(sha1),cbc(aes)) (authenc(hmac(sha1- generic),cbc(aes-asm))) Setting ahash key: 313233343536373839303132 Setting blk key: 31323334353637383930313233343536 crypto_authenc_encrypt: ivsize 16 iv: 01010101010101010101010101010101 crypto_authenc_genicv: dump vdst: CFE3A997243F38B0D6A89DCAB5126DC93952E493E72EA590CC8D186A4E1654860000000000000000000000000000000000000000 crypto_authenc_genicv ivsize 16,dst offset 3392 iv 01010101010101010101010101010101 crypto_authenc_genicv: iv after sg_init_table 00000000000000000101010101010101 crypto_authenc_genicv: vdst == iv + ivsize? 0 crypto_authenc_genicv: scatterlist dst 0 before fn assignement (line 355): 3242265088, 388, 32, dump: 495C501F1D94CC81BAB7B603AFA5C1A1D85C4268E06CDA8905AC56AC1B2AD386 crypto_authenc_genicv: scatterlist dst 1 before fn assignement (line 355): 3727819872, 0, 0, dump: crypto_authenc_genicv: scatterlist dst 2 before fn assignement (line 355): 3241960448, 1152, 16, dump: 00000000000000000101010101010101 crypto_authenc_genicv: scatterlist dst 3 before fn assignement (line 355): 3747577608, 0, 0, dump: crypto_authenc_genicv: scatterlist dst 0 after fn assignement (line 355): 3242265088, 388, 32, dump: 495C501F1D94CC81BAB7B603AFA5C1A1D85C4268E06CDA8905AC56AC1B2AD386 crypto_authenc_genicv: scatterlist dst 1 after fn assignement (line 355): 3727819872, 0, 0, dump: crypto_authenc_genicv: scatterlist dst 2 after fn assignement (line 355): 3241960448, 1152, 16, dump: 0000000000000000C01886E0201986E0 crypto_authenc_genicv: scatterlist dst 2 after fn assignement (line 355):: 3747577608, 0, 0, dump: -------------------------------------------------- Just for test, i tried to add a 16bit long offset when defining the memory address for the "iv" in the function crypto_authenc_encrypt() for the 32-bit kernel, and everything works fine. I don't know if i made a mistake in the code that causes this misbehaviour in the authenc module or if it is a bug. Thanks in advance for the reply.
#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 <crypto/authenc.h> #include <linux/pagemap.h> #include <linux/rtnetlink.h> #define MAX_IVLEN 16 #define AUTHSIZE 20 int testmode = 0; module_param(testmode, int, 0); void hexdump(unsigned char *buf, int len) { while(--len >=0) printk("%02X", *buf++); printk("\n"); } struct tcrypt_result { struct completion completion; int err; }; 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 testrun(void) { const char *algo = "authenc(hmac(sha1),cbc(aes))"; struct crypto_aead *tfm; unsigned int i; int ret = -ENOMEM; unsigned char *ekey = "1234567890123456"; unsigned char *akey = "123456789012"; unsigned char *key, *pp; unsigned int ekeylen = 16; unsigned int akeylen = 12; unsigned int keylen = 0; struct aead_request *req; struct tcrypt_result result; unsigned int authsize = AUTHSIZE; char *assoc = "\x49\x5c\x50\x1f\x1d\x94\xcc\x81" "\xba\xb7\xb6\x03\xaf\xa5\xc1\xa1" "\xd8\x5c\x42\x68\xe0\x6c\xda\x89" "\x05\xac\x56\xac\x1b\x2a\xd3\x86"; int assoclen = 32; unsigned char iv[MAX_IVLEN]; mm_segment_t old_fs = get_fs(); struct file *fp; struct scatterlist src_sg, dst_sg; struct scatterlist asg; char *filename = "file1.txt"; char *string = "ciao"; struct crypto_authenc_key_param *param; struct rtattr *rta; char *input; int blksize = 0; int clen = 16; /* len of data */ printk("assoc: "); hexdump(assoc, 32); tfm = crypto_alloc_aead(algo, 0, 0); if (IS_ERR(tfm)) { printk(KERN_ERR "alg: aead: Failed to load transform for %s: " "%ld\n", algo, PTR_ERR(tfm)); goto out; } blksize = ALIGN(crypto_aead_blocksize(tfm), 4); clen = ALIGN(clen + 2, blksize); input = kzalloc(clen + AUTHSIZE, GFP_KERNEL); if(!testmode) { set_fs(KERNEL_DS); fp = filp_open(filename, O_RDONLY, 0); if(IS_ERR(fp)) { printk("Error opening file: %s\n", filename); set_fs(old_fs); goto out; } fp->f_op->read(fp, input, clen + AUTHSIZE, &fp->f_pos); filp_close(fp, NULL); set_fs(old_fs); } else memcpy(input, string, strlen(string)); init_completion(&result.completion); req = aead_request_alloc(tfm, GFP_KERNEL); if (!req) { printk(KERN_ERR "alg: aead: Failed to allocate request for " "%s\n", algo); goto out_tfm; } aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &result); memset(iv, 1, MAX_IVLEN); crypto_aead_clear_flags(tfm, ~0); crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); keylen = akeylen + ekeylen + RTA_SPACE(sizeof(*param)); key = kzalloc(keylen, GFP_KERNEL); if (!key) goto out_req; pp = key; rta = (void *)pp; rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; rta->rta_len = RTA_LENGTH(sizeof(*param)); param = RTA_DATA(rta); pp += RTA_SPACE(sizeof(*param)); if(akeylen) { memcpy(pp, akey, akeylen); pp += akeylen; } ret = crypto_aead_setauthsize(tfm, authsize); if (ret) { printk(KERN_ERR "alg: aead: Failed to set " "authsize to %u on test for %s\n", authsize, algo); goto out_key; } param->enckeylen = cpu_to_be32(ekeylen); memcpy(pp, ekey, ekeylen); ret = crypto_aead_setkey(tfm, key, keylen); if (ret) { printk(KERN_ERR "alg: aead: Failed to set " "the key for %s\n", algo); goto out_key; } sg_init_one(&src_sg, input, clen + AUTHSIZE); sg_init_one(&dst_sg, input, clen + AUTHSIZE); sg_init_one(&asg, assoc, assoclen); aead_request_set_crypt(req, &src_sg, &dst_sg, clen + (testmode ? 0 : authsize), iv); aead_request_set_assoc(req, &asg, assoclen); ret = testmode ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); switch (ret) { case 0: if(!testmode) printk("File OK\n"); break; case -EINPROGRESS: case -EBUSY: ret = wait_for_completion_interruptible( &result.completion); if (!ret && !(ret = result.err)) { INIT_COMPLETION(result.completion); break; } case -EBADMSG: printk("File corrupted\n"); default: printk(KERN_ERR "alg: aead: %s failed " "for %s: ret=%d\n", testmode ? "encrypt" : "decrypt", algo, -ret); } if(ret) goto out_key; printk("%s: %d\n", testmode ? "encrypt" : "decrypt", ret); if(testmode) { set_fs(KERNEL_DS); fp = filp_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0700); if(IS_ERR(fp)) { printk("Error opening file: %s\n", filename); set_fs(old_fs); goto out_key; } fp->f_op->write(fp, input, clen + AUTHSIZE, &fp->f_pos); hexdump(input + clen, AUTHSIZE); filp_close(fp, NULL); set_fs(old_fs); } else { printk("Decrypted: %s\n", input); } kfree(input); out_key: kfree(key); out_req: aead_request_free(req); out_tfm: crypto_free_aead(tfm); out: return ret; } int __init testaead_start(void) { int ret; printk("--------- testing authenc: %s ---------------\n", testmode ? "encrypt" : "decrypt"); ret = testrun(); printk("Result: %d\n", ret); printk("--------------------------------------------------\n"); return -1; } void __exit testaead_stop(void) { } module_init(testaead_start); module_exit(testaead_stop); MODULE_LICENSE("GPL");