阅读本篇文章需要基础知识:
1.C/C++
2.systemverilog
3.dpi
4.aes basic knowledge
OpenSSL 是一个开源软件库和命令行工具套件,实现了 SSL/TLS 协议及多种加密算法,用于保障网络通信的机密性和完整性。
其核心功能模块包括:
1.密码算法库:支持对称加密(如 AES)、非对称加密(如 RSA)、散列算法(如 SHA)等;
2.SSL/TLS 协议库:提供安全通信协议实现;
3.应用程序工具集:包含证书生成、密钥管理、加密测试等实用命令。
为什么选择 OpenSSL?
开源与广泛兼容 ,安全协议支持全面 ,覆盖 SSLv2/3、TLS 1.0-1.3 等协议版本,功能集成度高,行业标准地位。
作为互联网安全基础设施的核心组件,被 Apache、Nginx 等主流服务器及开发框架广泛依赖。
Openssl库支持加解密比较繁多,这里以AES为例子,其他加解密算法依次类推。
阅读时长: 15min
1.openssl库下载及安装
官方地址:
https://openssl-library.org/source
通过上面path下载其tar包,解压缩后就如下(不同版本存在差异)
安装的话和其他类似 make install 可以参考其说明 按照说明一步步安装。
标准安装流程:
$ ./config $ make $ make test $ make install
也可以定制安装 如安装到指定位置:
$ ./config --prefix=/usr/local --openssldir=/usr/local/openssl
可以通过命令查看对应版本信息:
openssl version -a
其他细节可以参考官方说明,这里给出一个使用的demo场景 方便大家理解:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <openssl/aes.h> main(){ // Encryption key: 0x2b7e151628aed2a6abf7158809cf4f3c // Initial Vector: 0x000102030405060708090a0b0c0d0e0f // Test vector: 0x6bc1bee22e409f96e93d7e117393172a // 0xae2d8a571e03ac9c9eb76fac45af8e51 // 0x30c81c46a35ce411e5fbc1191a0a52ef // Cipher text: 0x7649abac8119b246cee98e9b12e9197d // 0x5086cb9b507219ee95db113a917678b2 // 0x73bed6b8e3c1743b7116e69e22229516 unsigned char MBlock[16]={0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a}; unsigned char MBlock2[16]; unsigned char CBlock[16]; unsigned char iv[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; unsigned char Key[16]={0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}; AES_KEY AESkey; int i; AES_set_encrypt_key((const unsigned char *) Key,128,&AESkey); AES_cbc_encrypt((const unsigned char *) MBlock,CBlock,16,(const AES_KEY *) &AESkey,iv, AES_ENCRYPT ); for(i=0;i<16;i++) { printf(" %x sizeof:%d \n",CBlock[i],sizeof(CBlock[i])); } printf("\n################\n"); }
对c文件预先单独编译,可以验证库的加解密功能:
gcc aes_xxx.c -D_PROG -I lib -L lib -lcrypto -lssl -lm -o aes.o
2 .dpi函数处理
为了方便集成到验证环境,我们需要额外写一个wrapper文件,因为openssl库里的函数需要多个配合才能完成一次加解密,所以对这个过程我们进行整体封装,这里一个示例如下:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <openssl/aes.h> #include "vcsuser.h" #include "svdpi.h" #ifdef _PROG main(){ unsigned char MBlock[16]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff}; unsigned char CBlock[16]; unsigned char Key[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; #else void aes_key_128( const svOpenArrayHandle input_message_h_before, const svOpenArrayHandle user_key_h, const svOpenArrayHandle user_iv_h ) { #endif int *plain_text; int *keys; int *iv; svBitVec32 input_message_before; /********************************************/ // unsigned char iv[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; /********************************************/ AES_KEY AESkey; int i; unsigned char MBlock[16]; unsigned char Key[24]; unsigned char IVs[16]; unsigned char CBlock[16]; FILE *fpout; FILE *fpplain; fpout = fopen("../rm/ecb_128.txt","w"); fpplain = fopen("../rm/plain.txt","w"); plain_text=svGetArrayPtr(input_message_h_before); keys=svGetArrayPtr(user_key_h); iv=svGetArrayPtr(user_iv_h); for(i=0;i<16;i++){ MBlock[i]=0xff & plain_text[i]; IVs[i]=0xff & iv[i]; printf("MBlock:%x, Plain_test:%x sizeof:%d \n ",MBlock[i],plain_text[i],sizeof(MBlock[i])); } for(i=0;i<24;i++){ Key[i]=0xff & keys[i]; printf("Key:%x,keys: %02x \n ",Key[i],keys[i]); } /************************ For Debug *********************/ for(i=0;i<16;i++) { fprintf(fpplain,"M:%0x P:%0x iv:%0x->%0x \n",MBlock[i],plain_text[i],iv[i],IVs[i]); } AES_set_decrypt_key((const unsigned char *) Key,192,&AESkey); AES_cbc_encrypt((const unsigned char *) MBlock,CBlock,16,(const AES_KEY *) &AESkey,IVs, AES_DECRYPT ); for(i=0;i<16;i++) { printf(" %x sizeof:%d \n",CBlock[i],sizeof(CBlock[i])); fprintf(fpout,"%0x\n",CBlock[i]); } printf("\n################\n"); fclose(fpout); fclose(fpplain); }
上面文件可以作为dpi使用,也可以单独使用 用于显示处理一些固定数据。
3.接口处理
C file的头部文件依赖需要都包含进来,否则会报错,因为sv的数据类型和c不一样,跨语言处理需要这些依赖库!
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <openssl/aes.h> #include "vcsuser.h" #include "svdpi.h"
通常systemverilog和c的程序参数不能一一映射,所以在接口转换过程中做了一些尝试,下面给出和上面我们写的wrapper对应的接口信息
//import "DPI-C" function void encode(); // <FOR ECB USE> import "DPI-C" function bit aes_key_128(input bit[31:0] input_message_h_before[],input bit[31:0] user_key_h[]); import "DPI-C" function bit aes_key_128(input bit[31:0] input_message_h_before[],input bit[31:0] user_key_h[],input bit[31:0] user_iv_h[]);
下面是我们sv里调用的一个用法可以参考:
aes_key_128(cfg.input_message_h_before,cfg.user_key_h,cfg.user_iv_h);
配合cfg来使用,cfg部分信息如下,我们也可以利用uvm特性在post_randomize修改,比如 有的会牵涉到大小端等 这里可以修改
class aes_ctrl_config extends uvm_object; apb_config apb_cfg; //rand bit [31:0] IN_value[]; rand bit [31:0] user_key_h[32]; rand bit [31:0] input_message_h_before[16]; rand bit [31:0] input_message_h_before_2[16]; rand bit [31:0] input_message_h_before_3[16]; rand bit [31:0] user_iv_h[16]; rand bit [8:0] AES_CTRL_STR; bit AES_STA_STR; bit [31:0] AES_KEY_REG1; bit [31:0] AES_KEY_REG2; ... `uvm_object_utils_begin(aes_ctrl_config) `uvm_field_object(apb_cfg, UVM_DEFAULT) `uvm_field_sarray_int(user_key_h, UVM_DEFAULT) `uvm_field_sarray_int(user_iv_h, UVM_DEFAULT) `uvm_field_sarray_int(input_message_h_before, UVM_DEFAULT) `uvm_field_sarray_int(input_message_h_before_2, UVM_DEFAULT) `uvm_field_sarray_int(input_message_h_before_3, UVM_DEFAULT) //`uvm_field_int(code_num, UVM_DEFAULT) `uvm_object_utils_end function new (string name = "aes_ctrl_config"); super.new(name); apb_cfg = apb_config::type_id::create("apb_cfg"); endfunction : new function void post_randomize(); AES_IV_REG1={user_iv_h[3][7:0] ,user_iv_h[2][7:0] ,user_iv_h[1][7:0] ,user_iv_h[0][7:0]}; AES_IV_REG2={user_iv_h[7][7:0] ,user_iv_h[6][7:0] ,user_iv_h[5][7:0] ,user_iv_h[4][7:0]}; .... endfunction //post_randomize endclass : aes_ctrl_config
4.编译参数
以上工作做完之后coding部分基本结束,但是还不能完全work,最最重要的部分是让EDA工具找到他们。
在本地文件都ready后,仿真还是不能启动的,为了能够link到openssl的库我们还需要EDA工具上指定link信息。这里以vcs工具为例子,
需要加入命令:-CFLAGS -lcrypto -lssl
功能:
-CFLAGS 用于向底层 C 编译器传递参数,-lcrypto 和 -lssl 表示链接 OpenSSL 加密库。这里完整cmd:
vcs -sverilog +nospecify -CFLAGS -lcrypto -lssl -debug_all -timescale='1ns/1ps' ....
其他加解密处理方式都比较类似可以参考本篇文章实现。