5

I need to be compatible with Solaris crypto mech SUN_CKM_AES_CCM. In Linux, I believe I should setup an AEAD request to get "ccm(aes)" mech. Documentation for Linux Crypto does seem rather poor, the best example appears to be tcrypt.c test, and kernel sources.

From Solaris, I did a test encryption of a 512 byte block, with 16 byte hmac, and 12 byte iv. This needs to stay the same, and hopefully the results be identical.

However, what I think should would work, does not;

   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 what we get back is that ivsize is 16 (and I see no way to set it to 12), and that encrypt fails with "-22" or EINVAL. There are lots of errors checking in the code, removed here, that confirm all prior call return success.

As far as I can tell, I follow the tcrypt.c sources pretty close. However, I wonder if the forced ivsize = 16 will mean I can not use the supplied algorithm anyway. That aside, it would be nice to see the encrypt call succeed and what is put in the cipherdata output.

The code is put into a kernel module, and run at _init() time. Initially I used blkcipher "aes", which works, but is not the ccm-aes variant. This made me change to use aead, which I can not get to work.

4

1 に答える 1

5

わかりました、これは私が学んだことです。

1)アプリケーションのivを呼び出しましょうnonce。そして、内部暗号のivと呼びましょうiv。Solarisコードはを使用していることがわかりましnonce-len=12たが、CCM-AESアルゴリズムは引き続きを使用していますiv-len=16

Solarisカーネルソースから、ivで構成されています:

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

したがって、Linuxでは、ivlen 16で「ccm(aes)」が必要であり、ivfromをnonce適切に準備します。

2)crypto_aead_encrypt()の前の呼び出しを呼び出す場合aead_request_set_assoc()は無視され、HMACは暗号バッファの最後に配置されます。私の場合、暗号文[512]で16バイト。したがって、入力の長さは+16である必要がありました。

スキャッターリストを使用すると、正しく設定されている場合、「最後の」HMACはどこか異なる可能性があります。

3)crypto_aead_decrypt()cryptolenを呼び出すときは、+ 16(cipherinputlen + maclen)にする必要があります。MACは、入力バッファの最後、つまり16バイトの暗号文[512]から読み取られます。これは、スキャッターリストを使用して別のバッファーにすることもできます。

4) crypto_aead_setauthsize()指定されたlenが正しいことを確認し、それに対して何もしません。これが実際にサイズを設定するとは思わないでください!

5)aead_request_set_assoc()ゼロのバッファだけであっても、設定する必要があります。

于 2012-11-13T07:12:44.517 に答える