int mbedtls_aes_crypt_cbc(
    mbedtls_aes_context* ctx,
    int mode,
    size_t inputLength,
    unsigned char iv[16],
    const unsigned char* input,
    unsigned char* output
)
1.0、参考
1.1、此函数的作用

AES/CBC算法

1.2、参数说明

mbedtls_aes_context* ctx必须调用mbedtls_aes_init(&ctx)进行初始化。

int mode可取值MBEDTLS_AES_ENCRYPTMBEDTLS_AES_DECRYPT,分别表示加密模式解密模式

size_t inputLengthconst unsigned char* input的长度,单位是字节。 该值只能是16的整数倍。实际上,要加密的字节数据不可能总是16的倍数,这就要求我们补足,以满足是16的整数倍。上什么数据呢,这有很多种方法。这称为Padding。有很多种Padding

unsigned char iv[16]是初始向量,16个字节。这是为了增加破解的难度。

unsigned char* output是输出的字节。

1.3、返回值说明

0表示成功。

MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH表示传入的inputLength不符合要求。

1.4、使用示例

step1、创建一个项目目录AES,并进入该目录

mkdir AES && cd AES

step2、使用curl命令下载代码

curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/include/mbedtls/aes.h
curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/library/aes.c

curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/include/mbedtls/platform_util.h
curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/library/platform_util.c

curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/include/mbedtls/platform.h
curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/library/platform.c

curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/include/mbedtls/threading.h
curl -LO https://raw.githubusercontent.com/ARMmbed/mbedtls/master/library/threading.c

step3、创建config.h文件,其内容如下

#define MBEDTLS_AES_C
#define MBEDTLS_CIPHER_MODE_CBC

MBEDTLS_AES_C这个宏控制着是否开启AES相关的定义。

MBEDTLS_CIPHER_MODE_CBC这个宏表示我们要使用CBC模式,当然还有其他模式,要使用哪个模式,就定义对应的宏:

#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_CIPHER_MODE_CTR
#define MBEDTLS_CIPHER_MODE_CFB
#define MBEDTLS_CIPHER_MODE_OFB
#define MBEDTLS_CIPHER_MODE_XTS

step4、将代码中的mbedtls/字符串去掉

sed -i    's@mbedtls/@@g' aes.c platform_util.h platform_util.c platform.c threading.h threading.c 2> /dev/null ||
sed -i "" 's@mbedtls/@@g' aes.c platform_util.h platform_util.c platform.c threading.h threading.c

step5、编写一个C语言源程序aesTest.c,其内容如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aes.h"
#include "../../../algorithm/base16/base16.h"

void showHelp() {
    printf("usage:   aes encode STRING\n");
    printf("usage:   aes decode HEX\n");
    exit(1);
}

//AES/CBC/PKCS5Padding
//input可以是任意长度
//key只能是16、24、32个ASSCII字符组成的串儿
unsigned char* aes_cbc_pkcs5padding_encode(const char* key, unsigned char iv[16], const char* input, size_t* outputLength) {
    size_t keyLength = strlen(key);
    
    if (keyLength != 32 && keyLength != 24 && keyLength != 16) {
        perror("key必须是16、24、32个ASSCII字符组成的串\n");
        return NULL;
    }
        
    //获取到输入的要加密的内容的长度
    size_t inputLength = strlen(input);
    printf("input = %s, inputLength = %zu\n", input, inputLength);

    //看看需要分成多少个块,即使输入的数据是16的整数倍,也要补充16个字节的整数16
    size_t n = (inputLength >> 4) + 1;
    printf("n = %zu\n", n);

    //https://tools.ietf.org/html/rfc8018#appendix-B.2.5
    unsigned int padding = 16 - (inputLength & 15);
    printf("padding = %d\n", padding);

    //用于加密的的数据长度:字节数,此字节数正好等于输出的字节数
    size_t needInputLength = n << 4;
    printf("needInputLength = %zu\n", needInputLength);

    *outputLength = needInputLength;

    unsigned char* toBeEncryptBytes = (unsigned char*) calloc(needInputLength, sizeof(unsigned char));
    memcpy(toBeEncryptBytes, (unsigned char*)input, inputLength);
    
    //填充数据
    for (unsigned int i = 0; i < padding; i++) {
        toBeEncryptBytes[inputLength + i] = padding;
    }
     
    //加密后的数据
    unsigned char* output = (unsigned char*) calloc(needInputLength, sizeof(unsigned char));

    mbedtls_aes_context aes;
    mbedtls_aes_init(&aes);
    //设置加密的key
    mbedtls_aes_setkey_enc(&aes, (unsigned char*)key, keyLength << 3);
    //加密
    int resultCode = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, needInputLength, iv, toBeEncryptBytes, output);
    
    if (NULL != toBeEncryptBytes) {
        free(toBeEncryptBytes);
        toBeEncryptBytes = NULL;
    }
    
    if (0 == resultCode) {
        return output;
    } else {
        free(output);
        return NULL;
    }
}

