验证环境中部署OpenSSL库

 

阅读本篇文章需要基础知识:
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' ....

其他加解密处理方式都比较类似可以参考本篇文章实现。


已发布

分类

,

来自

标签: