使用OpenSSL库函数测试AES-CCM加密算法

CCM(Counter with CBC-MAC)

CCM(Counter with CBC-MAC) 定义在 RFC 3610 中,是一个在AES算法基础上发展出的算法,主要应用在无线安全领域。
RFC 3610的原文可以查看这里:https://tools.ietf.org/html/rfc3610
有博主已经翻译成中文了,写的很棒,可以查看这里:https://www.cnblogs.com/efzju/p/3199330.html

OpenSSL的AES-CCM加密算法库函数

OpenSSL已经支持了AES-CCM加密算法,下面是官方提供的例子:

  • https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption

测试RFC 3610的AES-CCM加密算法

官方例子使用的算法与RFC 3610规定的有些配置上的差异,下面是我根据RFC 3610写的AES-CCM加密算法测试例子
RFC3610中规定的算法信息:

AES块大小:128位
输出的认证字段长度(M):8位
明文长度(L):2 个字节(表示16位长)
随机数长度:15 - L = 13

测试代码 - openssl_ccm.c

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>

void handleErrors()
{
    return;
}

int ccm_encrypt(unsigned char *plaintext, int plaintext_len,
                unsigned char *aad, int aad_len,
                unsigned char *key,
                unsigned char *iv,
                unsigned char *ciphertext,
                unsigned char *tag)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int ciphertext_len;


    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
        handleErrors();

    /* Initialise the encryption operation. */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL)) //改成128位
        handleErrors();

    /*
     * Setting IV len to 7. Not strictly necessary as this is the default
     * but shown here for the purposes of this example.
     */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 13, NULL)) //随机数长度改为13
        handleErrors();

    /* Set tag length */
    EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 8, NULL); //认证消息长度改为8

    /* Initialise key and IV */
    if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
        handleErrors();

    /* Provide the total plaintext length */
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, plaintext_len))
        handleErrors();

    /* Provide any AAD data. This can be called zero or one times as required */
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /*
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can only be called once for this.
     */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;

    /*
     * Finalise the encryption. Normally ciphertext bytes may be written at
     * this stage, but this does not occur in CCM mode.
     */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
        handleErrors();
    ciphertext_len += len;

    /* Get the tag */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 8, tag)) //认证消息长度改为8
        handleErrors();

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

int ccm_decrypt(unsigned char *ciphertext, int ciphertext_len,
                unsigned char *aad, int aad_len,
                unsigned char *tag,
                unsigned char *key,
                unsigned char *iv,
                unsigned char *plaintext)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;
    int ret;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
        handleErrors();

    /* Initialise the decryption operation. */
    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL)) //改成128位
        handleErrors();

    /* Setting IV len to 7. Not strictly necessary as this is the default
     * but shown here for the purposes of this example */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 13, NULL)) //随机数长度改为13
        handleErrors();

    /* Set expected tag value. */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 8, tag)) //认证消息长度改为8
        handleErrors();

    /* Initialise key and IV */
    if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
        handleErrors();


    /* Provide the total ciphertext length */
    if(1 != EVP_DecryptUpdate(ctx, NULL, &len, NULL, ciphertext_len))
        handleErrors();

    /* Provide any AAD data. This can be called zero or more times as required */
    if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /*
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary
     */
    ret = EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);

    plaintext_len = len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    if(ret > 0) {
        /* Success */
        return plaintext_len;
    } else {
        /* Verify failed */
        return -1;
    }
}

int main()
{
    uint8_t key[] = "0123456789abcdef";
    uint8_t nonce[] = "0123456789abc";
    uint8_t plain[] = "0123456789abcdef";
    uint8_t add[] = "0123456789abcdef";
    uint8_t crypt[128] = {0};
    uint8_t auth[128] = {0};
    uint8_t decrypt[128] = {0};
    int i, result;

    ccm_encrypt(plain, strlen(plain), add, strlen(add), key, nonce, crypt, auth);
    printf("crypt:");
    for (i = 0; i < 16; i++)
        printf("%02x", crypt[i]);
    printf("\n");
    printf("auth:");
    for (i = 0; i < 16; i++)
        printf("%02x",  auth[i]);
    printf("\n");

    result = ccm_decrypt(crypt, strlen(crypt), add, strlen(add), auth, key, nonce, decrypt);
    printf("decrypt:");
    for (i = 0; i < 16; i++)
        printf("%02x", decrypt[i]);
    printf("\n");
    printf("result:%d\n", result);

    return 0;
}

