背景
pyDES是纯的python DES加密算法实现。系统目前使用PyDES的3DES加密算法,但是性能低下,已成为系统目前的瓶颈,为提高性能,考虑换用C语言实现。
Google C语言的DES实现,PolarSSL排在前面,这是纯C的实现,决定采用。
编译PolarSSL
首先在PolarSSL的网站(https://polarssl.org/)下载最新的源代码,解压。使用默认的配置文件编译出的结果是静态链接库(.a 文件),我用这个静态库在Python那边的C语言文件编译会失败,所以得编译成动态链接库(.so 文件)。如下修改配置文件:
1、打开PolarSSL的 library/Makefile 文件。
2、在文件头添加 SHARED = -shared。
然后在PolarSSL目录打开终端,执行
make all
等待编译完成之后执行安装
sudo make install
执行完上条命令之后我们可以看一下效果
ls /usr/local/lib/
ls /usr/local/include/
刚才编译好的文件都在以上目录存在了,这里需要注意,so文件只在 /usr/local/lib 目录下还是不够的,程序运行时会提示缺失,得复制到 /usr/lib 下。
sudo cp /usr/local/lib/libpolarssl.so.7 /usr/lib/
配置Python
按照我之前写的《探究:使用C语言扩展Python3》写好接口的C文件,源代码如下:
/*
Author : Zhou Cheng (Sink)
Date : July 17, 2014
*/
#include
#include
// My C function
void tdes_encrypt(const char *key_in, const char *data, char *dest, const int byte_len) {
const int KEY_SIZE = 24;
const int CHUNK_SIZE = 8;
char key[KEY_SIZE];
memset(key, 0, KEY_SIZE);
int len = (int)strlen(key_in);
if (len > KEY_SIZE)
len = KEY_SIZE;
memcpy(key, key_in, len);
des3_context ctx;
des3_set3key_enc(&ctx, (unsigned char *)key);
int i, j, k;
for (i = 0, j = byte_len / CHUNK_SIZE, k = 0; i
des3_crypt_ecb(&ctx, (unsigned char *)(data + k), (unsigned char *)(dest + k));
}
}
// python extending with c function
static PyObject *
triple_des_encrypt(PyObject *self, PyObject *args) {
char *key;
char *data;
if (!PyArg_ParseTuple(args, "ss", &key, &data))
return NULL;
int cur_len, new_len;
int i, j;
i = strlen(data);
j = i / 8;
if (i % 8)
j ++;
cur_len = i;
new_len = j * 8;
char *input = (char *)malloc(new_len);
char *output = (char *)malloc(new_len);
memset(input, '\0', new_len);
memset(output, '\0', new_len);
memcpy(input, data, cur_len);
tdes_encrypt(key, input, output, new_len);
PyObject *result = Py_BuildValue("y#", output, new_len);
free(input);
free(output);
return result;
}
// method table
static PyMethodDef DemoMethods[] = {
{"tdes_encrypt", triple_des_encrypt, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} /* Sentinel */
};
// The method table must be referenced in the module definition structure.
static struct PyModuleDef demomodule = {
PyModuleDef_HEAD_INIT,
"demo", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
DemoMethods
};
// The initialization function must be named PyInit_name()
PyMODINIT_FUNC
PyInit_demo(void)
{
return PyModule_Create(&demomodule);
}
这里用到了PolarSSL库里面的函数,加密字符串不足8byte的整数倍补0,加密密钥不足24位同样。
接下来配置编译文件 setup.py,在需要添加的库中包含 PolarSSL,代码如下:
from distutils.core import setup, Extension
module1 = Extension('demo',
libraries = ['polarssl'],
sources = ['demo.c'])
setup (name = '3DES',
version = '1.0',
description = 'This is a demo package by Sink',
ext_modules = [module1])
编译
python3 setup.py build
编译出的 so 文件就可以被调用了。
性能对比
Python随机生成1000条data和key,保证正确的情况下分别调用两个函数测试性能。C语言只要0.02秒,Python则花了182秒,性能差距巨大。测试代码如下:
import pyDes
import demo
import time
from random import Random
def random_str(randomlength=8):
str = ''
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789!@#$%^&*()_+'
length = len(chars) - 1
random = Random()
for i in range(randomlength):
str+=chars[random.randint(0, length)]
return str
def des_encrypt_test(key, data):
"""3des encrypt"""
if isinstance(key, str):
key = key.encode('utf-8')
if isinstance(data, str):
data = data.encode('utf-8')
if len(key)
key += (24 - len(key)) * b"\0"
k = pyDes.triple_des(key, pyDes.ECB, pad=b"\0")
d = k.encrypt(data)
# print("Encrypted:%r" % binascii.hexlify(d))
# print("Decrypted:%r" % binascii.hexlify(k.decrypt(d)))
# print("pre str :%r" % k.decrypt(d).decode("utf-8"))
return d
if __name__ == '__main__':
data = []
key = []
# data init
for x in range(1,1000):
data.append(random_str(x))
key.append(random_str(16 + (x % 9)))
pass
# Correct
for x in range(0,999):
p = des_encrypt_test(key[x], data[x])
c = demo.tdes_encrypt(key[x], data[x])
if (p != c):
print("Error\n")
print(key[x])
print(data[x])
print("\n")
pass
# Performance
st = time.time()
for x in range(0,999):
des_encrypt_test(key[x], data[x])
et = time.time()
print(" P Time taken: {0} seconds.".format(et - st))
st = time.time()
for x in range(0,999):
demo.tdes_encrypt(key[x], data[x])
et = time.time()
print(" C Time taken: {0} seconds.".format(et - st))
# P Time taken: 181.95579504966736 seconds.
# C Time taken: 0.027108192443847656 seconds.