Python ctypes调用openssl动态C库的一些例子

AES 256 GCM加解密相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
* Copyright 2012-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/

/*
* Simple AES GCM test program, uses the same NIST data used for the FIPS
* self test but uses the application level EVP APIs.
*/
#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/evp.h>

/* AES-GCM test data from NIST public test vectors */

static const unsigned char gcm_key[] = {
0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66,
0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69,
0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f
};

static const unsigned char gcm_iv[] = {
0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84
};

static const unsigned char gcm_pt[] = {
0xf5, 0x6e, 0x87, 0x05, 0x5b, 0xc3, 0x2d, 0x0e, 0xeb, 0x31, 0xb2, 0xea,
0xcc, 0x2b, 0xf2, 0xa5
};

static const unsigned char gcm_aad[] = {
0x4d, 0x23, 0xc3, 0xce, 0xc3, 0x34, 0xb4, 0x9b, 0xdb, 0x37, 0x0c, 0x43,
0x7f, 0xec, 0x78, 0xde
};

static const unsigned char gcm_ct[] = {
0xf7, 0x26, 0x44, 0x13, 0xa8, 0x4c, 0x0e, 0x7c, 0xd5, 0x36, 0x86, 0x7e,
0xb9, 0xf2, 0x17, 0x36
};

static const unsigned char gcm_tag[] = {
0x67, 0xba, 0x05, 0x10, 0x26, 0x2a, 0xe4, 0x87, 0xd7, 0x37, 0xee, 0x62,
0x98, 0xf7, 0x7e, 0x0c
};

void aes_gcm_encrypt(void)
{
EVP_CIPHER_CTX *ctx;
int outlen, tmplen;
unsigned char outbuf[1024];
printf("AES GCM Encrypt:\n");
printf("Plaintext:\n");
BIO_dump_fp(stdout, gcm_pt, sizeof(gcm_pt));
ctx = EVP_CIPHER_CTX_new();
/* Set cipher type and mode */
EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
/* Set IV length if default 96 bits is not appropriate */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(gcm_iv), NULL);
/* Initialise key and IV */
EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv);
/* Zero or more calls to specify any AAD */
EVP_EncryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad));
/* Encrypt plaintext */
EVP_EncryptUpdate(ctx, outbuf, &outlen, gcm_pt, sizeof(gcm_pt));
/* Output encrypted block */
printf("Ciphertext:\n");
BIO_dump_fp(stdout, outbuf, outlen);
/* Finalise: note get no output for GCM */
EVP_EncryptFinal_ex(ctx, outbuf, &outlen);
/* Get tag */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, outbuf);
/* Output tag */
printf("Tag:\n");
BIO_dump_fp(stdout, outbuf, 16);
EVP_CIPHER_CTX_free(ctx);
}

void aes_gcm_decrypt(void)
{
EVP_CIPHER_CTX *ctx;
int outlen, tmplen, rv;
unsigned char outbuf[1024];
printf("AES GCM Decrypt:\n");
printf("Ciphertext:\n");
BIO_dump_fp(stdout, gcm_ct, sizeof(gcm_ct));
ctx = EVP_CIPHER_CTX_new();
/* Select cipher */
EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
/* Set IV length, omit for 96 bits */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(gcm_iv), NULL);
/* Specify key and IV */
EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_key, gcm_iv);
/* Zero or more calls to specify any AAD */
EVP_DecryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad));
/* Decrypt plaintext */
EVP_DecryptUpdate(ctx, outbuf, &outlen, gcm_ct, sizeof(gcm_ct));
/* Output decrypted block */
printf("Plaintext:\n");
BIO_dump_fp(stdout, outbuf, outlen);
/* Set expected tag value. */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(gcm_tag),
(void *)gcm_tag);
/* Finalise: note get no output for GCM */
rv = EVP_DecryptFinal_ex(ctx, outbuf, &outlen);
/*
* Print out return value. If this is not successful authentication
* failed and plaintext is not trustworthy.
*/
printf("Tag Verify %s\n", rv > 0 ? "Successful!" : "Failed!");
EVP_CIPHER_CTX_free(ctx);
}

