环境

操作系统:WSL2-Ubuntu22.04

加密库:mbedtlsBase64

在线AES计算网站:SSLeye

代码中需要用到mbedtls和Base64,可以根据上述链接获取


简介

高级加密标准(Advanced Encryption Standard,AES),是一种对称加密方式。AES支持三种加密方式:AES128,AES192,AES256,AES128标识密钥长度为128bit,AES128运算速度最快,AES256安全性最佳,三种方式的本质区别是加密轮数不同。


模式

一共有4种加密模式,即ECB、CBC、CFB、OFB,本文仅讲解最常见的ECB、CBC模式,有机会更新后续两种。

ECB模式:

优点:1.简单;2.有利于并行计算;3.误差不会被传送
缺点: 1.不能隐藏明文的模式(例如加密一张图片,虽然看不到原图,但是可能看到其轮廓);2.可能对明文进行主动攻击

CBC模式:

优点:1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准
缺点:1.不利于并行计算;2.误差传递;3.需要初始化向量IV


API简介

初始化/释放句柄

void mbedtls_aes_init( mbedtls_aes_context *ctx );
void mbedtls_aes_free( mbedtls_aes_context *ctx );


生成加/解密的密钥

int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits );
int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits );

ctx:句柄

key:密钥,必须16、24或32Bytes

keybits:密钥长度,128、192或256bit


ECB加/解密,每次执行一个块,一个块为16Bytes,明文不足一个块的需要进行补位

int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
                    int mode,
                    const unsigned char input[16],
                    unsigned char output[16] );

ctx:句柄

mode:MBEDTLS_AES_ENCRYPT或MBEDTLS_AES_DECRYPT

input:输入指针,长度不足一个块16Bytes的需要进行补位

output:输出指针,长度为一个块16Bytes


CBC加/解密,可以加密任意长度的明文(必须补齐为16的整倍数)

int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx,
                    int mode,
                    size_t length,
                    unsigned char iv[16],
                    const unsigned char *input,
                    unsigned char *output );

ctx:句柄

mode:MBEDTLS_AES_ENCRYPT或MBEDTLS_AES_DECRYPT

length:输入长度(必须补齐为16的整倍数)

iv:初始化向量,必须为16字节且可读写。每个块运算完之后会生成新的向量传给下一个块运算,所以加密完成后此值会改变,解密时应该重新赋值。

input:输入指针

output:输出指针


ECB加/解密DEMO

#include <string.h>
#include <stdio.h>
#include "mbedtls/aes.h"
#include "base64.h"

int main(void)
{
    mbedtls_aes_context aes_ctx;
    unsigned char aes_in[16] = "123456789abcdef";
    unsigned char aes_out[16];
    unsigned char b64_out[1024] = {0};

    mbedtls_aes_init(&aes_ctx);

/****************************加密****************************/    
    // 加载加密密钥
    mbedtls_aes_setkey_enc(&aes_ctx, "1234567890123456", 128);

    // 加密 一次执行一个块即16BYTE
    mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, aes_in, aes_out);
    
    // 以base64编码形式打印
    base64_encode(aes_out, 16, b64_out);
    printf("%s\r\n", b64_out);
    // ahBLMYUa/tgH+sxQNzZxyw==

/****************************解密****************************/
    memset(aes_in, 0, 16);

    // 加载解密密钥
    mbedtls_aes_setkey_dec(&aes_ctx, "1234567890123456", 128);

    // 解密
    mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, aes_out, aes_in);

    printf("%s\r\n", aes_in);
    // 123456789abcdef

/****************************End****************************/
    mbedtls_aes_free(&aes_ctx);
}


CBC加/解密DEMO

#include <string.h>
#include <stdio.h>
#include "mbedtls/aes.h"
#include "base64.h"

int main(void)
{
    mbedtls_aes_context aes_ctx;
    unsigned char ivec[16] = "1234567890123456";
    unsigned char aes_in[32] = "1234567890123456789";
    unsigned char aes_out[32];
    unsigned char b64_out[1024] = {0};

    mbedtls_aes_init(&aes_ctx);

/****************************加密****************************/    
    // 加载加密密钥
    mbedtls_aes_setkey_enc(&aes_ctx, "1234567890123456", 128);

    // 加密
    mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, 32, ivec, aes_in, aes_out);
    
    // 以base64编码形式打印
    base64_encode(aes_out, 32, b64_out);
    printf("%s\r\n", b64_out);
    // 2LWYSMdnDJSym1TSN54uer0JwNlyHlQcjnl1uQ7ofOw=

/****************************解密****************************/
    memset(aes_in, 0, 32);

    // 加载解密密钥
    mbedtls_aes_setkey_dec(&aes_ctx, "1234567890123456", 128);

    memcpy(ivec, "1234567890123456", 16);

    // 解密
    mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, 32, ivec, aes_out, aes_in);

    printf("%s\r\n", aes_in);
    // 1234567890123456789
    
/****************************End****************************/
    mbedtls_aes_free(&aes_ctx);
}