CCM-AES from the Linux kernel

I need to be compatible with Crypto mech Solaris SUN_CKM_AES_CCM. On Linux, I find that I need to configure the AEAD request to get the "ccm (aes)" mech. The documentation for Linux Crypto looks pretty bad, the best example is the tcrypt.c test and kernel sources.

From Solaris, I performed a test encryption of a 512 byte block with 16 byte hmac and 12 byte iv. This should remain unchanged, and hopefully the results will be identical.

However, what I think should work does not work;

struct crypto_aead *tfm = NULL; struct aead_request *req; unsigned char key[16] = { 0x5c, 0x95, 0x64, 0x42, 0x00, 0x82, 0x1c, 0x9e, 0xd4, 0xac, 0x01, 0x83, 0xc4, 0x9c, 0x14, 0x97 }; unsigned int ivsize; int ret; struct scatterlist plaintext[1]; struct scatterlist ciphertext[1]; struct scatterlist hmactext[1]; unsigned char *plaindata = NULL; unsigned char *cipherdata = NULL; unsigned char *hmacdata = NULL; unsigned char *ivp = NULL; int i; unsigned char d; struct tcrypt_result result; tfm = crypto_alloc_aead("ccm(aes)", 0, 0); init_completion(&result.completion); req = aead_request_alloc(tfm, GFP_KERNEL); aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, cipher_work_done, &result); crypto_aead_clear_flags(tfm, ~0); ret = crypto_aead_setkey(tfm, key, sizeof(key)); ret = crypto_aead_setauthsize(tfm, 16); // authsize is hmac? ivsize = crypto_aead_ivsize(tfm); if (ivsize != 12) { printk("ivsize is not 12 %d - this needs to be fixed\n", ivsize); } plaindata = kmalloc(512, GFP_KERNEL); cipherdata = kmalloc(512, GFP_KERNEL); hmacdata = kmalloc(16, GFP_KERNEL); ivp = kmalloc(ivsize, GFP_KERNEL); if (!plaindata || !cipherdata || !hmacdata || !ivp) goto out; // put 00 01 02 03 ... in the input buffer... for (i = 0, d = 0; i < 512; i++, d++) plaindata[i] = d; memset(cipherdata, 0, 512); memset(hmacdata, 0, 16); memset(ivp, 0, ivsize); // Put a8 a9 aa .... in iv for (i = 0,d=0xa8; i < 12; i++, d++) ivp[i] = d; sg_init_one(&plaintext[0], plaindata, 512); sg_init_one(&ciphertext[0], cipherdata, 512); sg_init_one(&hmactext[0], hmacdata, 16); aead_request_set_crypt(req, plaintext, ciphertext, 512, ivp); aead_request_set_assoc(req, hmactext, 16); ret = crypto_aead_encrypt(req); printk("cipher call returns %d \n", ret); 

And we will return to the fact that ivsize is 16 (and I see no way to set it to 12), and this will encrypt with the error "-22" or EINVAL. There are many errors in the code that are deleted here, which confirm the success of all previous calls.

As far as I can tell, I pretty closely follow the sources of tcrypt.c. However, I am wondering if a forced ivsize = 16 mean that I cannot use the provided algorithm. Otherwise, it would be nice to see that the encryption call succeeded and what was placed in the output of cipherdata.

The code is placed in the kernel module and launched in _init (). I originally used blkcipher "aes", which works, but is not a variant of ccm-aes. This made me change the use of aead, which I cannot work with.

+4
source share
1 answer

Ok, this is what I found out.

1) Call iv nonce app. And let me call the inner cryptowald iv iv . It turns out that Solaris code uses nonce-len=12 , but the CCM-AES algorithm still uses iv-len=16 .

From the sources of the Solaris iv core consists of:

 iv[0] = 1..7, based on ivlen 16 - noncelen 12 = 2. iv[1] = the nonce data (12 bytes). iv[14] = 0 iv[15] = 1 

So, on Linux, I want "ccm (aes)" with ivlen 16 and properly prepare iv from nonce .

2) When crypto_aead_encrypt() called, the previous crypto_aead_encrypt() call is ignored, and the HMAC is placed at the end of the encryption buffer. In my case, in the ciphertext [512], for 16 bytes. Thus, the input must have a length of +16.

Using a scatter list, the HMAC β€œat the end” can be somewhere else if configured correctly.

3) When crypto_aead_decrypt() called, the cryptolen must be +16 (cipherinputlen + maclen). The MAC is read from the end of the input buffer, that is, ciphertext [512] for 16 bytes. Which can also be a separate buffer using a scatter list.

4) crypto_aead_setauthsize() checks the correctness of the given length, and then does nothing with it. Do not think that this actually sets the size!

5) aead_request_set_assoc() should be set, even if it is just a buffer of zeros.

+4
source

Source: https://habr.com/ru/post/1444747/


All Articles