//AES/CBC/PKCS5Padding
//key只能是16、24、32个ASSCII字符组成的串儿
int aes_cbc_pkcs5padding_decode(const char*key, unsigned char iv[16], unsigned char* input, size_t inputLength, unsigned char* output, size_t* outputLength) {
    size_t keyLength = strlen(key);
     
    if (keyLength != 32 && keyLength != 24 && keyLength != 16) {
        perror("key必须是16、24、32个ASSCII字符组成的串\n");
        return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
    }
    
    if ((inputLength & 15) != 0) {
        perror("inputLength必须是16大的整数倍");
        return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
    }

    //设置解密的key
    mbedtls_aes_context aes;
    mbedtls_aes_init(&aes);
    mbedtls_aes_setkey_dec(&aes, (unsigned char*)key, keyLength << 3);
    
    //解密数据
    int resultCode = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, inputLength, iv, input, output);
    if (0 == resultCode) {
        int padding = output[inputLength - 1];
        (*outputLength) = inputLength - padding;
    }

    return resultCode;
}

int main(int argc, char* argv[]) {
    if (argc != 3) {
        showHelp();
    }
    if (strcmp("encode", argv[1]) == 0 || strcmp("decode", argv[1]) == 0) {
        //初始向量,一般是一个随机数组成的,长度必须是块大小,一个块是16字节
        unsigned char iv[16] = {0};
        const char* key = "abcdefghjklqwert";
        size_t written = 0;
        if (strcmp("encode", argv[1]) == 0) {
            unsigned char* aesEncodedBytes = aes_cbc_pkcs5padding_encode(key, iv, argv[2], &written);
            char* hex = base16_encode(aesEncodedBytes, written, true);
            printf("aes_cbc_pkcs5padding(content=%s,key=%s)=%s\n", argv[2], key, hex);
            return 0;
        } else {
            unsigned char* input = base16_decode(argv[2]);
            size_t inputLength = strlen(argv[2]) >> 1;
            unsigned char output[inputLength];
            int resultCode = aes_cbc_pkcs5padding_decode(key, iv, input, inputLength, output, &written);
            if (0 == resultCode) {
                output[written] = '\0';
                printf("aes_cbc_pkcs5padding(content=%s,key=%s)=%s\n", output, key, argv[2]);
            } else {
                printf("error occurred. code is %d\n", resultCode);
            }
            return resultCode;
        }
    } else {
        showHelp();
    }
}

step6、使用cc命令进行编译

cc -o aesTest *.c

step7、执行aesTest,结果如下

./aesTest encode abc
aes_cbc_pkcs5padding(content=abc,key=abcdefghjklqwert)=EBBF70FEF806D11C4F1FA1007597105A

step8、与用Java实现的相同算法进行结果比较

import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;

public class AES {
    public static byte[] aes_cbc_pkcs5padding(byte[] content, String key, byte[] iv) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("ASCII"), "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuilder buf = new StringBuilder(bytes.length << 2);
        for(byte b : bytes) { // 使用String的format方法进行转换
            buf.append(String.format("%02X", new Integer(b & 0xff)));
        }
        return buf.toString();
    }

    public static void main(String[] args) throws Exception {
        String content = args[0];
        String key = "abcdefghjklqwert";
        byte[] iv = new byte[16];
        for (int i = 0; i < 16; i++) {
            iv[i] = 0;
        }
        String hex = bytesToHex(aes_cbc_pkcs5padding(content.getBytes("ASCII"), key, iv));
        System.out.printf("aes_cbc_pkcs5padding(content=%s,key=%s)=%s\n", content, key, hex);
    }
}

step9、使用javac命令进行编译

javac -cp . AES.java

step10、执行java AES abc,结果如下

java AES abc
aes_cbc_pkcs5padding(content=abc,key=abcdefghjklqwert)=EBBF70FEF806D11C4F1FA1007597105A

两种语言的实现结果是一样的。