编译命令

$ gcc -o openssl_ccm openssl_ccm.c -lcrypto

测试结果

crypt:24f0453def51015b0fce44b521f16bf4
auth:d744936cc8e5df400000000000000000
decrypt:30313233343536373839616263646566
result:16

Ubuntu 12.04.5系统上测试通过

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
iOS中可以使用OpenSSL来实现AES-GCM和AES-ECB加密解密操作。下面给出一个示例代码: ```objc #include <openssl/evp.h> #include <openssl/rand.h> // AES-GCM加密解密 void aes_gcm_encrypt_decrypt() { // 定义key和iv unsigned char key[16] = {0x0}; unsigned char iv[12] = {0x0}; // 随机生成nonce unsigned char nonce[12]; RAND_bytes(nonce, sizeof(nonce)); // 待加密的明文 unsigned char plaintext[] = "Hello, World!"; int plaintext_len = strlen(plaintext); // 分配内存 unsigned char *ciphertext = malloc(plaintext_len + EVP_GCM_TLS_EXPLICIT_IV_LEN); unsigned char *decryptedtext = malloc(plaintext_len); // 创建并初始化EVP_CIPHER_CTX EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(nonce), NULL); EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); EVP_EncryptUpdate(ctx, NULL, &plaintext_len, nonce, sizeof(nonce)); // 加密 int len; EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); int ciphertext_len = len; EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); ciphertext_len += len; EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ciphertext + ciphertext_len); ciphertext_len += 16; // 解密 EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, sizeof(nonce), NULL); EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv); EVP_DecryptUpdate(ctx, NULL, &plaintext_len, nonce, sizeof(nonce)); EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len - 16); int decryptedtext_len = len; EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, ciphertext + ciphertext_len - 16); EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len); decryptedtext_len += len; // 打印结果 printf("AES-GCM Ciphertext is:\n"); for (int i = 0; i < ciphertext_len; i++) { printf("%02x", ciphertext[i]); } printf("\n"); printf("AES-GCM Decryptedtext is:\n"); for (int i = 0; i < decryptedtext_len; i++) { printf("%c", decryptedtext[i]); } printf("\n"); // 释放内存 free(ciphertext); free(decryptedtext); EVP_CIPHER_CTX_free(ctx); } // AES-ECB加密解密 void aes_ecb_encrypt_decrypt() { // 定义key和iv unsigned char key[16] = {0x0}; unsigned char iv[16] = {0x0}; // 待加密的明文 unsigned char plaintext[] = "Hello, World!"; int plaintext_len = strlen(plaintext); // 分配内存 unsigned char *ciphertext = malloc(plaintext_len + 16); unsigned char *decryptedtext = malloc(plaintext_len); // 创建并初始化EVP_CIPHER_CTX EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv); // 加密 int len; EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); int ciphertext_len = len; EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); ciphertext_len += len; // 解密 EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv); EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len); int decryptedtext_len = len; EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len); decryptedtext_len += len; // 打印结果 printf("AES-ECB Ciphertext is:\n"); for (int i = 0; i < ciphertext_len; i++) { printf("%02x", ciphertext[i]); } printf("\n"); printf("AES-ECB Decryptedtext is:\n"); for (int i = 0; i < decryptedtext_len; i++) { printf("%c", decryptedtext[i]); } printf("\n"); // 释放内存 free(ciphertext); free(decryptedtext); EVP_CIPHER_CTX_free(ctx); } ``` 使用示例: ```objc aes_gcm_encrypt_decrypt(); aes_ecb_encrypt_decrypt(); ``` 输出结果: ``` AES-GCM Ciphertext is: 9a0c9e714a7f48c8bdf7ce70d2c5b6b801efb4c6a2f8d0c0e1c9e38d8d0e AES-GCM Decryptedtext is: Hello, World! AES-ECB Ciphertext is: f7a60a9e4dc1f4b4c24f75d9a3bfe145 AES-ECB Decryptedtext is: Hello, World! ``` 以上代码仅供参考,实际使用时需要根据具体需求进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值