int main(int argc, char **argv)
{
aes_gcm_encrypt();
aes_gcm_decrypt();
}

参考:https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/demos/evp/aesgcm.c
转换成Python ctypes方式调用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import base64
import ctypes
import os
from ctypes import c_void_p, c_char_p, c_int, create_string_buffer, POINTER

# 加载 OpenSSL 动态库
libcrypto = ctypes.CDLL("libcrypto.so") # 根据系统选择动态库路径(Linux)

# 设置 OpenSSL 相关的函数原型
libcrypto.EVP_CIPHER_CTX_new.restype = c_void_p
libcrypto.EVP_CIPHER_CTX_new.argtypes = []

libcrypto.EVP_CIPHER_CTX_free.argtypes = [c_void_p]

libcrypto.EVP_CIPHER_CTX_get_params.argtypes = [c_void_p, POINTER(c_void_p)]
libcrypto.EVP_CIPHER_free.argtypes = [c_void_p]

libcrypto.EVP_EncryptInit_ex.argtypes = [
c_void_p,
c_void_p,
c_void_p,
c_char_p,
c_char_p,
]
libcrypto.EVP_EncryptUpdate.argtypes = [
c_void_p,
c_char_p,
POINTER(c_int),
c_char_p,
c_int,
]
libcrypto.EVP_EncryptFinal_ex.argtypes = [c_void_p, c_char_p, POINTER(c_int)]

libcrypto.EVP_DecryptInit_ex.argtypes = [
c_void_p,
c_void_p,
c_void_p,
c_char_p,
c_char_p,
]
libcrypto.EVP_DecryptUpdate.argtypes = [
c_void_p,
c_char_p,
POINTER(c_int),
c_char_p,
c_int,
]
libcrypto.EVP_DecryptFinal_ex.argtypes = [c_void_p, c_char_p, POINTER(c_int)]

libcrypto.EVP_aes_256_gcm.restype = c_void_p
libcrypto.EVP_aes_256_gcm.argtypes = []

libcrypto.EVP_CIPHER_fetch.argtypes = [c_void_p, c_char_p, c_void_p]
libcrypto.EVP_CIPHER_fetch.restype = c_void_p

libcrypto.EVP_CIPHER_CTX_ctrl.argtypes = [c_void_p, c_int, c_int, c_void_p]
libcrypto.EVP_CIPHER_CTX_ctrl.restype = c_int
# (ctx, EVP_CTRL_AEAD_SET_IVLEN, sizeof(gcm_iv), NULL)
libcrypto.BIO_dump_fp.argtypes = [c_void_p, c_void_p, c_int]
libcrypto.BIO_dump_fp.restype = c_int
libcrypto.fopen.argtypes = [c_char_p, c_char_p]
libcrypto.fopen.restype = c_void_p


# AES GCM加密
def aes_256_gcm_encrypt(key: bytes, iv: bytes, plaintext: bytes, aad: bytes = b""):
key_ptr = c_char_p(key)
iv_ptr = c_char_p(iv)

# 创建加密上下文
ctx = libcrypto.EVP_CIPHER_CTX_new()
cipher = libcrypto.EVP_aes_256_gcm()
# print(11111)
# cipher = libcrypto.EVP_CIPHER_fetch(
# libctx, c_char_p(b"AES-256-GCM"), propq)
# print(ctypes.cast(cipher, c_void_p))
# print(11111)

# 初始化加密操作
print(2222)
ls = libcrypto.EVP_EncryptInit_ex(ctx, cipher, None, None, None)
print(ls)

print(2222)
libcrypto.EVP_CIPHER_CTX_ctrl(ctx, c_int(0x9), c_int(len(iv)), None)
print(333)
libcrypto.EVP_EncryptInit_ex(ctx, None, None, key_ptr, iv_ptr)
print(444)
# 处理AAD(附加认证数据)
outlen = c_int(0)
libcrypto.EVP_EncryptUpdate(
ctx, None, ctypes.byref(outlen), c_char_p(aad), c_int(len(aad))
)
print(555)
# outlen = c_int(0)
# if not libcrypto.EVP_EncryptUpdate(ctx, None, None, aad_buffer, len(aad)):
# raise ValueError("Error encrypting AAD")
outbuf = create_string_buffer(len(plaintext))
libcrypto.EVP_EncryptUpdate(
ctx, outbuf, ctypes.byref(outlen), c_char_p(
plaintext), c_int(len(plaintext))
)
print(666)

