我需要与 Solaris 加密机制 SUN_CKM_AES_CCM 兼容。在 Linux 中,我相信我应该设置一个 AEAD 请求来获取“ccm(aes)”机械。 Linux Crypto 的文档看起来确实很差,最好的例子似乎是 tcrypt.c 测试和内核源代码。
我在 Solaris 上对一个 512 字节的 block 进行了测试加密,其中包含 16 字节的 hmac 和 12 字节的 iv。这需要保持不变,并希望结果相同。
但是,我认为应该会起作用,但实际上并没有;
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);
我们得到的结果是 ivsize 是 16(我看不出有什么办法可以将它设置为 12),并且加密失败并返回“-22”或 EINVAL。代码中有很多错误检查,已在此处删除,确认所有先前的调用返回成功。
据我所知,我非常关注 tcrypt.c 源代码。但是,我想知道强制 ivsize = 16
是否意味着我无论如何都无法使用提供的算法。除此之外,很高兴看到加密调用成功以及密码数据输出中放入了什么。
代码被放入内核模块,并在 _init() 时运行。最初我使用 blkcipher“aes”,它可以工作,但不是 ccm-aes 变体。这让我改用 aead,但我无法开始工作。
最佳答案
好的,这就是我学到的。
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 上,我想要“ccm(aes)”和 ivlen 16,并从 nonce
中正确准备 iv
。
2)
当调用 crypto_aead_encrypt()
时,先前调用的 aead_request_set_assoc()
被忽略,HMAC 被放在密码缓冲区的末尾。在我的例子中,在 ciphertext[512],16 个字节。因此输入的长度需要为 +16。
使用分散列表,如果设置正确,“末尾”的 HMAC 可能会有所不同。
3)
当调用 crypto_aead_decrypt()
时,cryptolen 应该是 +16 (cipherinputlen + maclen)。从输入缓冲区的末尾读取 MAC,即 16 字节的 ciphertext[512]。这也可以是使用 scatterlist 的单独缓冲区。
4)
crypto_aead_setauthsize()
检查给定的 len 是否正确,然后不对其执行任何操作。不要认为这实际上设置了大小!
5) aead_request_set_assoc()
必须设置,即使它只是一个零缓冲区。
关于来自 Linux 内核的 CCM-AES,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13284986/