ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c/c++编写dll进行AES加解密供其他语言调用

2021-10-05 20:03:33  阅读:259  来源: 互联网

标签:AES aes 加解密 unsigned c++ dll char ctypes result


上一篇文章:c/c++编写dll供其他语言调用

那篇文章说了怎么用dev c++和vs2017编写dll计算md5,这好像并没什么软用,只是做演示用的代码,因为大部分语言想找md5的库很简单,所以这篇文章说说怎么编写AES加解密的dll

AES代码

叫我用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;

dll源码

https://gitee.com/kanadeblisst/vs2017-aes-dll

Python调用

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找代码应该不难。

标签:AES,aes,加解密,unsigned,c++,dll,char,ctypes,result
来源: https://blog.csdn.net/Qwertyuiop2016/article/details/120616957

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有