# # 加密明文
# ciphertext = create_string_buffer(len(plaintext))
# if not libcrypto.EVP_EncryptUpdate(
# ctx, ciphertext, ctypes.byref(outlen), plaintext_buffer, len(plaintext)
# ):
# raise ValueError("Error encrypting plaintext")
print(outbuf.raw[: outlen.value].hex())
# 获取加密后的数据
ciphertext = outbuf.raw[: outlen.value]
libcrypto.EVP_EncryptFinal_ex(ctx, outbuf, ctypes.byref(outlen))
print(777)
import sys

libcrypto.BIO_dump_fp(
libcrypto.fopen(b"1", b"w"),
c_char_p(b"test"),
len(b"test"),
)
libcrypto.EVP_CIPHER_CTX_ctrl(ctx, c_int(0x10), c_int(16), outbuf)

# 获取认证标签
# #tag = create_string_buffer(16)
# if not libcrypto.EVP_EncryptFinal_ex(ctx, tag, ctypes.byref(outlen)):
# raise ValueError("Error finalizing encryption")

# 释放上下文
libcrypto.EVP_CIPHER_CTX_free(ctx)

return ciphertext, outbuf.raw


# AES GCM 解密
def aes_256_gcm_decrypt(
key: bytes, iv: bytes, ciphertext: bytes, aad: bytes = b"", tag: bytes = b""
):
print("tag:", tag.hex())
ctx = libcrypto.EVP_CIPHER_CTX_new()
libcrypto.EVP_DecryptInit_ex(
ctx, libcrypto.EVP_aes_256_gcm(), None, None, None)
libcrypto.EVP_CIPHER_CTX_ctrl(ctx, c_int(0x9), len(iv), None)
libcrypto.EVP_DecryptInit_ex(ctx, None, None, c_char_p(key), c_char_p(iv))
outlen = c_int(0)
libcrypto.EVP_DecryptUpdate(
ctx, None, ctypes.byref(outlen), c_char_p(aad), len(aad)
)
outbuf = create_string_buffer(len(ciphertext))
libcrypto.EVP_DecryptUpdate(
ctx, outbuf, ctypes.byref(outlen), c_char_p(
ciphertext), len(ciphertext)
)
print("Plaintext:\n")
# BIO_dump_fp(stdout, outbuf, outlen);
print(outbuf.raw)
text = outbuf.raw[: outlen.value]
print("tag:", tag)
libcrypto.EVP_CIPHER_CTX_ctrl(ctx, c_int(0x10), len(tag), c_char_p(tag))
rv = libcrypto.EVP_DecryptFinal_ex(ctx, outbuf, ctypes.byref(outlen))
print(rv)

# 释放解密上下文
libcrypto.EVP_CIPHER_CTX_free(ctx)

return text


# 测试数据
key = b"77889900112233445566778899001122"
print(key.hex())
iv = b"778899001122"
print(iv.hex())
plaintext = b"1231"
print(plaintext.hex())
aad = b""

# 加密过程
ciphertext, tag = aes_256_gcm_encrypt(key, iv, plaintext, aad)
print(f"Ciphertext: {ciphertext.hex()}")
print(f"Tag: {tag.hex()}")


