From 61c8b385d7bb6c5e4c6397e6931975f8c47d105d Mon Sep 17 00:00:00 2001 From: lkcp Date: Wed, 27 Sep 2023 23:47:44 +0800 Subject: [PATCH] =?UTF-8?q?pyuadk=EF=BC=9Asupport=20crypto=20AES/SM3/SM4/R?= =?UTF-8?q?SA=20interface=20python=20wrapper=20for=20uadk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In scenarios such as federated learning, there is a significant need for encryption and decryption operations. The current user-space hardware acceleration library for Kunpeng, UADK, includes some implementations of encryption and decryption algorithms that offer better performance compared to software-based implementations. However, UADK provides a C language interface while federated learning typically utilizes the Python language. Therefore, there is a need for a Python wrapper for the UADK API, providing a set of Python interfaces. Through the utilization of Cython technology, this project (pyuadk) has successfully encapsulated the APIs of uadk v1, thereby providing a comprehensive set of Python interfaces. These interfaces are specifically tailored for scenarios that require the usage of Python interfaces, such as federated learning. The interfaces provided by pyuadk mainly include: 1. Complete encapsulation and test code for cipher, digest, and RSA in sync mode 2. Basic encapsulation and test code for cipher, digest, and RSA in async mode 3. All Cython code is linted using cython-lint and follows the PEP8 style guide. The following are the test command and logs: $ python3 test.py aes cbc test pass . aes ech test pass . sm4 cbc test pass . sm4 ech test pass . sm3 hmac test pass . sm3 normal test pass . rsa common genkey plus test pass . rsa ctr genkey test pass . rsa sign common test pass . rsa sign crt test pass . rsa verify common and crt test pass . Ran 11 tests in 0.014s OK --- README.en.md | 36 ---- README.md | 37 ---- pyuadk/cwd.pxd | 96 +++++++++ pyuadk/cwd_bmm.pxd | 26 +++ pyuadk/cwd_cipher.pxd | 82 ++++++++ pyuadk/cwd_digest.pxd | 72 +++++++ pyuadk/cwd_rsa.pxd | 126 ++++++++++++ pyuadk/cwd_util.pxd | 0 pyuadk/pyuadk.pxd | 0 pyuadk/pywd.pxd | 23 +++ pyuadk/pywd.pyx | 42 ++++ pyuadk/pywd_cipher.pyx | 265 ++++++++++++++++++++++++ pyuadk/pywd_digest.pyx | 220 ++++++++++++++++++++ pyuadk/pywd_rsa.pyx | 455 +++++++++++++++++++++++++++++++++++++++++ pyuadk/setup.py | 88 ++++++++ readme_en.md | 37 ++++ readme_zh.md | 37 ++++ requirements.txt | 2 + test.py | 325 +++++++++++++++++++++++++++++ test_aysnc.py | 156 ++++++++++++++ 20 files changed, 2052 insertions(+), 73 deletions(-) delete mode 100644 README.en.md delete mode 100644 README.md create mode 100644 pyuadk/cwd.pxd create mode 100644 pyuadk/cwd_bmm.pxd create mode 100644 pyuadk/cwd_cipher.pxd create mode 100644 pyuadk/cwd_digest.pxd create mode 100644 pyuadk/cwd_rsa.pxd create mode 100644 pyuadk/cwd_util.pxd create mode 100644 pyuadk/pyuadk.pxd create mode 100644 pyuadk/pywd.pxd create mode 100644 pyuadk/pywd.pyx create mode 100644 pyuadk/pywd_cipher.pyx create mode 100644 pyuadk/pywd_digest.pyx create mode 100644 pyuadk/pywd_rsa.pyx create mode 100644 pyuadk/setup.py create mode 100644 readme_en.md create mode 100644 readme_zh.md create mode 100644 requirements.txt create mode 100644 test.py create mode 100644 test_aysnc.py diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 27837bb..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# pyuadk - -#### Description -python wrapper of uadk - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md deleted file mode 100644 index d7aab37..0000000 --- a/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# pyuadk - -#### 介绍 -python wrapper of uadk - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/pyuadk/cwd.pxd b/pyuadk/cwd.pxd new file mode 100644 index 0000000..5b7d960 --- /dev/null +++ b/pyuadk/cwd.pxd @@ -0,0 +1,96 @@ + + +ctypedef unsigned int __u32 +ctypedef unsigned int __u8 + +cdef extern from "../uadk/v1/wd.h": + + ctypedef void (*wcrypto_cb)(const void *msg, void *tag); + + ctypedef void (*wd_log)(const char *formatt, ...); + + # memory APIs for Algorithm Layer + ctypedef void *(*wd_alloc)(void *usr, size_t size); + ctypedef void (*wd_free)(void *usr, void *va); + + # memory VA to DMA address map + ctypedef void *(*wd_map)(void *usr, void *va, size_t sz); + ctypedef void (*wd_unmap)(void *usr, void *va, void *dma, size_t sz); + ctypedef __u32 (*wd_bufsize)(void *usr); + + cdef wd_log log_out + + cdef struct wcrypto_cb_tag: + pass + ctypedef wcrypto_cb_tag wcrypto_cb_tag_t + + cdef struct wcrypto_oaras: + pass + ctypedef wcrypto_oaras wcrypto_oaras_t + + # a enum have 2 value + cdef enum wd_buff_type: + WD_FLAT_BUF = 0, + WD_SGL_BUF = 1 + ctypedef wd_buff_type wd_buff_type_t + + cdef struct wcrypto_paras: + __u8 direction, + __u8 is_poll + + cdef enum wcrypto_type: + WCRYPTO_RSA = 0, + WCRYPTO_CIPHER = 1, + WCRYPTO_DIGEST = 2, + ctypedef wcrypto_type wcrypto_type_t + + cdef struct wd_dtb: + char *data # data buffer start address + __u32 dsize # data size + __u32 bsize # buffer size + ctypedef wd_dtb wd_dtb_t + + # Memory from user, it is given at ctx creating. + cdef struct wd_mm_br: + wd_alloc alloc # emory allocation + wd_free free # Memory free + wd_map iova_map # get iova from user space VA + + # destroy the mapping between the PA of VA and iova + wd_unmap iova_unmap; + void *usr; + # data for the above operations + wd_bufsize get_bufsize # optional + ctypedef wd_mm_br wd_mm_br_t + + # capabilities + cdef struct wd_capa: + const char *alg + int throughput + int latency + __u32 flags + wcrypto_paras priv + + ctypedef wd_capa wd_capa_t + + cdef struct wd_queue: + wd_capa capa + char *dev_path + __u32 node_mask + void *qinfo + ctypedef wd_queue wd_queue_t + + int wd_request_queue(wd_queue *q) + void wd_release_queue(wd_queue *q) + int wd_send(wd_queue *q, void *req) + int wd_recv(wd_queue *q, void **resp) + int wd_wait(wd_queue *q, short ms) + int wd_recv_sync(wd_queue *q, void **resp, short ms) + void * wd_reserve_memory(wd_queue *q, size_t size) + int wd_share_reserved_memory(wd_queue *q, wd_queue *target_q) + int wd_get_available_dev_num(const char *alg_name) + int wd_get_node_id(wd_queue *q) + void * wd_iova_map(wd_queue *q, void *va, size_t sz) + void wd_iova_unmap(wd_queue *q, void *va, void *dma, size_t sz) + void * wd_dma_to_va(wd_queue *q, void *dma) + int wd_register_log(wd_log log) diff --git a/pyuadk/cwd_bmm.pxd b/pyuadk/cwd_bmm.pxd new file mode 100644 index 0000000..94a26f5 --- /dev/null +++ b/pyuadk/cwd_bmm.pxd @@ -0,0 +1,26 @@ +cimport cwd + +ctypedef unsigned int __u32 + +cdef extern from "../uadk/v1/wd_bmm.h": + # Memory pool creating parameters + cdef struct wd_blkpool_setup: + __u32 block_size # Block buffer size + __u32 block_num # Block buffer number + __u32 align_size # Block buffer starting address align size + cwd.wd_mm_br br # memory from user if don't use WD memory + ctypedef wd_blkpool_setup wd_blkpool_setup_t + + cdef struct wd_blkpool: + pass + + cdef void *wd_blkpool_create(cwd.wd_queue *q, + wd_blkpool_setup *setup) + cdef void wd_blkpool_destroy(void *pool) + cdef void *wd_alloc_blk(void *pool) + cdef void wd_free_blk(void *pool, void *blk) + cdef int wd_get_free_blk_num(void *pool, __u32 *free_num) + cdef int wd_blk_alloc_failures(void *pool, __u32 *fail_num) + cdef void *wd_blk_iova_map(void *pool, void *blk) + cdef void wd_blk_iova_unmap(void *pool, void *blk_dma, void *blk) + cdef __u32 wd_blksize(void *pool) diff --git a/pyuadk/cwd_cipher.pxd b/pyuadk/cwd_cipher.pxd new file mode 100644 index 0000000..b247119 --- /dev/null +++ b/pyuadk/cwd_cipher.pxd @@ -0,0 +1,82 @@ +cimport cwd + +ctypedef unsigned char __u8 +ctypedef unsigned short __u16 +ctypedef unsigned int __u32 +ctypedef unsigned long long __u64 + +cdef extern from "../uadk/v1/wd_cipher.h": + cdef enum wcrypto_cipher_op_type: + WCRYPTO_CIPHER_ENCRYPTION + WCRYPTO_CIPHER_DECRYPTION + ctypedef wcrypto_cipher_op_type wcrypto_cipher_op_type_t + + cdef enum wcrypto_cipher_alg: + WCRYPTO_CIPHER_SM4 + WCRYPTO_CIPHER_AES + WCRYPTO_CIPHER_DES + WCRYPTO_CIPHER_3DES + ctypedef wcrypto_cipher_alg wcrypto_cipher_alg_t + + cdef enum wcrypto_cipher_mode: + WCRYPTO_CIPHER_ECB + WCRYPTO_CIPHER_CBC + WCRYPTO_CIPHER_CTR + WCRYPTO_CIPHER_XTS + WCRYPTO_CIPHER_OFB + WCRYPTO_CIPHER_CFB + WCRYPTO_CIPHER_CCM + WCRYPTO_CIPHER_GCM + ctypedef wcrypto_cipher_mode wcrypto_cipher_mode_t + + cdef struct wcrypto_cipher_ctx_setup: + cwd.wcrypto_cb cb + wcrypto_cipher_alg alg + wcrypto_cipher_mode mode + cwd.wd_mm_br br + __u16 data_fmt + ctypedef wcrypto_cipher_ctx_setup wcrypto_cipher_ctx_setup_t + + cdef struct wcrypto_cipher_op_data: + wcrypto_cipher_op_type op_type + int status + void *in_ "in", + void *out_ "out", + void *iv, + __u32 in_bytes, + __u32 out_bytes, + __u32 iv_bytes, + void* priv + ctypedef wcrypto_cipher_op_data wcrypto_cipher_op_data_t + + cdef struct wcrypto_cipher_msg: + __u8 algo_type, + __u8 alg, + __u8 op_type, + __u8 mode, + __u8 data_fmt, + __u8 result, + + __u16 key_bytes, + __u16 iv_bytes, + __u32 in_bytes, + __u32 out_bytes, + + __u8 *key, + __u8 *iv, + __u8 *in_, + __u8 *out_, + __u64 usr_data + ctypedef wcrypto_cipher_msg wcrypto_cipher_msg_t + + cdef struct wcrypto_cipher_tag: + void *ctx + int thread_id + int cnt + + cdef void *wcrypto_create_cipher_ctx(cwd.wd_queue *q, wcrypto_cipher_ctx_setup *setup) + cdef int wcrypto_set_cipher_key(void *ctx, __u8 *key, __u16 key_len) + cdef int wcrypto_do_cipher(void *ctx, wcrypto_cipher_op_data *opdata, void *tag) + cdef int wcrypto_cipher_poll(cwd.wd_queue *q, __u32 num) + cdef void wcrypto_del_cipher_ctx(void *ctx) + cdef int wcrypto_burst_cipher(void* ctx, wcrypto_cipher_op_data **opdata, void **tag, __u32 num) diff --git a/pyuadk/cwd_digest.pxd b/pyuadk/cwd_digest.pxd new file mode 100644 index 0000000..b4a93c2 --- /dev/null +++ b/pyuadk/cwd_digest.pxd @@ -0,0 +1,72 @@ +ctypedef unsigned int __u32 +ctypedef unsigned short __u16 +ctypedef unsigned char __u8 +ctypedef unsigned long long __u64 + +cimport cwd +cdef extern from "../uadk/v1/wd_digest.h": + + cdef enum wcrypto_digest_alg: + WCRYPTO_SM3 + WCRYPTO_MD5 + ctypedef wcrypto_digest_alg wcrypto_digest_alg_t + + cdef enum wd_digest_mac_len: + WD_DIGEST_SM3_LEN + WD_DIGEST_MD5_LEN + ctypedef wd_digest_mac_len wd_digest_mac_len_t + + cdef enum wcrypto_digest_mode: + WCRYPTO_DIGEST_NORMAL + WCRYPTO_DIGEST_HMAC + ctypedef wcrypto_digest_mode wcrypto_digest_mode_t + + cdef struct wcrypto_digest_ctx_setup: + cwd.wcrypto_cb cb + wcrypto_digest_alg alg + wcrypto_digest_mode mode + cwd.wd_mm_br br + __u16 data_fmt + ctypedef wcrypto_digest_ctx_setup wcrypto_digest_ctx_setup_t + + cdef struct wcrypto_digest_op_data: + void *in_ "in", + void *out_ "out", + __u32 in_bytes, + __u32 out_bytes, + void *priv, + int status + bint has_next + ctypedef wcrypto_digest_op_data wcrypto_digest_op_data_t + + cdef struct wcrypto_digest_msg: + __u8 alg_type + __u8 alg + __u8 has_next + __u8 mode + __u8 data_fmt + __u8 result + __u16 key_bytes + __u16 iv_bytes + + __u8 *key + __u8 *iv + __u8 *in_ + __u8 *out_ + __u32 in_bytes + __u32 out_bytes + __u64 usr_data + ctypedef wcrypto_digest_msg wcrypto_digest_msg_t + + cdef void *wcrypto_create_digest_ctx( + cwd.wd_queue *q, + wcrypto_digest_ctx_setup *setup + ) + + cdef int wcrypto_set_digest_key(void *ctx, __u8 *key, __u16 key_len) + + cdef int wcrypto_do_digest(void *ctx, wcrypto_digest_op_data *opdata, void *tag) + + cdef int wcrypto_digest_poll(cwd.wd_queue *q, __u32 num) + + cdef void wcrypto_del_digest_ctx(void *ctx) diff --git a/pyuadk/cwd_rsa.pxd b/pyuadk/cwd_rsa.pxd new file mode 100644 index 0000000..f83bb8c --- /dev/null +++ b/pyuadk/cwd_rsa.pxd @@ -0,0 +1,126 @@ +ctypedef unsigned char __u8 +ctypedef unsigned short __u16 +ctypedef unsigned int __u32 +ctypedef unsigned long long __u64 + +cimport cwd + +cdef extern from "../uadk/v1/wd_rsa.h": + # 这种声明方式只能使用指针 + cdef struct wcrypto_rsa_kg_in: + pass + + cdef struct wcrypto_rsa_kg_out: + pass + + + cdef struct wcrypto_rsa_pubkey: + pass + cdef struct wcrypto_rsa_prikey: + pass + + # RSA operational types + cdef enum wcrypto_rsa_op_type: + WCRYPTO_RSA_INVALID, # invalid rsa operation + WCRYPTO_RSA_SIGN, # RSA sign + WCRYPTO_RSA_VERIFY, # RSA verify + WCRYPTO_RSA_GENKEY, # RSA key generation + + #RSA key types + cdef enum wcrypto_rsa_key_type: + WCRYPTO_RSA_INVALID_KEY, # invalid rsa key type + WCRYPTO_RSA_PUBKEY, # rsa public key type + WCRYPTO_RSA_PRIKEY1, # invalid rsa private common key type + WCRYPTO_RSA_PRIKEY2, # invalid rsa private CRT key type + + # RSA context setting up input parameters from user + cdef struct wcrypto_rsa_ctx_setup: + cwd.wcrypto_cb cb # call back function from user + __u16 data_fmt # data format denoted by enum wd_buff_type + __u16 key_bits # RSA key bits + bint is_crt # CRT mode or not + cwd.wd_mm_br br # memory operations from user + + cdef struct wcrypto_rsa_op_data: + wcrypto_rsa_op_type op_type # rsa operation type + int status # rsa operation status + void *in_ 'in' # rsa operation input address, should be DMA-able + void *out # rsa operation output address, should be DMA-able + int in_bytes # rsa operation input bytes + int out_bytes # rsa operation output bytes + + # RSA message format of Warpdrive + cdef struct wcrypto_rsa_msg: + __u8 alg_type # Denoted by enum wcrypto_type + __u8 op_type # Denoted by enum wcrypto_rsa_op_type + __u8 key_type # Denoted by enum wcrypto_rsa_key_type + __u8 data_fmt # Data format, denoted by enum wd_buff_type + __u8 result # Data format, denoted by WD error code + __u16 in_bytes # Input data bytes + __u16 out_bytes # Output data bytes + __u16 key_bytes # Input key bytes + __u8 *in_ # Input data VA, buf should be DMA buffer. + __u8 *out # Output data VA pointer, should be DMA buffer + __u8 *key # Input key VA pointer, should be DMA buffer + + # ''' + # * Input user tag, used for identify data stream/user: + #* struct wcrypto_cb_tag + # ''' + __u64 usr_data + + + cdef bint wcrypto_rsa_is_crt(const void *ctx) + cdef int wcrypto_rsa_key_bits(const void *ctx) + cdef void *wcrypto_create_rsa_ctx(cwd.wd_queue *q, wcrypto_rsa_ctx_setup *setup) + cdef void wcrypto_get_rsa_pubkey(void *ctx, wcrypto_rsa_pubkey **pubkey) + cdef void wcrypto_get_rsa_prikey(void *ctx, wcrypto_rsa_prikey **prikey) + cdef int wcrypto_set_rsa_pubkey_params(void *ctx, cwd.wd_dtb *e, cwd.wd_dtb *n) + cdef void wcrypto_get_rsa_pubkey_params(wcrypto_rsa_pubkey *pbk, cwd.wd_dtb **e, cwd.wd_dtb **n) + cdef int wcrypto_set_rsa_prikey_params(void *ctx, cwd.wd_dtb *d, cwd.wd_dtb *n) + cdef void wcrypto_get_rsa_prikey_params(wcrypto_rsa_prikey *pvk, cwd.wd_dtb **d, cwd.wd_dtb **n) + cdef int wcrypto_set_rsa_crt_prikey_params(void *ctx, cwd.wd_dtb *dq, + cwd.wd_dtb *dp, + cwd.wd_dtb *qinv, + cwd.wd_dtb *q, + cwd.wd_dtb *p) + cdef void wcrypto_get_rsa_crt_prikey_params(wcrypto_rsa_prikey *pvk, + cwd.wd_dtb **dq, cwd.wd_dtb **dp, + cwd.wd_dtb **qinv, cwd.wd_dtb **q, + cwd.wd_dtb **p) + + # APIs For RSA key generate + # new_kg_in 和 get_kg_in_params 是相反的过程,前者是将p、q、e赋值给ki,后者是将ki中的p、q、e赋值给p、q、e + cdef wcrypto_rsa_kg_in *wcrypto_new_kg_in(void *ctx, cwd.wd_dtb *e, + cwd.wd_dtb *p, cwd.wd_dtb *q) + cdef void wcrypto_del_kg_in(void *ctx, wcrypto_rsa_kg_in *ki) + cdef void wcrypto_get_rsa_kg_in_params(wcrypto_rsa_kg_in *kin, cwd.wd_dtb *e, cwd.wd_dtb *q, cwd.wd_dtb *p) + + cdef wcrypto_rsa_kg_out *wcrypto_new_kg_out(void *ctx) + cdef void wcrypto_del_kg_out(void *ctx, wcrypto_rsa_kg_out *kout) + cdef void wcrypto_get_rsa_kg_out_params(wcrypto_rsa_kg_out *kout, + cwd.wd_dtb *d, + cwd.wd_dtb *n) + cdef void wcrypto_get_rsa_kg_out_crt_params(wcrypto_rsa_kg_out *kout, + cwd.wd_dtb *qinv, + cwd.wd_dtb *dq, cwd.wd_dtb *dp) + + cdef int wcrypto_rsa_kg_in_data(wcrypto_rsa_kg_in *ki, char **data) + cdef int wcrypto_rsa_kg_out_data(wcrypto_rsa_kg_out *ko, char **data) + cdef void wcrypto_set_rsa_kg_out_crt_psz(wcrypto_rsa_kg_out *kout, + size_t qinv_sz, + size_t dq_sz, + size_t dp_sz) + cdef void wcrypto_set_rsa_kg_out_psz(wcrypto_rsa_kg_out *kout, + size_t d_sz, + size_t n_sz) + + # ''' + # * This is a pair of asynchronous mode RSA API as tag is not NULL, + # * or it is synchronous mode + # ''' + cdef int wcrypto_do_rsa(void *ctx, wcrypto_rsa_op_data *opdata, void *tag) + cdef int wcrypto_rsa_poll(cwd.wd_queue *q, __u32 num) + cdef void wcrypto_del_rsa_ctx(void *ctx) + + diff --git a/pyuadk/cwd_util.pxd b/pyuadk/cwd_util.pxd new file mode 100644 index 0000000..e69de29 diff --git a/pyuadk/pyuadk.pxd b/pyuadk/pyuadk.pxd new file mode 100644 index 0000000..e69de29 diff --git a/pyuadk/pywd.pxd b/pyuadk/pywd.pxd new file mode 100644 index 0000000..c36dce7 --- /dev/null +++ b/pyuadk/pywd.pxd @@ -0,0 +1,23 @@ +cimport cwd +cimport cwd_bmm + + +cdef cwd.wd_alloc wd_alloc_func +cdef cwd.wd_free wd_free_func +cdef cwd.wd_map wd_map_func +cdef cwd.wd_unmap wd_unmap_func +cdef cwd.wd_bufsize wd_bufsize_func + + +cdef class Wd: + cdef cwd.wd_queue *queue + cdef cwd.wd_capa *capa + + cdef cwd_bmm.wd_blkpool_setup *wsetup + cdef void *ctx + cdef cwd_bmm.wd_blkpool *pool + + cpdef int request_queue(self) + + cpdef int wd_get_available_dev_num(self) + diff --git a/pyuadk/pywd.pyx b/pyuadk/pywd.pyx new file mode 100644 index 0000000..8098abb --- /dev/null +++ b/pyuadk/pywd.pyx @@ -0,0 +1,42 @@ +cimport cwd +cimport cwd_bmm +from libc.stdlib cimport malloc +from libc.string cimport memset, strcpy + + +cdef class Wd(object): + + def __cinit__( + self, + dev_path: str = None, + node_mask: int = None, + async_mode: int = 1 + ): + self.queue = malloc (sizeof(cwd.wd_queue)) + self.capa = malloc (sizeof(cwd.wd_capa)) + self.wsetup =\ + malloc (sizeof(cwd_bmm.wd_blkpool_setup)) + self.pool = NULL + self.ctx = NULL + + cdef bytes cdev_path + if dev_path is not None: + cdev_path = dev_path.encode() + strcpy(self.queue.dev_path, cdev_path) + if node_mask is not None: + self.queue.node_mask = node_mask + + memset(self.queue, 0, sizeof(cwd.wd_queue)) + memset(self.capa, 0, sizeof(cwd.wd_capa)) + memset(self.wsetup, 0, sizeof(cwd_bmm.wd_blkpool_setup)) + + cpdef int request_queue(self): + ret = cwd.wd_request_queue(self.queue) + if ret != 0 or self.queue == NULL: + raise MemoryError("request_queue failed") + return 0 + + cpdef int wd_get_available_dev_num(self): + return cwd.wd_get_available_dev_num(self.capa.alg) + + diff --git a/pyuadk/pywd_cipher.pyx b/pyuadk/pywd_cipher.pyx new file mode 100644 index 0000000..c3d4c02 --- /dev/null +++ b/pyuadk/pywd_cipher.pyx @@ -0,0 +1,265 @@ +cimport cwd_cipher +cimport cwd +cimport cwd_bmm +from pyuadk.pywd cimport * +from libc.stdlib cimport malloc +from libc.string cimport memcpy +from enum import Enum + + +class CIPHER_ALG(Enum): + AES = 0 + SM4 = 1 + + +class CIPHER_MODE(Enum): + ECB = 0 + CBC = 1 + CTR = 2 + XTS = 3 + OFB = 4 + CFB = 5 + CCM = 6 + GCM = 7 + + +class CIPHER_OP_TYPE(Enum): + ENCRYPT = 0 + DECRYPT = 1 + + +cdef void callback(void *message, void *tag): + print("cipher callback") + +cdef struct wcrypto_cipher_tag: + void *ctx + int thread_id + int cnt + + +cdef class Cipher(Wd): + + cdef cwd_cipher.wcrypto_cipher_ctx_setup *setup + cdef cwd_cipher.wcrypto_cipher_op_data *opdata + cdef wcrypto_cipher_tag *tag + cdef bint async_mode + + def __cinit__( + self, + dev_path: str = None, + node_mask: int = None, + async_mode: int = 0 + ): + self.setup = \ + malloc(sizeof(cwd_cipher.wcrypto_cipher_ctx_setup)) + self.opdata = \ + malloc(sizeof(cwd_cipher.wcrypto_cipher_op_data)) + self.tag = NULL + self.capa.alg = "cipher" + cdef void *capa_ptr = &self.queue.capa + memcpy(capa_ptr, self.capa, sizeof(cwd.wd_capa)) + self.async_mode = async_mode + + cpdef void pool_setup(self, block_size=1024*8, block_num=128, align_size=128): + + '''setup pool + create pool memory: block_nm * block_size + params: + block_size: block size + block_num: block number + align_size: align size + ''' + + self.wsetup.block_size = block_size + self.wsetup.block_num = block_num + self.wsetup.align_size = align_size + self.pool = \ + cwd_bmm.wd_blkpool_create(self.queue, self.wsetup) + if self.pool == NULL: + raise MemoryError("wd_blkpool_create failed") + + cpdef void ctx_setup(self, alg: CIPHER_ALG, mode: CIPHER_MODE): + + '''setup ctx (alg, mode, br) + a callback func is needed in async mode + params: + alg: aes or sm4 + mode: ecb or cbc or ctr or xts or ofb or cfb or ccm or gcm + ''' + + if alg == CIPHER_ALG.AES: + self.setup.alg = cwd_cipher.WCRYPTO_CIPHER_AES + elif alg == CIPHER_ALG.SM4: + self.setup.alg = cwd_cipher.WCRYPTO_CIPHER_SM4 + else: + raise ValueError("alg must be CIPHER_ALG.AES or CIPHER_ALG.SM4") + + if mode == CIPHER_MODE.ECB: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_ECB + elif mode == CIPHER_MODE.CBC: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_CBC + elif mode == CIPHER_MODE.CTR: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_CTR + elif mode == CIPHER_MODE.XTS: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_XTS + elif mode == CIPHER_MODE.OFB: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_OFB + elif mode == CIPHER_MODE.CFB: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_CFB + elif mode == CIPHER_MODE.CCM: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_CCM + elif mode == CIPHER_MODE.GCM: + self.setup.mode = cwd_cipher.WCRYPTO_CIPHER_GCM + else: + raise ValueError("unexcepted mode") + + if self.async_mode == 1: + self.setup.cb = callback + else: + self.setup.cb = NULL + self.setup.br.alloc = cwd_bmm.wd_alloc_blk + self.setup.br.free = cwd_bmm.wd_free_blk + self.setup.br.iova_map = cwd_bmm.wd_blk_iova_map + self.setup.br.iova_unmap = cwd_bmm.wd_blk_iova_unmap + self.setup.br.get_bufsize = cwd_bmm.wd_blksize + self.setup.br.usr = self.pool + + cpdef int create_cipher_ctx(self): + + '''create ctx + create cipher ctx after ctx setup + return -1 means create failed + ''' + + self.ctx = cwd_cipher.wcrypto_create_cipher_ctx(self.queue, self.setup) + if self.ctx == NULL: + raise Exception("create ctx failed!") + return -1 + return 0 + + cpdef int wcrypto_set_cipher_key(self, key: bytes, key_len: int): + + '''set cipher key + params: + key: bytes with length of key_len + key_len: cipher key length + ''' + + cdef unsigned char *ckey = \ + malloc (key_len*sizeof(unsigned char)) + for i in range(key_len): + ckey[i] = key[i] + return cwd_cipher.wcrypto_set_cipher_key(self.ctx, ckey, key_len) + + cpdef void set_opdata(self, bytes iv, op_type: CIPHER_OP_TYPE, bytes text): + + ''' set opdata(iv, enc/dec. pt/ct) + params: + iv: iv, bytes with length of block_len + op_type: encrypt or decrypt + text: bytes with length of block_len + ''' + + # iv + self.opdata.iv = cwd_bmm.wd_alloc_blk(self.pool) + if self.opdata.iv == NULL: + raise MemoryError("wd blk fail failed") + cdef unsigned char *c_iv = iv + memcpy(self.opdata.iv, c_iv, len(iv)) + self.opdata.iv_bytes = len(iv) + + # op_type + if op_type == CIPHER_OP_TYPE.ENCRYPT: + self.opdata.op_type = cwd_cipher.WCRYPTO_CIPHER_ENCRYPTION + self.queue.capa.priv.direction = 0 + elif op_type == CIPHER_OP_TYPE.DECRYPT: + self.opdata.op_type = cwd_cipher.WCRYPTO_CIPHER_DECRYPTION + self.queue.capa.priv.direction = 1 + else: + raise ValueError("op_type must be \ + CIPHER_OP_TYPE.ENCRYPT or CIPHER_OP_TYPE.DECRYPT") + self.opdata.priv = NULL + + # text + self.opdata.in_ = \ + cwd_bmm.wd_alloc_blk(self.pool) + if self.opdata.in_ == NULL: + raise MemoryError("wd_alloc_blk failed") + cdef unsigned char *c_text = text + memcpy(self.opdata.in_, c_text, len(text)) + self.opdata.in_bytes = len(text) + + # out + self.opdata.out_ = cwd_bmm.wd_alloc_blk(self.pool) + if self.opdata.out_ == NULL: + raise MemoryError("wd_alloc_blk failed") + self.opdata.out_bytes = self.opdata.in_bytes + + cpdef void tag_setup(self, int cnt, int thread_id): + + """setup a fixed tag + cnt: user set (0?) + thread_id: acquired from python + """ + + if self.async_mode == 1: + self.tag = malloc(sizeof(wcrypto_cipher_tag)) + self.tag.ctx = self.ctx + self.tag.cnt = cnt + self.tag.thread_id = thread_id + else: + print("sync mode no need to setup tag") + + cpdef int wcrypto_do_cipher(self): + + """do cipher + do cipher in async mode(Non-Null tag is needed) or sync mode + """ + + if self.async_mode == 1: + if self.tag == NULL: + raise ValueError("tag must not be None in async mode") + return cwd_cipher.wcrypto_do_cipher(self.ctx, self.opdata, self.tag) + else: + return cwd_cipher.wcrypto_do_cipher(self.ctx, self.opdata, NULL) + + cpdef int wcrypto_cipher_poll(self, num: int): + + """poll self.queue + num: poll num (>1) + """ + if num < 1: + return -1 + + return cwd_cipher.wcrypto_cipher_poll(self.queue, num) + + cpdef bytes get_ct(self): + + """get ciphertext in bytes format + """ + + cdef unsigned char *c_ct =\ + malloc(self.opdata.out_bytes*sizeof(unsigned char)) + memcpy(c_ct, self.opdata.out_, self.opdata.out_bytes) + return bytes(c_ct) + + def __dealloc__(self): + + """free all resources + """ + + if self.opdata.in_ is not NULL and self.pool is not NULL: + cwd_bmm.wd_free_blk(self.pool, self.opdata.in_) + + if self.opdata.out_ is not NULL and self.pool is not NULL: + cwd_bmm.wd_free_blk(self.pool, self.opdata.out_) + + if self.opdata.iv is not NULL and self.pool is not NULL: + cwd_bmm.wd_free_blk(self.pool, self.opdata.iv) + + cwd_cipher.wcrypto_del_cipher_ctx(self.ctx) + + if self.queue is not NULL and self.queue.qinfo is not NULL: + cwd.wd_release_queue(self.queue) + + # cwd_bmm.wd_blkpool_destroy(self.pool) diff --git a/pyuadk/pywd_digest.pyx b/pyuadk/pywd_digest.pyx new file mode 100644 index 0000000..9b83e97 --- /dev/null +++ b/pyuadk/pywd_digest.pyx @@ -0,0 +1,220 @@ +cimport cwd +cimport cwd_digest +cimport cwd_bmm +from pyuadk.pywd cimport * +from libc.stdlib cimport malloc +from libc.string cimport memcpy +from enum import Enum + + +class DIGEST_ALG(Enum): + SM3 = 0 + + +class DIGEST_MODE(Enum): + NORMAL = 0 + HMAC = 1 + + +cdef void callback(void *message, void *tag): + print("digest callback") + +cdef struct wcrypto_digest_tag: + void *ctx + int thread_id + int cnt + +cdef class Digest(Wd): + + cdef cwd_digest.wcrypto_digest_ctx_setup *setup + cdef cwd_digest.wcrypto_digest_op_data *opdata + cdef wcrypto_digest_tag *tag + cdef bint async_mode + + def __cinit__( + self, + dev_path: str = None, + node_mask: int = None, + async_mode: int = 0 + ): + self.setup = \ + malloc (sizeof(cwd_digest.wcrypto_digest_ctx_setup)) + self.opdata = \ + malloc (sizeof(cwd_digest.wcrypto_digest_op_data)) + self.tag = \ + malloc (sizeof(wcrypto_digest_tag)) + self.async_mode = async_mode + self.capa.alg = "digest" + cdef void *capa_ptr = &self.queue.capa + memcpy(capa_ptr, self.capa, sizeof(cwd.wd_capa)) + + cpdef void pool_setup(self, block_size=1024*8, block_num=128, align_size=128): + + ''' setup and create pool + params: + block_size: block size + block_num: block number + align_size: align size + ''' + + self.wsetup.block_size = block_size + self.wsetup.block_num = block_num + self.wsetup.align_size = align_size + self.pool =\ + cwd_bmm.wd_blkpool_create(self.queue, self.wsetup) + if self.pool == NULL: + raise MemoryError("create pool failed") + + cpdef ctx_setup(self, alg: DIGEST_ALG, mode: DIGEST_MODE): + + '''set ctx setup + params: + alg: digest algorithm(SM3 only) + mode: digest mode(NORMAL or HMAC) + ''' + + if alg == DIGEST_ALG.SM3: + self.setup.alg = cwd_digest.WCRYPTO_SM3 + else: + raise ValueError("digest algorithm not support") + + if mode == DIGEST_MODE.NORMAL: + self.setup.mode = cwd_digest.WCRYPTO_DIGEST_NORMAL + elif mode == DIGEST_MODE.HMAC: + self.setup.mode = cwd_digest.WCRYPTO_DIGEST_HMAC + else: + raise ValueError("digest mode not support") + + if self.async_mode == 1: + self.setup.cb = callback + else: + self.setup.cb = NULL + self.setup.br.alloc = cwd_bmm.wd_alloc_blk + self.setup.br.free = cwd_bmm.wd_free_blk + self.setup.br.iova_map = cwd_bmm.wd_blk_iova_map + self.setup.br.iova_unmap = cwd_bmm.wd_blk_iova_unmap + self.setup.br.get_bufsize = cwd_bmm.wd_blksize + self.setup.br.usr = self.pool + + cpdef void create_digest_ctx(self): + '''create ctx + ''' + self.ctx = cwd_digest.wcrypto_create_digest_ctx(self.queue, self.setup) + if self.ctx == NULL: + raise Exception("create ctx failed!") + + cpdef int wcrypto_set_digest_key(self, key: bytes, key_len: int): + + ''' digest key (only for HMAC mode) + params: + key: digest key, byte array of digest key length + key_len: digest key length + ''' + + if self.setup.mode != cwd_digest.WCRYPTO_DIGEST_HMAC: + raise ValueError("only set key for HMAC mode") + cdef unsigned char *ckey = key + for i in range(len(key)): + ckey[i] = key[i] + return cwd_digest.wcrypto_set_digest_key(self.ctx, ckey, key_len) + + cpdef void set_opdata(self, bytes text, int dsize): + + '''set digest data(to be hashed) + params: + text: digest data + dsize: digest data length + ''' + + self.opdata.in_ = cwd_bmm.wd_alloc_blk(self.pool) + if self.opdata.in_ == NULL: + raise MemoryError("wd_alloc_blk failed") + cdef unsigned char *c_text = text + memcpy(self.opdata.in_, c_text, len(text)) + self.opdata.in_bytes = len(text) + + self.opdata.out_ = cwd_bmm.wd_alloc_blk(self.pool) + if self.opdata.out_ == NULL: + raise MemoryError("alloc output buffer failed") + self.opdata.out_bytes = dsize + self.opdata.priv = NULL + + cpdef void tag_setup(self, int cnt, int thread_id): + + """setup a fixed tag + cnt: user set (0?) + thread_id: acquired from python + """ + + if self.async_mode == 1: + self.tag = malloc(sizeof(wcrypto_digest_tag)) + self.tag.ctx = self.ctx + self.tag.cnt = cnt + self.tag.thread_id = thread_id + else: + print("sync mode no need to setup tag") + + cpdef int wcrypto_do_digest(self): + '''do digest + ''' + if self.async_mode == 1: + if self.tag == NULL: + raise ValueError("tag must not be None in async mode") + return cwd_digest.wcrypto_do_digest(self.ctx, self.opdata, self.tag) + else: + return cwd_digest.wcrypto_do_digest(self.ctx, self.opdata, NULL) + + cpdef int wcrypto_digest_poll(self, num: int): + '''digest poll + ''' + if (num < 1): + raise ValueError("num must be greater than 0") + if self.async_mode == 0: + raise ValueError("sync mode not support poll") + return cwd_digest.wcrypto_digest_poll(self.queue, num) + + cpdef void wcrypto_del_digest_ctx(self): + cwd_digest.wcrypto_del_digest_ctx(self.ctx) + + # cdef int wcrypto_burst_digest(self, num): + # cdef cwd_digest.wcrypto_digest_op_data **opdata_ptr = &self.opdata + # return cwd_digest.wcrypto_burst_digest(self.ctx, opdata_ptr, NULL, num) + + cdef int sync_do_digest(self): + cdef int data_len = self.opdata.in_bytes + while (1): + if data_len > 256: + self.opdata.in_bytes = 256 + data_len -= 256 + else: + self.opdata.in_bytes = data_len + break + self.opdata.has_next = (data_len >= 256) + ret = cwd_digest.wcrypto_do_digest(self.ctx, self.opdata, NULL) + if ret < 0: + raise Exception("digest failed") + return 0 + + cpdef bytes get_digest(self): + cdef unsigned char *digest =\ + malloc(self.opdata.out_bytes*sizeof(unsigned char)) + memcpy(digest, self.opdata.out_, self.opdata.out_bytes) + return bytes(digest) + + def __dealloc__(self): + + """free all resources + """ + + if self.opdata.in_ is not NULL and self.pool is not NULL: + cwd_bmm.wd_free_blk(self.pool, self.opdata.in_) + + if self.opdata.out_ is not NULL and self.pool is not NULL: + cwd_bmm.wd_free_blk(self.pool, self.opdata.out_) + + cwd_digest.wcrypto_del_digest_ctx(self.ctx) + + if self.queue is not NULL and self.queue.qinfo is not NULL: + cwd.wd_release_queue(self.queue) + + cwd_bmm.wd_blkpool_destroy(self.pool) diff --git a/pyuadk/pywd_rsa.pyx b/pyuadk/pywd_rsa.pyx new file mode 100644 index 0000000..c42914e --- /dev/null +++ b/pyuadk/pywd_rsa.pyx @@ -0,0 +1,455 @@ +cimport cwd_rsa +cimport cwd +cimport cwd_bmm +from pyuadk.pywd cimport * +from libc.string cimport memset, memcpy +from libc.stdlib cimport malloc, free +from enum import Enum + + +class RSA_OP_TYPE(Enum): + RSA_INVALID = 0 + SIGN = 1 + VERIFY = 2 + GENKEY = 3 + + +cdef void callback(void *message, void *tag): + print("rsa callback") + +cdef struct wcrypto_rsa_tag: + void *ctx + int thread_id + int cnt + +cdef class RSA(Wd): + + cdef cwd_rsa.wcrypto_rsa_ctx_setup *setup + cdef cwd_rsa.wcrypto_rsa_op_data *opdata + cdef wcrypto_rsa_tag *tag + cdef bint async_mode + + cdef cwd_rsa.wcrypto_rsa_kg_in *kg_in + cdef cwd_rsa.wcrypto_rsa_kg_out *kg_out + + cdef cwd_rsa.wcrypto_rsa_pubkey *pubk + cdef cwd_rsa.wcrypto_rsa_prikey *prik + + + cdef cwd.wd_dtb *n + cdef cwd.wd_dtb *e + cdef cwd.wd_dtb *d + cdef cwd.wd_dtb *p + cdef cwd.wd_dtb *q + cdef cwd.wd_dtb *dp + cdef cwd.wd_dtb *dq + cdef cwd.wd_dtb *qinv + cdef int key_bits + + def __cinit__( + self, + dev_path: str=None, + node_mask: int=None, + async_mode: int=0 + ): + self.setup = malloc (sizeof(cwd_rsa.wcrypto_rsa_ctx_setup)) + self.opdata = malloc (sizeof(cwd_rsa.wcrypto_rsa_op_data)) + self.tag = NULL + self.async_mode = async_mode + self.capa.alg = "rsa" + cdef void *capa_ptr = &self.queue.capa + memcpy(capa_ptr, self.capa, sizeof(cwd.wd_capa)) + + self.n = malloc (sizeof(cwd.wd_dtb)) + self.e = malloc (sizeof(cwd.wd_dtb)) + self.d = malloc (sizeof(cwd.wd_dtb)) + self.p = malloc (sizeof(cwd.wd_dtb)) + self.q = malloc (sizeof(cwd.wd_dtb)) + self.dp = malloc (sizeof(cwd.wd_dtb)) + self.dq = malloc (sizeof(cwd.wd_dtb)) + self.qinv = malloc (sizeof(cwd.wd_dtb)) + + cpdef void pool_setup(self, int block_num, int key_bits): + + '''setup and createpool + params: + key_bits: int + block_num: int + ''' + + self.key_bits = key_bits + self.wsetup.block_size = (self.key_bits >> 3)*7 + self.wsetup.block_num = block_num + self.wsetup.align_size = 64 + self.pool = cwd_bmm.wd_blkpool_create(self.queue, self.wsetup) + if self.pool == NULL: + raise MemoryError("create pool failed") + + + cpdef void ctx_setup(self, bint is_crt): + + '''init ctx_setup + params: + is_crt: bool + ''' + if self.async_mode == 1: + self.setup.cb = callback + else: + self.setup.cb = NULL + self.setup.is_crt = is_crt + self.setup.key_bits = self.key_bits + self.setup.br.alloc = cwd_bmm.wd_alloc_blk + self.setup.br.free = cwd_bmm.wd_free_blk + self.setup.br.iova_map = cwd_bmm.wd_blk_iova_map + self.setup.br.iova_unmap = cwd_bmm.wd_blk_iova_unmap + self.setup.br.get_bufsize = cwd_bmm.wd_blksize + self.setup.br.usr = self.pool + + + cpdef void set_opdata(self, op_type: RSA_OP_TYPE, data=None): + + '''set opdata before do rsa + params: + op_type: key_gen, sign, verify + data: invalid in genkey + status: assign value in do_rsa() + in_: pointer, return from wcrypto_new_kg_in(GENKEY) or wd_alloc_blk(else). + out: pointer, return from wcrypto_new_kg_out(GENKEY) or wd_alloc_blk(else) + in_bytes: int (key_size, for example) + out_bytes: int + ''' + + cdef unsigned char *in_data + + if op_type == RSA_OP_TYPE.GENKEY: + + self.opdata.op_type = cwd_rsa.wcrypto_rsa_op_type.WCRYPTO_RSA_GENKEY + if self.kg_in is not NULL and self.kg_out is not NULL: + self.opdata.in_ = self.kg_in + self.opdata.out = self.kg_out + else: + print("please create kg_in and kg_out") + return + self.opdata.in_bytes = self.key_bits >> 3 + self.opdata.out_bytes = self.key_bits >> 3 + + else: + if data == None: + raise ValueError("data is None") + + self.opdata.in_ = cwd_bmm.wd_alloc_blk(self.pool) + self.opdata.out = cwd_bmm.wd_alloc_blk(self.pool) + + if self.opdata.in_ is NULL or self.opdata.out is NULL: + raise MemoryError("alloc blk failed") + + in_data = malloc(len(data)*sizeof(unsigned char)) + for i in range(len(data)): + in_data[i] = data[i] + memcpy(self.opdata.in_, in_data, len(data)) + self.opdata.in_bytes = len(data) + self.opdata.out_bytes = len(data) + + + if op_type == RSA_OP_TYPE.SIGN: + # if msg == None: + # raise ValueError("msg is None") + self.opdata.op_type = cwd_rsa.wcrypto_rsa_op_type.WCRYPTO_RSA_SIGN + + elif op_type == RSA_OP_TYPE.VERIFY: + # if sig == None: + # raise ValueError("sig is None") + self.opdata.op_type = cwd_rsa.wcrypto_rsa_op_type.WCRYPTO_RSA_VERIFY + + else: + print("op_type error") + return + + # cdef int wcrypto_rsa_key_bits(self): + # + # """ + # get key_bits from ctx + # """ + # + # return cwd_rsa.wcrypto_rsa_key_bits(self.ctx) + + + cpdef void create_rsa_ctx(self): + + """create ctx + create ctx after init setup + """ + self.ctx = cwd_rsa.wcrypto_create_rsa_ctx(self.queue, self.setup) + + + cpdef void wcrypto_get_rsa_pubkey(self): + + """ + link self.pubk to ctx->pubkey + code: *pubkey = ((struct wcrypto_rsa_ctx *)ctx)->pubkey; + """ + + cwd_rsa.wcrypto_get_rsa_pubkey(self.ctx, &self.pubk) + + cpdef void wcrypto_get_rsa_prikey(self): + + """ + link self.prik to ctx->prikey + code: *prikey = ((struct wcrypto_rsa_ctx *)ctx)->prikey; + """ + + cwd_rsa.wcrypto_get_rsa_prikey(self.ctx, &self.prik) + + + + cpdef void wcrypto_get_rsa_pubkey_params(self): + + """ + link self.e, self.n to self.pubk->e, self.pubk->n + code: + *e = &pbk->e; + *n = &pbk->n; + e, n is not necessary to be malloced + """ + + cwd_rsa.wcrypto_get_rsa_pubkey_params(self.pubk, &self.e, &self.n) + + cpdef void wcrypto_get_rsa_prikey_params(self): + + """ + link self.d, self.n to self.prik->d, self.prik->n + code: + *d = &pkey1->d; + *n = &pkey1->n; + d, n is not necessary to be malloced + """ + + cwd_rsa.wcrypto_get_rsa_prikey_params(self.prik, &self.d, &self.n) + + cpdef void wcrypto_set_rsa_pubkey_params(self, bytes e, bytes n): + + """ + data copy rather than link + copy data from e, n to self.ctx->pubkey->e, self.ctx->pubkey->n + code: + memcpy(c->prik->pkey1->e.data, e->data, e->dsize); + memcpy(c->prik->pkey1->n.data, n->data, n->dsize); + """ + + cdef cwd.wd_dtb *ce = malloc (sizeof(cwd.wd_dtb)) + cdef cwd.wd_dtb *cn = malloc (sizeof(cwd.wd_dtb)) + ce.dsize = len(e) + cn.dsize = len(n) + ce.data = malloc(ce.dsize) + cn.data = malloc(cn.dsize) + self.__set_wd_dtb(ce, e) + self.__set_wd_dtb(cn, n) + cwd_rsa.wcrypto_set_rsa_pubkey_params(self.ctx, ce, cn) + + cpdef void wcrypto_set_rsa_prikey_params(self, bytes d, bytes n): + + """ + data copy rather than link + copy data from d, n to self.ctx->prikey->pkey1->d, self.ctx->prikey->pkey1->n + code: + memcpy(c->prikey->d.data, d->data, d->dsize); + memcpy(c->prikey->n.data, n->data, n->dsize); + """ + + cdef cwd.wd_dtb *cd = malloc (sizeof(cwd.wd_dtb)) + cdef cwd.wd_dtb *cn = malloc (sizeof(cwd.wd_dtb)) + cd.dsize = len(d) + cn.dsize = len(n) + cd.data = malloc(cd.dsize) + cn.data = malloc(cn.dsize) + self.__set_wd_dtb(cd, d) + self.__set_wd_dtb(cn, n) + cwd_rsa.wcrypto_set_rsa_prikey_params(self.ctx, cd, cn) + + + cpdef void wcrypto_set_rsa_crt_prikey_params(self, bytes dq, bytes dp, bytes qinv, bytes q, bytes p): + + """ + data copy + copy data from dq, dp, qinv, p, q to self.ctx->prikey->pkey2->* + """ + cdef cwd.wd_dtb *cdq = malloc (sizeof(cwd.wd_dtb)) + cdef cwd.wd_dtb *cdp = malloc (sizeof(cwd.wd_dtb)) + cdef cwd.wd_dtb *cqinv = malloc (sizeof(cwd.wd_dtb)) + cdef cwd.wd_dtb *cq = malloc (sizeof(cwd.wd_dtb)) + cdef cwd.wd_dtb *cp = malloc (sizeof(cwd.wd_dtb)) + cdq.dsize = len(dq) + cdp.dsize = len(dp) + cqinv.dsize = len(qinv) + cq.dsize = len(q) + cp.dsize = len(p) + cdq.data = malloc(cdq.dsize) + cdp.data = malloc(cdp.dsize) + cqinv.data = malloc(cqinv.dsize) + cq.data = malloc(cq.dsize) + cp.data = malloc(cp.dsize) + self.__set_wd_dtb(cdq, dq) + self.__set_wd_dtb(cdp, dp) + self.__set_wd_dtb(cqinv, qinv) + self.__set_wd_dtb(cq, q) + self.__set_wd_dtb(cp, p) + cwd_rsa.wcrypto_set_rsa_crt_prikey_params(self.ctx, cdq, cdp, cqinv, cq, cp) + + # get d, n (wd_dtb) from rsa_prikey->pkey1 + cpdef get_prikey(self): + """ + return d, n in bytes format + """ + # struct.unsigned char -> wd_dtb + cwd_rsa.wcrypto_get_rsa_prikey_params(self.prik, &self.d, &self.n) + d = self.__get_wd_dtb(self.d) + n = self.__get_wd_dtb(self.n) + return d, n + + + # get dp, dq,q qinv ... from rsa_prik->pkey2 + cpdef get_crt_prikey(self): + """ + return dp, dq, qinv, q, p in bytes format + """ + if not self.wcrypto_rsa_is_crt(): + raise ValueError("not crt mode") + cwd_rsa.wcrypto_get_rsa_crt_prikey_params(self.prik, &self.dq, &self.dp, &self.qinv, &self.q, &self.p) + dp = self.__get_wd_dtb(self.dp) + dq = self.__get_wd_dtb(self.dq) + qinv = self.__get_wd_dtb(self.qinv) + q = self.__get_wd_dtb(self.q) + p = self.__get_wd_dtb(self.p) + return dp, dq, qinv, q, p + + + cpdef void wcrypto_new_kg_in(self, e: bytes, p: bytes, q: bytes): + ''' + 用现有的 e, p, q 构建一个 kg_in 结构体 + 肯定是不能直接返回结构体指针的,那这样看也是作为一个成员出现比较合适 + 这里有一个要注意的点是要给 wd_dtb 的 data 指针分配内存 + ''' + cdef cwd.wd_dtb *ce = malloc(sizeof(cwd.wd_dtb)) + ce.dsize = len(e) + ce.data = malloc(ce.dsize) + if ce.data == NULL: + raise MemoryError("malloc failed") + self.__set_wd_dtb(ce, e) + + cdef cwd.wd_dtb *cp = malloc(sizeof(cwd.wd_dtb)) + cp.dsize = len(p) + cp.data = malloc(cp.dsize) + if cp.data == NULL: + raise MemoryError("malloc failed") + self.__set_wd_dtb(cp, p) + + cdef cwd.wd_dtb *cq = malloc(sizeof(cwd.wd_dtb)) + cq.dsize = len(q) + cq.data = malloc(cq.dsize) + if cq.data == NULL: + raise MemoryError("malloc failed") + self.__set_wd_dtb(cq, q) + + # print(self.ctx==NULL, ce==NULL, cp==NULL, cq==NULL) + + self.kg_in = cwd_rsa.wcrypto_new_kg_in(self.ctx, ce, cp, cq) + free(ce.data) + free(ce) + free(cp.data) + free(cp) + free(cq.data) + free(cq) + + + cdef void wcrypto_del_kg_in(self): + cwd_rsa.wcrypto_del_kg_in(self.ctx, self.kg_in) + + cpdef void wcrypto_new_kg_out(self): + """ + create a kg_out struct contains: + d, n + dp, dq, qinv (if setup.crt is True) + return pointer of this struct + """ + self.kg_out = cwd_rsa.wcrypto_new_kg_out(self.ctx) + + cdef void wcrypto_del_kg_out(self): + cwd_rsa.wcrypto_del_kg_out(self.ctx, self.kg_out) + + cpdef void wcrypto_get_rsa_kg_out_params(self): + """ + get d, n from kg_out + """ + cwd_rsa.wcrypto_get_rsa_kg_out_params(self.kg_out, self.d, self.n) + + cdef void wcrypto_get_rsa_kg_out_crt_params(self): + """ + get dp, dq, qinv from kg_out + """ + cwd_rsa.wcrypto_get_rsa_kg_out_crt_params(self.kg_out, self.qinv, self.dq, self.dp) + + cpdef void tag_setup(self, int cnt, int thread_id): + + """setup a fixed tag + cnt: user set (0?) + thread_id: acquired from python + """ + + if self.async_mode == 1: + self.tag = malloc(sizeof(wcrypto_rsa_tag)) + self.tag.ctx = self.ctx + self.tag.cnt = cnt + self.tag.thread_id = thread_id + else: + print("sync mode no need to setup tag") + + cpdef int wcrypto_do_rsa(self): + return cwd_rsa.wcrypto_do_rsa(self.ctx, self.opdata, NULL) + + cpdef int wcrypto_rsa_poll(self, num:int): + if num < 1: + raise ValueError("num must be greater than 0") + if self.async_mode == 0: + raise ValueError("sync mode not support poll") + return cwd_rsa.wcrypto_rsa_poll(self.queue, num) + + cdef void wcrypto_del_rsa_ctx(self): + cwd_rsa.wcrypto_del_rsa_ctx(self.ctx) + + cpdef get_kg_out(self): + self.wcrypto_get_rsa_kg_out_params() + d = self.__get_wd_dtb(self.d) + n = self.__get_wd_dtb(self.n) + return d, n + + cpdef get_kg_out_crt(self): + # cwd_rsa.wcrypto_get_rsa_kg_out_crt_params(self.kg_out, self.qinv, self.dq, self.dp) + self.wcrypto_get_rsa_kg_out_crt_params() + dq = self.__get_wd_dtb(self.dq) + dp = self.__get_wd_dtb(self.dp) + qinv = self.__get_wd_dtb(self.qinv) + return dq, dp, qinv + + cpdef get_opdata_out(self): + # memcpy self.opdata.out to a u8 array + cdef char *out = malloc(self.opdata.out_bytes) + memcpy(out, self.opdata.out, self.opdata.out_bytes) + return bytes(out[:self.opdata.out_bytes]) + + cdef __set_wd_dtb(self, cwd.wd_dtb *dtb, data: bytes): + dtb.dsize = len(data) + # print(dtb.dsize) + for i in range(dtb.dsize): + dtb.data[i] = data[i] + + cdef __get_wd_dtb(self, cwd.wd_dtb *dtb): + return bytes(dtb.data[:dtb.dsize]) + + + def __dealloc__(self): + # free queue + if self.queue is not NULL: + cwd.wd_release_queue(self.queue) + # self.wcrypto_del_kg_in() + # self.wcrypto_del_kg_out() + # self.wcrypto_del_rsa_ctx() diff --git a/pyuadk/setup.py b/pyuadk/setup.py new file mode 100644 index 0000000..d9d3676 --- /dev/null +++ b/pyuadk/setup.py @@ -0,0 +1,88 @@ +from setuptools import setup, Extension +from Cython.Build import cythonize + +extensions = [ + + Extension("pyuadk.pywd", + ["pyuadk/pywd.pyx", + "uadk/v1/wd_rsa.c", + "uadk/v1/wd_cipher.c", + "uadk/v1/wd.c", + "uadk/v1/wd_util.c", + "uadk/v1/wd_adapter.c", + "uadk/v1/wd_sgl.c", + "uadk/v1/wd_bmm.c", + "uadk/v1/wd_ecc.c", + "uadk/v1/drv/dummy_drv.c", + "uadk/v1/drv/hisi_qm_udrv.c", + "uadk/v1/drv/hisi_rng_udrv.c", + "uadk/v1/drv/hisi_hpre_udrv.c", + "uadk/v1/drv/hisi_sec_udrv.c", + "uadk/v1/drv/hisi_zip_udrv.c" + ], + include_dirs=["uadk/"]), + + Extension("pyuadk.pywd_cipher", + ["pyuadk/pywd_cipher.pyx", + "uadk/v1/wd_rsa.c", + "uadk/v1/wd_cipher.c", + "uadk/v1/wd.c", + "uadk/v1/wd_util.c", + "uadk/v1/wd_adapter.c", + "uadk/v1/wd_sgl.c", + "uadk/v1/wd_bmm.c", + "uadk/v1/wd_ecc.c", + "uadk/v1/drv/dummy_drv.c", + "uadk/v1/drv/hisi_qm_udrv.c", + "uadk/v1/drv/hisi_rng_udrv.c", + "uadk/v1/drv/hisi_hpre_udrv.c", + "uadk/v1/drv/hisi_sec_udrv.c", + "uadk/v1/drv/hisi_zip_udrv.c" + ], + include_dirs=["uadk/"]), + Extension("pyuadk.pywd_digest", + ["pyuadk/pywd_digest.pyx", + "uadk/v1/wd_digest.c", + "uadk/v1/wd_rsa.c", + "uadk/v1/wd_cipher.c", + "uadk/v1/wd.c", + "uadk/v1/wd_util.c", + "uadk/v1/wd_adapter.c", + "uadk/v1/wd_sgl.c", + "uadk/v1/wd_bmm.c", + "uadk/v1/wd_ecc.c", + "uadk/v1/drv/dummy_drv.c", + "uadk/v1/drv/hisi_qm_udrv.c", + "uadk/v1/drv/hisi_rng_udrv.c", + "uadk/v1/drv/hisi_hpre_udrv.c", + "uadk/v1/drv/hisi_sec_udrv.c", + "uadk/v1/drv/hisi_zip_udrv.c" + ], + include_dirs=["uadk/"]), + Extension("pyuadk.pywd_rsa", + [ + "pyuadk/pywd_rsa.pyx", + "uadk/v1/wd_rsa.c", + "uadk/v1/wd.c", + "uadk/v1/wd_util.c", + "uadk/v1/wd_adapter.c", + "uadk/v1/wd_sgl.c", + "uadk/v1/wd_bmm.c", + "uadk/v1/wd_ecc.c", + "uadk/v1/drv/dummy_drv.c", + "uadk/v1/drv/hisi_qm_udrv.c", + "uadk/v1/drv/hisi_rng_udrv.c", + "uadk/v1/drv/hisi_hpre_udrv.c", + "uadk/v1/drv/hisi_sec_udrv.c", + "uadk/v1/drv/hisi_zip_udrv.c" + ], + include_dirs=["uadk/"]) + # 添加其他Cython文件的Extension对象 +] + +setup( + name="pyuadk", + ext_modules=cythonize(extensions), + + # package_data={'pyuadk': ['build/lib.linux-aarch64-3.9/pywd_cipher.cpython-39-aarch64-linux-gnu.so']}, +) diff --git a/readme_en.md b/readme_en.md new file mode 100644 index 0000000..a964f97 --- /dev/null +++ b/readme_en.md @@ -0,0 +1,37 @@ +# pyuadk +This project is a Python wrapper for the cryptographic acceleration library [UADK](https://gitee.com/openeuler/uadk), implemented using Cython. It currently supports: + +1. Encryption and decryption, as well as common modes of operation, for AES and SM4. +2. Hashing operations and HMAC operations for SM3. +3. Key generation, signing, and verification for RSA in both regular and CRT modes. + +## Compilation +```shell +git clone --recurse-submodules https://gitee.com/openeuler/pyuadk.git +pip3 install -r requirements.txt +python3 pyuadk/setup.py build_ext --inplace +``` +## Usage +```python +from pyuadk import pywd_cipher + +cipher = pywd_cipher.Cipher() +cipher.request_queue() +cipher.pool_setup(1024*8, 128, 128) + +key = bytes([0x01]*16) +iv = bytes([0x02]*16) +pt = bytes([0x03]*16) + +alg = pywd_cipher.CIPHER_ALG.AES +mode = pywd_cipher.CIPHER_MODE.CBC +cipher.ctx_setup(alg, mode) +cipher.create_cipher_ctx() + +cipher.wcrypto_set_cipher_key(self.key, len(self.key)) +cipher.set_opdata(self.iv, pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + +ret = self.cipher.wcrypto_do_cipher() +if ret == 0: + ct = self.cipher.get_ct() +``` diff --git a/readme_zh.md b/readme_zh.md new file mode 100644 index 0000000..de2cdd2 --- /dev/null +++ b/readme_zh.md @@ -0,0 +1,37 @@ +# pyuadk +本项目是对密码加速库 [UADK](https://gitee.com/openeuler/uadk) 的 python 封装,使用 Cython 实现,目前支持: +1. AES 和 SM4 的加解密及常见工作模式 +2. SM3 的哈希操作和 HMAC 操作 +3. RSA 常规模式和 CRT 模式下的密钥生成、签名和验签 + +## 编译 +```shell +git clone --recurse-submodules https://gitee.com/openeuler/pyuadk.git +pip3 install -r requirements.txt +python3 pyuadk/setup.py build_ext --inplace +``` + +## 使用 +```python +from pyuadk import pywd_cipher + +cipher = pywd_cipher.Cipher() +cipher.request_queue() +cipher.pool_setup(1024*8, 128, 128) + +key = bytes([0x01]*16) +iv = bytes([0x02]*16) +pt = bytes([0x03]*16) + +alg = pywd_cipher.CIPHER_ALG.AES +mode = pywd_cipher.CIPHER_MODE.CBC +cipher.ctx_setup(alg, mode) +cipher.create_cipher_ctx() + +cipher.wcrypto_set_cipher_key(self.key, len(self.key)) +cipher.set_opdata(self.iv, pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + +ret = self.cipher.wcrypto_do_cipher() +if ret == 0: + ct = self.cipher.get_ct() +``` diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..60b66a1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +setuptools~=65.5.1 +Cython~=3.0.0 diff --git a/test.py b/test.py new file mode 100644 index 0000000..9d32468 --- /dev/null +++ b/test.py @@ -0,0 +1,325 @@ +from pyuadk import pywd_cipher, pywd_digest, pywd_rsa +# from pyuadk.pywd_rsa import RSA_OP_TYPE +import unittest +from Crypto.Cipher import AES +from Crypto.PublicKey import RSA +import time +import struct, os +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT +from gmssl.sm3 import sm3_hash +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import padding + +from cryptography.hazmat.primitives.asymmetric import rsa + +class TestPyWdCipherSync(unittest.TestCase): + + def __init__(self, methodName='runTest'): + super().__init__(methodName) + self.cipher = pywd_cipher.Cipher() + self.cipher.request_queue() + self.cipher.pool_setup(1024*8, 128, 128) + self.key = bytes([0x01]*16) + self.iv = bytes([0x02]*16) + self.pt = bytes([0x03]*16) + + + def test_cipher_aes_cbc_sync(self): + # cipher = pywd_cipher.Cipher() + # cipher.request_queue() + + + alg = pywd_cipher.CIPHER_ALG.AES + mode = pywd_cipher.CIPHER_MODE.CBC + self.cipher.ctx_setup(alg, mode) + self.cipher.create_cipher_ctx() + + self.cipher.wcrypto_set_cipher_key(self.key, len(self.key)) + + self.cipher.set_opdata(self.iv, pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + + ret = self.cipher.wcrypto_do_cipher() + cth = self.cipher.get_ct() + self.assertEqual(ret, 0) + + aes_ecb = AES.new(self.key, AES.MODE_CBC, self.iv) + cts = aes_ecb.encrypt(self.pt) + + self.assertEqual(cth[0], cts[0]) + + self.cipher.set_opdata(self.iv, pywd_cipher.CIPHER_OP_TYPE.DECRYPT, cth) + ret = self.cipher.wcrypto_do_cipher() + pth = self.cipher.get_ct() + self.assertEqual(ret, 0) + + self.assertEqual(pth[0], self.pt[0]) + + print("\naes cbc test pass") + + def test_cipher_aes_ecb(self): + + alg = pywd_cipher.CIPHER_ALG.AES + mode = pywd_cipher.CIPHER_MODE.ECB + self.cipher.ctx_setup(alg, mode) + self.cipher.create_cipher_ctx() + + + self.cipher.wcrypto_set_cipher_key(self.key, len(self.key)) + self.cipher.set_opdata(bytes([]), pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + + + ret = self.cipher.wcrypto_do_cipher() + cth = self.cipher.get_ct() + self.assertEqual(ret, 0) + + aes_ecb = AES.new(self.key, AES.MODE_ECB) + cts = aes_ecb.encrypt(self.pt) + + self.assertEqual(cth[:-1], cts) + # print("cth = ", ct[:16]) + self.cipher.set_opdata(bytes([]), pywd_cipher.CIPHER_OP_TYPE.DECRYPT, cth[:-1]) + ret = self.cipher.wcrypto_do_cipher() + pth = self.cipher.get_ct() + self.assertEqual(ret, 0) + self.assertEqual(pth[0], self.pt[0]) + + + print("\naes ecb test pass") + + + def test_cipher_sm4_ecb(self): + + alg = pywd_cipher.CIPHER_ALG.SM4 + mode = pywd_cipher.CIPHER_MODE.ECB + self.cipher.ctx_setup(alg, mode) + self.cipher.create_cipher_ctx() + + + self.cipher.wcrypto_set_cipher_key(self.key, len(self.key)) + self.cipher.set_opdata(bytes([]), pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + + + ret = self.cipher.wcrypto_do_cipher() + cth = self.cipher.get_ct() + self.assertEqual(ret, 0) + + + sm4 = CryptSM4() + sm4.set_key(self.key, SM4_ENCRYPT) + cts = sm4.crypt_ecb(self.pt) + + + self.assertEqual(cth[:16], cts[:16]) + + self.cipher.set_opdata(bytes([]), pywd_cipher.CIPHER_OP_TYPE.DECRYPT, cth[:-1]) + ret = self.cipher.wcrypto_do_cipher() + pth = self.cipher.get_ct() + self.assertEqual(ret, 0) + self.assertEqual(pth[0], self.pt[0]) + + print("\nsm4 ecb test pass") + + def test_cipher_sm4_cbc(self): + + alg = pywd_cipher.CIPHER_ALG.SM4 + mode = pywd_cipher.CIPHER_MODE.CBC + self.cipher.ctx_setup(alg, mode) + self.cipher.create_cipher_ctx() + + + self.cipher.wcrypto_set_cipher_key(self.key, len(self.key)) + self.cipher.set_opdata(self.iv, pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + + + ret = self.cipher.wcrypto_do_cipher() + cth = self.cipher.get_ct() + self.assertEqual(ret, 0) + + sm4 = CryptSM4() + sm4.set_key(self.key, SM4_ENCRYPT) + cts = sm4.crypt_cbc(self.iv, self.pt) + + self.assertEqual(cth[0], cts[0]) + + self.cipher.set_opdata(self.iv, pywd_cipher.CIPHER_OP_TYPE.DECRYPT, cth) + ret = self.cipher.wcrypto_do_cipher() + pth = self.cipher.get_ct() + self.assertEqual(ret, 0) + self.assertEqual(pth[0], self.pt[0]) + + print("\nsm4 cbc test pass") + + + +class TestPyWdDigest(unittest.TestCase): + + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.digest = pywd_digest.Digest() + self.digest.request_queue() + self.digest.pool_setup(1024*8, 128, 128) + + self.pt = bytes([0x01]*10) + self.iv = bytes([0x02]*16) + self.key = bytes([0x03]*16) + + self.alg = pywd_digest.DIGEST_ALG.SM3 + + + + def test_digest_sm3_normal(self): + + mode = pywd_digest.DIGEST_MODE.NORMAL + self.digest.ctx_setup(self.alg, mode) + self.digest.create_digest_ctx() + self.digest.set_opdata(self.pt, 16) + ret = self.digest.wcrypto_do_digest() + self.assertEqual(ret, 0) + + + digest_h = self.digest.get_digest() + digest_s = sm3_hash(list(self.pt)) + + # print(digest_h) + + # self.assertEqual(digest_h[0], int(digest_s[:2], base=16)) + + print("\nsm3 normal test pass") + + def test_digest_sm3_hmac(self): + + mode = pywd_digest.DIGEST_MODE.HMAC + self.digest.ctx_setup(self.alg, mode) + self.digest.create_digest_ctx() + self.digest.wcrypto_set_digest_key(self.key, len(self.key)) + self.digest.set_opdata(self.pt, 16) + ret = self.digest.wcrypto_do_digest() + self.assertEqual(ret, 0) + + digest = self.digest.get_digest() + # print(digest) + + print("\nsm3 hmac test pass") + +class TestPyWdRSA(unittest.TestCase): + + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.rsa = pywd_rsa.RSA() + self.rsa.request_queue() + self.rsa.pool_setup(64, 2048) + + self.msg = b'Hello World!' + self.sig = None + + # use cryptography lib + self.private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + public_key = self.private_key.public_key() + self.e = bytes.fromhex(f"{public_key.public_numbers().e:#0{514}x}"[2:]) + self.n = bytes.fromhex(f"{public_key.public_numbers().n:#0{514}x}"[2:]) + self.d = bytes.fromhex(f"{self.private_key.private_numbers().d:#0{514}x}"[2:]) + self.p = bytes.fromhex(f"{self.private_key.private_numbers().p:#0{258}x}"[2:]) + self.q = bytes.fromhex(f"{self.private_key.private_numbers().q:#0{258}x}"[2:]) + self.dp = bytes.fromhex(f"{self.private_key.private_numbers().dmp1:#0{258}x}"[2:]) + self.dq = bytes.fromhex(f"{self.private_key.private_numbers().dmq1:#0{258}x}"[2:]) + self.qinv = bytes.fromhex(f"{self.private_key.private_numbers().iqmp:#0{258}x}"[2:]) + + + def test_rsa_genkey_common(self): + + self.rsa.ctx_setup(0) + self.rsa.create_rsa_ctx() + + self.rsa.wcrypto_new_kg_in(self.e, self.p, self.q) + self.rsa.wcrypto_new_kg_out() + + self.rsa.set_opdata(pywd_rsa.RSA_OP_TYPE.GENKEY) + ret = self.rsa.wcrypto_do_rsa() + self.assertEqual(ret, 0) + + d, n = self.rsa.get_kg_out() + # print(d.hex(), n.hex()) + self.assertEqual(int.from_bytes(d, byteorder="big"), self.private_key.private_numbers().d) + self.assertEqual(int.from_bytes(n, byteorder="big"), self.private_key.public_key().public_numbers().n) + print("\nrsa common genkey test pass") + + + def test_rsa_genkey_crt(self): + + self.rsa.ctx_setup(1) + self.rsa.create_rsa_ctx() + + self.rsa.wcrypto_new_kg_in(self.e, self.p, self.q) + self.rsa.wcrypto_new_kg_out() + + self.rsa.set_opdata(pywd_rsa.RSA_OP_TYPE.GENKEY) + + ret = self.rsa.wcrypto_do_rsa() + + self.assertEqual(ret, 0) + dq, dp, qinv = self.rsa.get_kg_out_crt() + + self.assertEqual(int.from_bytes(dp, byteorder="big"), self.private_key.private_numbers().dmp1) + self.assertEqual(int.from_bytes(dq, byteorder="big"), self.private_key.private_numbers().dmq1) + self.assertEqual(int.from_bytes(qinv, byteorder="big"), self.private_key.private_numbers().iqmp) + + print("\nrsa ctr genkey test pass") + + def test_rsa_sign_common(self): + + self.rsa.ctx_setup(0) + self.rsa.create_rsa_ctx() + + self.rsa.wcrypto_set_rsa_prikey_params(self.d, self.n) + + self.rsa.set_opdata(pywd_rsa.RSA_OP_TYPE.SIGN, self.d) + ret = self.rsa.wcrypto_do_rsa() + self.assertEqual(ret, 0) + + self.sig = self.rsa.get_opdata_out() + + print("\nrsa sign common test pass") + + + def test_rsa_sign_crt(self): + + self.rsa.ctx_setup(1) + self.rsa.create_rsa_ctx() + + self.rsa.wcrypto_set_rsa_crt_prikey_params(self.dq, self.dp, self.qinv, self.q, self.p) + + self.rsa.set_opdata(pywd_rsa.RSA_OP_TYPE.SIGN, self.d) + ret = self.rsa.wcrypto_do_rsa() + self.assertEqual(ret, 0) + + self.sig = self.rsa.get_opdata_out() + + print("\nrsa sign crt test pass") + + def test_rsa_verify_common_and_crt(self): + self.rsa.ctx_setup(0) + self.rsa.create_rsa_ctx() + + self.rsa.wcrypto_set_rsa_pubkey_params(self.e, self.n) + sig = self.private_key.sign( + self.msg, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() + ) + + self.rsa.set_opdata(pywd_rsa.RSA_OP_TYPE.VERIFY, data=sig) + ret = self.rsa.wcrypto_do_rsa() + self.assertEqual(ret, 0) + + ver = self.rsa.get_opdata_out() + print("\nrsa verify common and crt test pass") + + + +if __name__ == '__main__': + unittest.main() + \ No newline at end of file diff --git a/test_aysnc.py b/test_aysnc.py new file mode 100644 index 0000000..0df0130 --- /dev/null +++ b/test_aysnc.py @@ -0,0 +1,156 @@ +import unittest +import ctypes +from pyuadk import pywd_cipher, pywd_digest, pywd_rsa +from Crypto.Cipher import AES +import threading +from cryptography.hazmat.primitives.asymmetric import rsa + + +class test_sec_pthread_dt(ctypes.Structure): + _fields_ = [ + ("cpu_id", ctypes.c_int), + ("thread_num", ctypes.c_int), + ("pool", ctypes.POINTER(ctypes.c_void_p)), + ("q", ctypes.POINTER(ctypes.c_void_p)), + ("send_task_num", ctypes.c_uint32), + ("recv_task_num", ctypes.c_uint32), + ] + + +class Cipher_Async_Tag(ctypes.Structure): + _fields_ = [ + ("ctx", ctypes.POINTER(ctypes.c_void_p)), + ("thread_id", ctypes.c_int), + ("cnt", ctypes.c_int), + ("thread_info", ctypes.POINTER(test_sec_pthread_dt)), + ] + + +def cipher_cb(message, cipher_tag): + tag = ctypes.cast(cipher_tag, ctypes.POINTER(Cipher_Async_Tag)).contents + thread_info = ctypes.cast( + tag.thread_info, ctypes.POINTER(test_sec_pthread_dt) + ).contents + thread_info.recv_task_num.contents.value += 1 + print("a") + + +cipher_cb_ptr = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) + + +@staticmethod +def test_cb(a): + print("test cb ", a) + + +class TestPyWdCipherAsync(unittest.TestCase): + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.cipher = pywd_cipher.Cipher(async_mode=1) + self.cipher.request_queue() + self.cipher.pool_setup(1024 * 8, 128, 128) + self.key = bytes([0x01] * 16) + self.iv = bytes([0x02] * 16) + self.pt = bytes([0x03] * 16) + + def test_aes_ecb_async(self): + alg = pywd_cipher.CIPHER_ALG.AES + mode = pywd_cipher.CIPHER_MODE.ECB + + self.cipher.ctx_setup(alg, mode) + self.cipher.create_cipher_ctx() + + self.cipher.wcrypto_set_cipher_key(self.key, len(self.key)) + self.cipher.set_opdata(bytes([]), pywd_cipher.CIPHER_OP_TYPE.ENCRYPT, self.pt) + ret = -22 + count = 0 + self.cipher.tag_setup(0, 27694) + while ret != 0 and count < 2: + ret = self.cipher.wcrypto_do_cipher() + count += 1 + + self.cipher.wcrypto_cipher_poll(2) + self.assertEqual(ret, 0) + # print(count) + + cth = self.cipher.get_ct() + aes_ecb = AES.new(self.key, AES.MODE_ECB) + cts = aes_ecb.encrypt(self.pt) + self.assertEqual(cth[0], cts[0]) + + print("\naes ecb async test pass") + +class TestPyWdDigestAysnc(unittest.TestCase): + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.digest = pywd_digest.Digest(async_mode=1) + self.digest.request_queue() + self.digest.pool_setup(1024 * 8, 128, 128) + self.data = bytes([0x01] * 16) + + def test_digest_sm3_async(self): + alg = pywd_digest.DIGEST_ALG.SM3 + mode = pywd_digest.DIGEST_MODE.NORMAL + self.digest.ctx_setup(alg, mode) + self.digest.create_digest_ctx() + self.digest.set_opdata(self.data, 16) + ret = -22 + count = 0 + self.digest.tag_setup(2, 27694) + while ret != 0 and count < 2: + ret = self.digest.wcrypto_do_digest() + count += 1 + + self.digest.wcrypto_digest_poll(2) + self.assertEqual(ret, 0) + # print(count) + + digest = self.digest.get_digest() + # print(digest) + print("\nsm3 normal async test pass") + +class TestPyWdRSAAsync(unittest.TestCase): + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.rsa = pywd_rsa.RSA(async_mode=1) + self.rsa.request_queue() + self.rsa.pool_setup(64, 2048) + + self.private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + public_key = self.private_key.public_key() + self.e = bytes.fromhex(f"{public_key.public_numbers().e:#0{514}x}"[2:]) + self.n = bytes.fromhex(f"{public_key.public_numbers().n:#0{514}x}"[2:]) + self.d = bytes.fromhex(f"{self.private_key.private_numbers().d:#0{514}x}"[2:]) + self.p = bytes.fromhex(f"{self.private_key.private_numbers().p:#0{258}x}"[2:]) + self.q = bytes.fromhex(f"{self.private_key.private_numbers().q:#0{258}x}"[2:]) + self.dp = bytes.fromhex(f"{self.private_key.private_numbers().dmp1:#0{258}x}"[2:]) + self.dq = bytes.fromhex(f"{self.private_key.private_numbers().dmq1:#0{258}x}"[2:]) + self.qinv = bytes.fromhex(f"{self.private_key.private_numbers().iqmp:#0{258}x}"[2:]) + + + def test_rsa_genkey_common_async(self): + + self.rsa.ctx_setup(0) + self.rsa.create_rsa_ctx() + + self.rsa.wcrypto_new_kg_in(self.e, self.p, self.q) + self.rsa.wcrypto_new_kg_out() + + self.rsa.set_opdata(pywd_rsa.RSA_OP_TYPE.GENKEY) + ret = -22 + count = 0 + self.rsa.tag_setup(2, 27694) + while ret != 0 and count < 2: + ret = self.rsa.wcrypto_do_rsa() + count += 1 + print(count) + self.assertEqual(ret, 0) + # self.rsa.wcrypto_rsa_poll(2) + d, n = self.rsa.get_kg_out() + self.assertEqual(int.from_bytes(d, byteorder="big"), self.private_key.private_numbers().d) + self.assertEqual(int.from_bytes(n, byteorder="big"), self.private_key.public_key().public_numbers().n) + print("\nrsa common genkey async test pass") + + +if __name__ == "__main__": + unittest.main() -- Gitee