aes ccm模式 java,CCM-AES从Linux内核

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.

解决方案

Ok, this is what I have learnt.

1)

Let's call the Application's iv nonce. And let's call the internal crypto's iv iv. It turns out that the Solaris code is using nonce-len=12, but the CCM-AES algorithm still uses iv-len=16.

From Solaris kernel sources, iv is made up with:

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 prepare the iv from nonce properly.

2)

When calling crypto_aead_encrypt() the prior call of aead_request_set_assoc() is ignored, and HMAC is put at the end of the cipher buffer. In my case, at ciphertext[512], for 16 bytes. So the input needed to be +16 in length.

Using scatterlist, the HMAC "at the end" can be somewhere different if set up correctly.

3)

When calling crypto_aead_decrypt() the cryptolen should be +16 (cipherinputlen + maclen). The MAC is read from end of input buffer, ie, ciphertext[512] for 16 bytes. Which can also be a separate buffer using scatterlist.

4)

crypto_aead_setauthsize() checks that the len given is correct, then does nothing with it. Don't think this actually sets the size!

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CCM (Counter with CBC-MAC) 模式是一种加密模式,它同时提供了加密和完整性保护。在 Java 中使用 CCM 模式需要使用 Java Cryptography Extension (JCE) 提供的 API。 下面是使用 Java 实现 AES CCM 模式的示例代码: ```java import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AESCCMExample { public static void main(String[] args) throws Exception { // 16-byte AES key byte[] keyBytes = "0123456789abcdef".getBytes("UTF-8"); SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); // 12-byte nonce byte[] nonceBytes = "123456789012".getBytes("UTF-8"); IvParameterSpec nonce = new IvParameterSpec(nonceBytes); // plaintext String plaintext = "Hello, world!"; // create cipher object and initialize with key and nonce Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, nonce); // encrypt plaintext byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8")); // print ciphertext System.out.println("Ciphertext: " + new String(ciphertext, "UTF-8")); // initialize cipher object for decryption cipher.init(Cipher.DECRYPT_MODE, key, nonce); // decrypt ciphertext byte[] decrypted = cipher.doFinal(ciphertext); // print decrypted plaintext System.out.println("Decrypted plaintext: " + new String(decrypted, "UTF-8")); } } ``` 在上面的示例代码中,我们使用 16 字节的 AES 密钥和 12 字节的随机数(也称为“nonce”)来加密明文。我们使用 `Cipher` 类的 `getInstance` 方法和 `AES/CCM/NoPadding` 参数来创建一个 CCM 模式的 `Cipher` 对象。然后,我们使用 `init` 方法初始化 `Cipher` 对象以进行加密或解密操作。在加密示例中,我们使用 `doFinal` 方法对明文进行加密,并打印出密文。在解密示例中,我们使用相同的密钥和随机数来初始化 `Cipher` 对象,然后使用 `doFinal` 方法对密文进行解密,并打印出明文。 请注意,Java 中的 CCM 模式要求随机数长度为 7 到 13 个字节,并且密文长度不能超过 $2^{16}-2^{8}(m_L+2)$ 个字节,其中 $m_L$ 是消息长度的编码长度(通常为 2 或 3 个字节)。因此,我们在示例代码中使用了 12 字节的随机数,并对明文长度没有做限制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值