ciphertext = base64.b64decode(
b"BGDr211pjM/koptwkyQ7iXWTBqVf1R89Z19MPY2QiIv4/h/UNXuDjjc+uQ/9ZkJqdOfZ8MH/j+P907tbTFJhYyyd2+dqyEzBSEKq8RlpZIbHyYcnw6XRdA4c4HiAcB0ZzW8Qu3gMnH3DydMSNHwx1r7oEGewL/2SgejQemo3wK7BlpKWAJ7oX/pXCrS3JRRKHE8QG6piJLyUBB+GwuggNbE7sev7StGjezNoD2y0w0gTagKfF4C/5bVxmxbDX+DFSTfPIwA7KhRa58Vm3vL2kf+RBi1/aL9SA2+a1E6uJEAt/EEzZJ+4UJPljqIkQOAEwmD99ijG1smrRfmMkXdwmEOYeckYNwoUQbPv1wOI40UfOh2etmu9nzmuSsoNDWGJza9x4CwOXlIHvPbZtBbYO20mBy0W2byx7dh+vGbzeLgBJ8IWbHc50DNAV6GA/sxifcZPZs8USn42WoKtuKqrUVq28H+faCNvaVdSbI+ZUSG6F/euDMVdguWMlfub4J3KLxC346MDCRoX6bEXG3J4+Mo7JPi+xfoh2JKewHF2D4RgJIEkPt9ffhEDKG7jtJGSzYYqfKBEVU2/vDuGV8Y+nHmsGFcbCiM1I7onmMS1L977O0UEMwvz8cIjnXd9kRMhGrBU6yR0DvEZ67K3a5wCxbwEbNaWPy5n2oDUF3mWESXSMSIgdN6qcgpok95xegLmcEkKtp4MYdd/cT7IS2qtWJmNJKiAqg=="
)

tag = b""

iv = base64.b64decode(b"eorS/CBlfWrqeWWj")
print(iv.hex())
key = b"4e3b9ft1a68eb6548af9y895c1b14ad5"
# 解密过程
try:
decrypted_plaintext = aes_256_gcm_decrypt(key, iv, ciphertext, aad, tag)
print(decrypted_plaintext[:-16])
except ValueError as e:
print(e)

RSA非对称加解密相关,使用chatgpt生成手动修护了异常和错误

加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import ctypes
import sys
import base64
from ctypes import c_char_p, c_void_p, POINTER

# 加载 OpenSSL 动态库(Linux 下通常是 libcrypto.so)
libcrypto = ctypes.CDLL("libcrypto.so") # 根据系统调整库的路径

# 定义 C 函数原型
libcrypto.PEM_read_RSAPrivateKey.argtypes = [
c_void_p,
POINTER(c_void_p),
c_void_p,
c_void_p,
]
libcrypto.PEM_read_RSAPrivateKey.restype = c_void_p # 返回类型是 RSA*

# 打开私钥文件的 C 函数
libcrypto.fopen.argtypes = [c_char_p, c_char_p]
libcrypto.fopen.restype = c_void_p # 返回 FILE*,即 void*
# 定义 C 函数原型
libcrypto.BN_bn2hex.argtypes = [c_void_p]
libcrypto.BN_bn2hex.restype = c_char_p # 返回类型是 C 字符串

libcrypto.BN_bn2dec.argtypes = [c_void_p]
libcrypto.BN_bn2dec.restype = c_char_p # 返回类型是 C 字符串


# 打开文件
def open_file(filename):
return libcrypto.fopen(filename.encode("utf-8"), b"r")


# RSA_get0_key: 获取 RSA 密钥的模数和公钥指数
libcrypto.RSA_get0_key.argtypes = [
c_void_p,
POINTER(c_void_p),
POINTER(c_void_p),
c_void_p,
]
libcrypto.RSA_get0_key.restype = None # 返回类型是 void


# 打印 RSA 密钥信息
def print_rsa_info(rsa):
if rsa is None:
print("RSA key is NULL.")
return

# 获取模数和公钥指数
n = c_void_p()
e = c_void_p()
libcrypto.RSA_get0_key(rsa, ctypes.byref(n), ctypes.byref(e), None)

# 打印模数 (n)
print("RSA Key Info:")
print(" Modulus (n):")

# 使用 sys.stdout 获取 FILE* 类型
n_hex = libcrypto.BN_bn2hex(n)
print(n_hex.decode()) # 打印十六进制表示
# libcrypto.BN_print_fp(stdout_fp, n) # 输出到标准输出

