上一篇文章:c/c++编写dll供其他语言调用
那篇文章说了怎么用dev c++和vs2017编写dll计算md5,这好像并没什么软用,只是做演示用的代码,因为大部分语言想找md5的库很简单,所以这篇文章说说怎么编写AES加解密的dll
叫我用c/c++写个aes算法来不太可能,还是照旧去github借鉴一个。找了很久,发现c语言写的要么不全,要么看不懂。最后只能筛选c++写的,选中了下面这个,理由很简单,有很多调用演示代码,很容易看出怎么调用的,而且我用dev c++一跑就通,加密模式也支持(ECB, CBC, CFB)。
https://github.com/SergeyBel/AES
首先肯定是用dev c++测试一下代码是不是正常,结果对不对了。github中aes主要代码在src文件夹里的两个文件,tests文件夹放的则是如何调用的
具体测试的细节就不说了,因为我对c/c++也不熟,基本都是一步一百度,不过这个代码调用接口倒是很简单,也没什么太大的问题
实例化一个aes类,如何调用类方法就行,比如ecb模式
AES aes(128); unsigned char plain[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; unsigned char key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; unsigned char right[] = { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }; unsigned int len = 0; unsigned char *out = aes.EncryptECB(plain, 16, key, len); ASSERT_FALSE(memcmp(right, out, BLOCK_BYTES_LENGTH)); ASSERT_EQ(BLOCK_BYTES_LENGTH, len); delete[] out;
其中plain是要加密的内容,right是加密后的内容,而out则是实际加密后的结果,后面那两句只是对比一下out和right是不是一样。其他模式也差不多,就只需要多传一个iv。
AES aes(128); unsigned char plain[] = "1234567890abcdef"; unsigned char key[] = "1234567890abcdef"; unsigned int len = 0; unsigned char *out = aes.EncryptECB(plain, 16, key, len); for(int i=0; i<len; i++ ){ printf( "%02x", out[i]); } delete[] out;
比如运行这段代码,查看输出结果
95b012b0bc898e5c37eeed6588635f09
找一个测试网站看看结果是不是一样:https://the-x.cn/cryptography/Aes.aspx
对比一下是没问题的,而且给出的代码里也演示了key长度为128,192,和256bit的情况,现在还少了一样,填充模式。
看了下演示代码里也有不对齐blockSize(这里是16个字节)的情况,在看一下源码,就知道了。如果加密数据长度正好整除16字节,则不填充也就是NoPadding模式,如果整除不了,则用0x0来填充,也就是ZeroPadding模式。但是实际的ZeroPadding模式在能整除的情况,也是要填充16个0x0的,
这显然不符合规范,所以可以改一下,让他支持两种填充模式(ZeroPadding和Pkcs7Padding)和不填充。ZeroPadding填充:填充n个0x0,n为blockSize-加密的文本长度%blockSize;Pkcs7Padding填充,填充n个0xn,n为blockSize-加密的文本长度%blockSize。,
假设要加密的文本为input, 其长度是inputSize, alignIn就是填充后的内容。
ZeroPadding代码:
uint8_t paddingNum = 16 - (inputSize % 16); unsigned int alignInSize = inputSize + paddingNum; unsigned char *alignIn = new unsigned char[alignInSize]; memcpy(alignIn, input, inputSize); memset(alignIn + inputSize, 0x0, paddingNum); delete[] alignIn;
Pkcs7Padding
uint8_t paddingNum = 16 - (inputSize % 16); unsigned int alignInSize = inputSize + paddingNum; unsigned char *alignIn = new unsigned char[alignInSize]; memcpy(alignIn, input, inputSize); memset(alignIn + inputSize, paddingNum, paddingNum); delete[] alignIn;
https://gitee.com/kanadeblisst/vs2017-aes-dll
import ctypes import base64 class AES: Pkcs7Padding = 2 ZeroPadding = 1 NoPadding = 0 ECB = 0 CBC = 1 CFB = 2 def __init__(self, key, iv): self.key = key.encode() self.iv = iv.encode() self.aes_dll = ctypes.CDLL("D:\\Android\\vs2017\\AES\\Debug\\AES.dll") def decrypt(self, text, mode=0, padding=0): btext = text.encode() AESDecrypt = self.aes_dll.AESDecrypt AESDecrypt.argtypes=[ctypes.c_uint, ctypes.c_uint, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] AESDecrypt.restype = ctypes.c_int result = ctypes.create_string_buffer(len(text.encode()) + 17) result_len = AESDecrypt(ctypes.c_uint(mode), ctypes.c_uint(padding), ctypes.c_char_p(btext), ctypes.c_char_p(self.key), ctypes.c_char_p(self.iv), result) return result.value[:result_len] def encrypt(self, text, mode=0, padding=0): btext = text.encode() AESDecrypt = self.aes_dll.AESEncrypt AESDecrypt.argtypes=[ctypes.c_uint, ctypes.c_uint, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] AESDecrypt.restype = ctypes.c_int result = ctypes.create_string_buffer(len(text.encode()) + 17) result_len = AESDecrypt(ctypes.c_uint(mode), ctypes.c_uint(padding), ctypes.c_char_p(btext), ctypes.c_char_p(self.key), ctypes.c_char_p(self.iv), result) return result.raw[:result_len] if __name__ == "__main__": a = AES("1234567890abcdef", "1234567890abcdef") text = "1234567890abcdef" result = a.encrypt(text, mode=AES.CFB, padding=AES.ZeroPadding) print("字符串: %s, 长度:%d, aes: %s, base64: %s" % (text, len(result), result.hex(), base64.b64encode(result)))
dll中只是把char数组加密成了char数组,转为Python中的类型也就是字节,所以要想转为hex和base64只需要调用Python的方法即可。
写这个dll也是突发奇想,正好国庆在家有时间,奈何本人基础有点差,代码写的也有点烂,所以上面的代码很可能会有bug,如果你测试正好遇到了,可以提出一起解决。
另外其实hex和base64也可以在dll 中实现,百度或者github找代码应该不难。