阅读本篇文章需要基础知识:
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' ....
其他加解密处理方式都比较类似可以参考本篇文章实现。