print("\n Public exponent (e):")
e_hex = libcrypto.BN_bn2hex(e)
print(e_hex.decode()) # 打印十六进制表示
# libcrypto.BN_print_fp(stdout_fp, e) # 输出到标准输出

# 获取 RSA 密钥的大小
bits = (
libcrypto.RSA_size(ctypes.cast(rsa, c_void_p)) * 8
) # RSA_size 返回字节数,乘以 8 转换为位数
print(f" Key size: {bits} bits")


# 错误打印函数
libcrypto.ERR_print_errors_fp.argtypes = [c_void_p]
libcrypto.ERR_print_errors_fp.restype = None


# 加载私钥
def load_private_key(privkey_filename):
# 打开文件
privkey_file = open_file(privkey_filename)
if not privkey_file:
print("Unable to open private key file")
return None

# 加载 RSA 私钥
rsa = libcrypto.PEM_read_RSAPrivateKey(privkey_file, None, None, None)
if not rsa:
print("Unable to load private key")
libcrypto.ERR_print_errors_fp(None) # 输出 OpenSSL 错误
return None

print(f"Private key loaded successfully from {privkey_filename}.")
return rsa


# 使用示例
privkey_filename = "private_key.pem"
rsa_privkey = load_private_key(privkey_filename)

if rsa_privkey:
print("Private key loaded successfully")
print_rsa_info(rsa_privkey)
else:
print("Failed to load private key")


# 分块加密
def encrypt_rsa(rsa, data):
rsa_len = libcrypto.RSA_size(ctypes.cast(rsa, c_void_p))
block_size = rsa_len - 11 # 最大加密块大小:RSA_size - 填充空间

