c/c + + Write dll for AES encryption and decryption for other languages to call

Previous article: c/c + + Write dll for other languages to call

That article talked about how to use dev c + + and vs2017 to write dll to calculate md5. It doesn't seem to have any soft use. It's just code for demonstration. Because most languages want to find md5 library is very simple, this article talks about how to write AES encryption and decryption dll

AES code

It's impossible for me to write an aes algorithm in c/c + +. I'd better use github for reference. After looking for it for a long time, I found that the c language was either incomplete or incomprehensible. Finally, only those written in c + + can be screened. The reason for selecting the following is very simple. There are many call demonstration codes, and it is easy to see how to call them. In addition, I can run with dev c + +, and the encryption mode is also supported (ECB, CBC, CFB).

https://github.com/SergeyBel/AES

Modify code

First of all, you must test whether the code is normal with dev c + +, and the result is correct. The aes code in github is mainly in two files in src folder, and how to call the tests folder

I won't talk about the details of the specific test, because I'm not familiar with c/c + +. I'm basically Baidu step by step, but the code calling interface is very simple and there's no big problem

Instantiate an aes class and just call the class method, such as ecb mode

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;

Where plain is the content to be encrypted, right is the encrypted content, and out is the actual encrypted result. The latter two sentences just compare whether out and right are the same. Other modes are similar, so you only need to transmit one more 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;

For example, run this code to see the output
95b012b0bc898e5c37eeed6588635f09

Find a test website to see if the results are the same: https://the-x.cn/cryptography/Aes.aspx


There is no problem in comparison, and the code also demonstrates that the key length is 128192, which is the same as that of 256bit. Now, the filling mode is missing.

After looking at the demonstration code, there is also a case of misaligned blocksize (here is 16 bytes). Just look at the source code. If the encrypted data length is exactly divided by 16 bytes, it will not be filled, that is, NoPadding mode. If it cannot be divided, it will be filled with 0x0, that is, ZeroPadding mode. However, the actual ZeroPadding mode also needs to fill in 16 0x0s when it can be divided,

This obviously does not conform to the specification, so it can be changed to support two filling modes (ZeroPadding and Pkcs7Padding) and no filling. ZeroPadding: fill in n 0x0 s, n is blockSize - encrypted text length% blockSize; Pkcs7Padding, filled with n 0xn, n is blockSize - encrypted text length% blockSize.,

Suppose the text to be encrypted is input, its length is inputSize, and alignIn is the filled content.
ZeroPadding Code:

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 source code

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

Python call

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("character string: %s, Length:%d, aes: %s, base64: %s" % (text, len(result), result.hex(), base64.b64encode(result)))

dll only encrypts the char array into a char array and converts it to the type in Python, that is, bytes. Therefore, if you want to convert it to hex and base64, you only need to call Python methods.

other

Writing this dll is also a whim. I happen to have time at home on the national day. However, my foundation is a little poor, and the code is a little bad, so there may be bug s in the above code. If you happen to encounter them in the test, you can propose to solve them together.

In addition, hex and base64 can also be implemented in dll. It should not be difficult for Baidu or github to find the code.

Tags: C++

Posted on Tue, 05 Oct 2021 21:17:40 -0400 by greatepier