encrypted_data = ctypes.create_string_buffer(
rsa_len * ((len(data) // block_size) + 1)
)

data_len = len(data)
encrypted_len = 0
i = 0

while i < data_len:
chunk_len = min(block_size, data_len - i)
# 对当前块进行加密
len_encrypted = libcrypto.RSA_private_encrypt(
chunk_len,
ctypes.byref(ctypes.create_string_buffer(data[i: i + chunk_len])),
ctypes.byref(encrypted_data, encrypted_len),
ctypes.cast(rsa, c_void_p),
1, # RSA_PKCS1_OAEP_PADDING
)

if len_encrypted == -1:
print("RSA encryption failed")
libcrypto.ERR_print_errors_fp(sys.stderr)
return None

encrypted_len += len_encrypted
i += chunk_len

return encrypted_data.raw[:encrypted_len]


# 待加密的数据
# data = b"Hello, RSA encryption! This is a long message that will be split into multiple blocks."
data = """
test_-------TEST
""".encode("utf-8")

print(f"Original Data (length: {len(data)}):\n{data.decode()}")

# 加密
encrypted_data = encrypt_rsa(rsa_privkey, data)
if encrypted_data is None:
sys.exit(1)

print(f"\nEncrypted Data (length: {len(encrypted_data)}):")
print(" ".join(f"{byte:02x}" for byte in encrypted_data))
print(base64.b64encode(encrypted_data))

解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import ctypes
import base64
import sys
from ctypes import c_char_p, c_void_p, POINTER

# 加载 OpenSSL 动态库(Linux 下通常是 libcrypto.so)
libcrypto = ctypes.CDLL("libcrypto.so") # 根据系统调整库的路径

# 用于错误处理
libcrypto.ERR_print_errors_fp.argtypes = [c_void_p]

# 打开私钥文件的 C 函数
libcrypto.fopen.argtypes = [c_char_p, c_char_p]
libcrypto.fopen.restype = c_void_p # 返回 FILE*,即 void*
# 定义 C 函数原型
libcrypto.BN_bn2hex.argtypes = [c_void_p]
libcrypto.BN_bn2hex.restype = c_char_p # 返回类型是 C 字符串

libcrypto.BN_bn2dec.argtypes = [c_void_p]
libcrypto.BN_bn2dec.restype = c_char_p # 返回类型是 C 字符串


# 打开文件
def open_file(filename):
return libcrypto.fopen(filename.encode("utf-8"), b"r")


# RSA_get0_key: 获取 RSA 密钥的模数和公钥指数
libcrypto.RSA_get0_key.argtypes = [
c_void_p,
POINTER(c_void_p),
POINTER(c_void_p),
c_void_p,
]
libcrypto.RSA_get0_key.restype = None # 返回类型是 void


# 打印 RSA 密钥信息
def print_rsa_info(rsa):
if rsa is None:
print("RSA key is NULL.")
return

# 获取模数和公钥指数
n = c_void_p()
e = c_void_p()
libcrypto.RSA_get0_key(rsa, ctypes.byref(n), ctypes.byref(e), None)

# 打印模数 (n)
print("RSA Key Info:")
print(" Modulus (n):")

# 使用 sys.stdout 获取 FILE* 类型
n_hex = libcrypto.BN_bn2hex(n)
print(n_hex.decode()) # 打印十六进制表示
# libcrypto.BN_print_fp(stdout_fp, n) # 输出到标准输出

print("\n Public exponent (e):")
e_hex = libcrypto.BN_bn2hex(e)
print(e_hex.decode()) # 打印十六进制表示
# libcrypto.BN_print_fp(stdout_fp, e) # 输出到标准输出

# 获取 RSA 密钥的大小
bits = (
libcrypto.RSA_size(ctypes.cast(rsa, c_void_p)) * 8
) # RSA_size 返回字节数,乘以 8 转换为位数
print(f" Key size: {bits} bits")


# 定义 C 函数原型
libcrypto.PEM_read_RSA_PUBKEY.argtypes = [
c_void_p, c_void_p, c_void_p, c_void_p]
libcrypto.PEM_read_RSA_PUBKEY.restype = c_void_p # 返回 RSA 对象指针


# 加载 RSA 公钥并打印信息
def load_public_key(pubkey_filename):
try:
# 打开文件并加载公钥
public_file = open_file(pubkey_filename)

if not public_file:
print("Unable to open private key file")
return None
# 创建 C 字符串指针,指向文件内容
# buffer = ctypes.create_string_buffer(file_data)

# 加载 RSA 公钥
rsa1 = libcrypto.PEM_read_RSA_PUBKEY(public_file, None, None, None)

if not rsa1:
print("Failed to load public key.")
libcrypto.ERR_print_errors_fp(sys.stderr) # 打印 OpenSSL 错误
return None

print(f"Public key loaded successfully from {pubkey_filename}.")
return rsa1

except Exception as e:
print(f"An error occurred: {e}")
return None


# 使用示例
pubkey_filename = "public_key.pem"
rsa_pubkey = load_public_key(pubkey_filename)

if rsa_pubkey:
print("Private key loaded successfully")
print_rsa_info(rsa_pubkey)
else:
print("Failed to load private key")


# 分块解密
def decrypt_rsa(rsa, encrypted_data):
rsa_len = libcrypto.RSA_size(ctypes.cast(rsa, c_void_p))
block_size = rsa_len
encrypted_len = len(encrypted_data)

decrypted_data = ctypes.create_string_buffer(encrypted_len)

decrypted_len = 0
i = 0

while i < encrypted_len:
# 对当前块进行解密
len_decrypted = libcrypto.RSA_public_decrypt(
block_size,
ctypes.byref(
ctypes.create_string_buffer(encrypted_data[i: i + block_size])
),
ctypes.byref(decrypted_data, decrypted_len),
ctypes.cast(rsa, c_void_p),
1, # RSA_PKCS1_OAEP_PADDING
)

if len_decrypted == -1:
print("RSA decryption failed")
libcrypto.ERR_print_errors_fp(sys.stderr)
return None

decrypted_len += len_decrypted
i += block_size

return decrypted_data.raw[:decrypted_len]


encrypted_base64 = b"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"
encrypted_data = base64.b64decode(encrypted_base64)

# 解密
decrypted_data = decrypt_rsa(rsa_pubkey, encrypted_data)
if decrypted_data is None:
sys.exit(1)

print(f"\nDecrypted Data:\n{decrypted_data.decode()}")