OpenSSL EVP詳解

OpenSSL EVP詳解

  • Chapter1 OpenSSL EVP詳解
    • 一、EVP基本介紹
      • 1. EVP 加密和解密
      • 2. EVP 簽名和驗證
      • 3. EVP 加解密文件
    • 二、源碼結構
      • 2.1 全局函數
      • 2.2 BIO擴充
      • 2.3 摘要算法EVP封裝
      • 2.4 對稱算法EVP封裝
      • 2.5 非對稱算法EVP封裝
      • 2.6 基于口令的加密
    • 三、開發實例
      • 3.1 示例1
      • 3.2 示例2
      • 3.3 示例3
      • 3.4 示例4
  • Chapter2 openssl之EVP實現哈希(md5,sha256,sm3)
    • 一、環境說明
    • 二、功能說明
    • 三、EVP接口說明
    • 四、使用實例
      • 4.1 MD5算法實現實例。
      • 4.2 sha256算法實現實例。
      • 4.3 sm3算法實現實例。
    • 五、源碼地址
  • Chapter3 OpenSSL之EVP(二)——EVP系列函數介紹


國密算法
國密即國家密碼局認定的國產密碼算法。主要有SM1,SM2,SM3,SM4。密鑰長度和分組長度均為128位。

1、SM1 為對稱加密。其加密強度與AES相當。該算法不公開,調用該算法時,需要通過加密芯片的接口進行調用。
2、SM2為非對稱加密,基于ECC。該算法已公開。由于該算法基于ECC,故其簽名速度與秘鑰生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快于RSA。
3、SM3 消息摘要。可以用MD5作為對比理解。該算法已公開。校驗結果為256位,本身是散列算法,官方叫雜湊類算法,根據SHA256算法改進而來。
4、SM4 無線局域網標準的分組數據算法。對稱加密,密鑰長度和分組長度均為128位。

5、SM7適用于非接觸式IC卡的對稱算法,秘鑰長度128bit
6、SM9是標識算法,支持加密、簽名、交換。

國密芯片算法一般是對稱算法,密鑰不公開,當使用特定的芯片進行SM1或其他國密算法加密時,若用多個線程調用加密卡的API時,要考慮芯片對于多線程的支持情況。


EVP函數提供一個高層次的接口OpenSSL加密功能。

他們提供以下功能:

一個一致的接口,不管底層算法或模式
支持眾多的算法
加密/解密使用對稱和非對稱算法
簽名/驗證
導出密鑰
安全散列函數
消息認證碼
支持獨立的加密引擎


BIO是IO函數的抽象,對應用屏蔽底層IO細節,有2種類型的BIO:數據源BIO,過濾器BIO。

數據源BIO:內存、文件、網絡等;

過濾器BIO:消息摘要、加密、解密等;

EVP是高級加密接口,封裝了消息摘要、加密解密、簽名驗簽等,對外提供統一接口,推薦使用EVP接口。


Openssl EVP(high-level cryptographic functions[1])提供了豐富的密碼學中的各種函數。Openssl 中實現了各種對稱算法、摘要算法以及簽名/驗簽算法。EVP 函數將這些具體的算法進行了封裝。
??EVP系列的函數的聲明包含在”evp.h”里面,這是一系列封裝了openssl>加密庫里面所有算法的函數。通過這樣的統一的封裝,使得只需要在初始化參數的時候做很少的改變,就可以使用相同的代碼但采用不同的加密算法進行數據的加密和解密。
??EVP系列函數主要封裝了加密、摘要、編碼三大類型的算法,使用算法前需要調用OpenSSL_add_all_algorithms函數。
??其中以加密算法與摘要算法為基本,公開密鑰算法是對數據加密采用了對稱加密算法,對密鑰采用非對稱加密(公鑰加密,私鑰解密)。數字簽名是非對稱算法(私鑰簽名,公鑰認證)。
??EVP 主要封裝了如下功能函數:

實現了base64 編解碼BIO;
實現了加解密BIO;
實現了摘要BIO;
實現了reliable BIO;
封裝了摘要算法;
封裝了對稱加解密算法;
封裝了非對稱密鑰的加密(公鑰)、解密(私鑰)、簽名與驗證以及輔助函數;
基于口令的加密(PBE);
對稱密鑰處理;
數字信封:數字信封用對方的公鑰加密對稱密鑰,數據則用此對稱密鑰加密。發送給對方時,同時發送對稱密鑰密文和數據密文。接收方首先用自己的私鑰解密密鑰密文,得到對稱密鑰,然后用它解密數據。
其他輔助函數。


Chapter1 OpenSSL EVP詳解

原文鏈接:https://blog.csdn.net/ARV000/article/details/134681320

EVP(Enveloped Public Key)是 OpenSSL 中用于提供對稱加密、非對稱加密和哈希功能的高級加
密接口。EVP 庫提供了一個抽象的加密框架,使得可以在不同的算法實現之間進行切換,而不需要改變應用程序的代碼。以下是一些 EVP 開發的主要方面:

一、EVP基本介紹

1. EVP 加密和解密

EVP 提供了通用的加密和解密函數,可以用于對稱加密和非對稱加密。一般的流程如下:

  • 選擇加密算法,創建相應的 EVP_CIPHER 結構。
  • 初始化 EVP_CIPHER_CTX 上下文。
  • 使用 EVP_EncryptInit_ex 或 EVP_DecryptInit_ex 初始化加密或解密操作。
  • 使用 EVP_EncryptUpdate 或 EVP_DecryptUpdate 處理數據。
  • 使用 EVP_EncryptFinal_ex 或 EVP_DecryptFinal_ex 完成加密或解密操作。
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher = EVP_aes_256_cbc();ctx = EVP_CIPHER_CTX_new();EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv);
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, plaintext_len);
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);EVP_CIPHER_CTX_free(ctx);

2. EVP 簽名和驗證

EVP 提供了通用的簽名和驗證函數,可以用于不同的哈希算法和簽名算法。一般的流程如下:

選擇哈希算法和簽名算法,創建相應的 EVP_MD 和 EVP_PKEY 結構。

  • 初始化 EVP_MD_CTX 上下文。
  • 使用 EVP_DigestInit_ex 初始化哈希操作。
  • 使用 EVP_DigestUpdate 處理數據。
  • 使用 EVP_DigestFinal_ex 完成哈希操作。
  • 使用 EVP_SignInit_ex 或 EVP_VerifyInit_ex 初始化簽名或驗證操作。
  • 使用 EVP_SignUpdate 或 EVP_VerifyUpdate 處理數據。
  • 使用 EVP_SignFinal 或 EVP_VerifyFinal 完成簽名或驗證操作。
EVP_MD_CTX *mdctx;
const EVP_MD *md = EVP_sha256();
EVP_PKEY *pkey;
unsigned char signature[256];
size_t sig_len;mdctx = EVP_MD_CTX_new();
pkey = load_private_key();EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, data, data_len);
EVP_DigestFinal_ex(mdctx, digest, &digest_len);EVP_SignInit_ex(mdctx, EVP_sha256(), NULL);
EVP_SignUpdate(mdctx, data, data_len);
EVP_SignFinal(mdctx, signature, &sig_len, pkey);EVP_MD_CTX_free(mdctx);

3. EVP 加解密文件

EVP 還提供了一些便捷的函數用于對文件進行加解密操作,例如 EVP_EncryptInit_ex、EVP_DecryptUpdate、EVP_EncryptFinal_ex 等。

EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher = EVP_aes_256_cbc();ctx = EVP_CIPHER_CTX_new();EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv);
EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, plaintext_len);
EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen);EVP_CIPHER_CTX_free(ctx);

這些是 EVP 庫的一些基本用法。具體的使用取決于你的需求,可以根據 OpenSSL 的文檔和示例代碼進一步了解。

二、源碼結構

evp源碼位于crypto/evp目錄,可以分為如下幾類:

2.1 全局函數

主要包括c_allc.c、c_alld.c、c_all.c以及names.c。他們加載openssl支持的所有的對稱算法和摘要算法,放入到哈希表中。實現了OpenSSL_add_all_digests、OpenSSL_add_all_ciphers以及OpenSSL_add_all_algorithms(調用了前兩個函數)函數。在進行計算時,用戶也可以單獨加載摘要函數(EVP_add_digest)和對稱計算函數(EVP_add_cipher)。

2.2 BIO擴充

包括bio_b64.c、bio_enc.c、bio_md.c和bio_ok.c,各自實現了BIO_METHOD方法,分別用于base64編解碼、對稱加解密以及摘要。

2.3 摘要算法EVP封裝

由digest.c實現,實現過程中調用了對應摘要算法的回調函數。各個摘要算法提供了自己的EVP_MD靜態結構,對應源碼為m_xxx.c。

2.4 對稱算法EVP封裝

由evp_enc.c實現,實現過程調用了具體對稱算法函數,實現了Update操作。各種對稱算法都提供了一個EVP_CIPHER靜態結構,對應源碼為e_xxx.c。需要注意的是,e_xxx.c中不提供完整的加解密運算,它只提供基本的對于一個block_size數據的計算,完整的計算由evp_enc.c來實現。當用戶想添加一個自己的對稱算法時,可以參考e_xxx.c的實現方式。一般用戶至少需要實現如下功能:

? 構造一個新的靜態的EVP_CIPHER結構;

? 實現EVP_CIPHER結構中的init函數,該函數用于設置iv,設置加解密標記、以及根據外送密鑰生成自己的內部密鑰;

? 實現do_cipher函數,該函數僅對block_size字節的數據進行對稱運算;

? 實現cleanup函數,該函數主要用于清除內存中的密鑰信息。

2.5 非對稱算法EVP封裝

主要是以p_開頭的文件。其中,p_enc.c封裝了公鑰加密;p_dec.c封裝了私鑰解密;p_lib.c實現一些輔助函數;p_sign.c封裝了簽名函數;p_verify.c封裝了驗簽函數;p_seal.c封裝了數字信封;p_open.c封裝了解數字信封。

2.6 基于口令的加密

包括p5_crpt2.c、p5_crpt.c和evp_pbe.c。

三、開發實例

3.1 示例1

#include <string.h>#include <openssl/evp.h>int    main(){int                                ret,which=1;EVP_CIPHER_CTX             ctx;const EVP_CIPHER      *cipher;unsigned char        key[24],iv[8],in[100],out[108],de[100];int                                i,len,inl,outl,total=0;for(i=0;i<24;i++){memset(&key[i],i,1);}for(i=0;i<8;i++){memset(&iv[i],i,1);}for(i=0;i<100;i++){memset(&in[i],i,1);}EVP_CIPHER_CTX_init(&ctx);printf("please select :\n");printf("1: EVP_des_ede3_ofb\n");printf("2: EVP_des_ede3_cbc\n");scanf("%d",&which);if(which==1)cipher=EVP_des_ede3_ofb();elsecipher=EVP_des_ede3_cbc();ret=EVP_EncryptInit_ex(&ctx,cipher,NULL,key,iv);if(ret!=1){printf("EVP_EncryptInit_ex err1!\n");return -1;}inl=50;len=0;EVP_EncryptUpdate(&ctx,out+len,&outl,in,inl);len+=outl;EVP_EncryptUpdate(&ctx,out+len,&outl,in+50,inl);len+=outl;EVP_EncryptFinal_ex(&ctx,out+len,&outl);len+=outl;printf("加密結果長度:%d\n",len);/* 解密 */EVP_CIPHER_CTX_cleanup(&ctx);EVP_CIPHER_CTX_init(&ctx);ret=EVP_DecryptInit_ex(&ctx,cipher,NULL,key,iv);if(ret!=1){printf("EVP_DecryptInit_ex err1!\n");return -1;}total=0;EVP_DecryptUpdate(&ctx,de+total,&outl,out,44);total+=outl;EVP_DecryptUpdate(&ctx,de+total,&outl,out+44,len-44);total+=outl;ret=EVP_DecryptFinal_ex(&ctx,de+total,&outl);total+=outl;if(ret!=1){EVP_CIPHER_CTX_cleanup(&ctx);printf("EVP_DecryptFinal_ex err\n");return -1;}if((total!=100) || (memcmp(de,in,100))){printf("err!\n");return -1;}EVP_CIPHER_CTX_cleanup(&ctx);printf("test ok!\n");return 0;}

輸出結果如下:

please select :1: EVP_des_ede3_ofb2: EVP_des_ede3_cbc1加密結果長度:100test ok!please select :1: EVP_des_ede3_ofb2: EVP_des_ede3_cbc2加密結果長度:104test ok!

3.2 示例2

#include <string.h>#include <openssl/evp.h>int    main(){int                                cnid,ret,i,msize,mtype;int                                mpktype,cbsize,mnid,mbsize;const EVP_CIPHER      *type;const EVP_MD             *md;int                                datal,count,keyl,ivl;unsigned char        salt[20],data[100],*key,*iv;const      char        *cname,*mname;type=EVP_des_ecb();cnid=EVP_CIPHER_nid(type);cname=EVP_CIPHER_name(type);cbsize=EVP_CIPHER_block_size(type);printf("encrypto nid : %d\n",cnid);printf("encrypto name: %s\n",cname);printf("encrypto bock size : %d\n",cbsize);md=EVP_md5();mtype=EVP_MD_type(md);mnid=EVP_MD_nid(md);mname=EVP_MD_name(md);mpktype=EVP_MD_pkey_type(md);msize=EVP_MD_size(md);mbsize=EVP_MD_block_size(md);printf("md info : \n");printf("md type  : %d\n",mtype);printf("md nid  : %d\n",mnid);printf("md name : %s\n",mname);printf("md pkey type : %d\n",mpktype);printf("md size : %d\n",msize);printf("md block size : %d\n",mbsize);keyl=EVP_CIPHER_key_length(type);key=(unsigned char *)malloc(keyl);ivl=EVP_CIPHER_iv_length(type);iv=(unsigned char *)malloc(ivl);for(i=0;i<100;i++)memset(&data[i],i,1);for(i=0;i<20;i++)memset(&salt[i],i,1);datal=100;count=2;ret=EVP_BytesToKey(type,md,salt,data,datal,count,key,iv);printf("generate key value: \n");for(i=0;i<keyl;i++)printf("%x ",*(key+i));printf("\n");printf("generate iv value: \n");for(i=0;i<ivl;i++)printf("%x ",*(iv+i));printf("\n");return 0;}

EVP_BytesToKey函數通過salt以及data數據來生成所需要的key和iv。

輸出:

encrypto nid : 29encrypto name: DES-ECBencrypto bock size : 8md info :md type  : 4md nid  : 4md name : MD5md pkey type : 8md size : 16md block size : 64generate key value:54 0 b1 24 18 42 8d ddgenerate iv value:ba 7d c3 97 a0 c9 e0 70

3.3 示例3

#include <openssl/evp.h>#include <openssl/rsa.h>int    main(){int                         ret,inlen,outlen=0;unsigned long  e=RSA_3;char               data[100],out[500];EVP_MD_CTX             md_ctx,md_ctx2;EVP_PKEY            *pkey;RSA                      *rkey;BIGNUM               *bne;/* 待簽名數據*/strcpy(data,"openssl 編程作者:趙春平");inlen=strlen(data);/* 生成RSA密鑰*/bne=BN_new();ret=BN_set_word(bne,e);rkey=RSA_new();ret=RSA_generate_key_ex(rkey,1024,bne,NULL);if(ret!=1)  goto err;pkey=EVP_PKEY_new();EVP_PKEY_assign_RSA(pkey,rkey);/* 初始化*/EVP_MD_CTX_init(&md_ctx);ret=EVP_SignInit_ex(&md_ctx,EVP_md5(), NULL);if(ret!=1)goto err;ret=EVP_SignUpdate(&md_ctx,data,inlen);if(ret!=1)goto err;ret=EVP_SignFinal(&md_ctx,out,&outlen,pkey);/* 驗證簽名*/EVP_MD_CTX_init(&md_ctx2);ret=EVP_VerifyInit_ex(&md_ctx2,EVP_md5(), NULL);if(ret!=1) goto err;ret=EVP_VerifyUpdate(&md_ctx2,data,inlen);if(ret!=1) goto err;ret=EVP_VerifyFinal(&md_ctx2,out,outlen,pkey);if(ret==1)printf("驗證成功\n");elseprintf("驗證錯誤\n");err:RSA_free(rkey);BN_free(bne);return 0;}

3.4 示例4

#include <openssl/evp.h>#include <openssl/rsa.h>int    main(){int                         ret,ekl[2],npubk,inl,outl,total=0,total2=0;unsigned long  e=RSA_3;char               *ek[2],iv[8],in[100],out[500],de[500];EVP_CIPHER_CTX      ctx,ctx2;EVP_CIPHER        *type;EVP_PKEY            *pubkey[2];RSA                      *rkey;BIGNUM               *bne;/* 生成RSA密鑰*/bne=BN_new();ret=BN_set_word(bne,e);rkey=RSA_new();ret=RSA_generate_key_ex(rkey,1024,bne,NULL);pubkey[0]=EVP_PKEY_new();EVP_PKEY_assign_RSA(pubkey[0],rkey);type=EVP_des_cbc();npubk=1;EVP_CIPHER_CTX_init(&ctx);ek[0]=malloc(500);ek[1]=malloc(500);ret=EVP_SealInit(&ctx,type,ek,ekl,iv,pubkey,1);  /* 只有一個公鑰*/if(ret!=1) goto err;strcpy(in,"openssl 編程");inl=strlen(in);ret=EVP_SealUpdate(&ctx,out,&outl,in,inl);if(ret!=1)goto err;total+=outl;ret=EVP_SealFinal(&ctx,out+outl,&outl);if(ret!=1) goto err;total+=outl;memset(de,0,500);EVP_CIPHER_CTX_init(&ctx2);ret=EVP_OpenInit(&ctx2,EVP_des_cbc(),ek[0],ekl[0],iv,pubkey[0]);if(ret!=1) goto err;ret=EVP_OpenUpdate(&ctx2,de,&outl,out,total);total2+=outl;ret=EVP_OpenFinal(&ctx2,de+outl,&outl);total2+=outl;de[total2]=0;printf("%s\n",de);err:free(ek[0]);free(ek[1]);EVP_PKEY_free(pubkey[0]);BN_free(bne);getchar();return 0;}
輸出結果:openssl 編程

Chapter2 openssl之EVP實現哈希(md5,sha256,sm3)

原文鏈接:https://blog.csdn.net/arv002/article/details/130135979

一、環境說明

操作系統:linux(debian)

開發工具:Qt creator 4.8.2

Qt版本:5.11.3.45-1

openssl版本:openssl-3.1.0

二、功能說明

1、使用openssl的EVP接口開發對數據進行hash。算法包括:md5、sha256、sm3

2、使用openssl的EVP接口開發對文件進行hash。算法包括:md5、sha256、sm3

三、EVP接口說明

使用EVP的接口有以下幾個:EVP_MD_CTX_new,EVP_DigestInit_ex,EVP_DigestUpdate,EVP_DigestFinal_ex,EVP_MD_CTX_free

函數名稱 函數說明
EVP_MD_CTX 摘要上下文對象結構
EVP_MD_CTX * EVP_MD_CTX_new(void) 創建摘要上下文對象
int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type) 初始化摘要上下文,type為摘要算法抽象集合。
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
向摘要計算的海棉結構輸入一段數據,多次輸入表示數據累計。

成功返回1,失敗返回0

int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s); 生成最終摘要,輸出摘要值和長度。
成功返回1,失敗返回0。
int EVP_MD_CTX_free(EVP_MD_CTX *ctx) 釋放摘要上下文對象

四、使用實例

4.1 MD5算法實現實例。

實現了對數據的MD5散列,以及對文件內容MD5散列。

#include "encytion_md5.h"
#include <QtDebug>
#include <QFile>
#include <QDataStream>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
#include "tools.h"
EncytionMD5::EncytionMD5(QObject *) {}QString EncytionMD5::EncytonData(QString string)
{qInfo() << "EncytionMD5 " << string;unsigned int len = 0;EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_md5(), nullptr);// hash計算EVP_DigestUpdate(ctx, string.toStdString().c_str(),string.toStdString().length());unsigned char result[MD5_DIGEST_LENGTH] = {};EVP_DigestFinal_ex(ctx, result, &len);QString res = Tools::CharToHex(result, len);EVP_MD_CTX_free(ctx);return res;
}QString EncytionMD5::EncytonFile(QString inFilePath)
{qInfo() << "EncytionMD5 EncytonFile" << inFilePath;unsigned int len = 0;EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_md5(), nullptr);FILE *fp = nullptr;fp = fopen(inFilePath.toStdString().c_str(), "rb+");if (nullptr == fp) {return "";}char szDataBuff[MD5_DIGEST_LENGTH];unsigned long nLineLen;unsigned long a = 1;while (!feof(fp)) {memset(szDataBuff, 0x00, sizeof(szDataBuff));nLineLen = fread(szDataBuff, a,static_cast<unsigned long>(MD5_DIGEST_LENGTH), fp);if (nLineLen) {EVP_DigestUpdate(ctx, szDataBuff, static_cast<int>(nLineLen));}}fclose(fp);unsigned char result[MD5_DIGEST_LENGTH] = {};EVP_DigestFinal_ex(ctx, result, &len);EVP_MD_CTX_free(ctx);QString res = Tools::CharToHex(result, len);return res;
}

4.2 sha256算法實現實例。

實現了對數據的sha256散列,以及對文件內容sha256散列。

#include "encytion_sha256.h"
#include <QtDebug>
#include <QtDebug>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include "tools.h"
EncytionSha256::EncytionSha256(QObject *) {}
// 數據加密
QString EncytionSha256::EncytonData(QString string)
{qInfo() << "EncytionSha256 " << string;unsigned int len = 0;EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr);// hash計算EVP_DigestUpdate(ctx, string.toStdString().c_str(),string.toStdString().length());unsigned char result[SHA256_DIGEST_LENGTH] = {};EVP_DigestFinal_ex(ctx, result, &len);QString res = Tools::CharToHex(result, len);EVP_MD_CTX_free(ctx);return res;
}
// 文件加密,返回加密內容
QString EncytionSha256::EncytonFile(QString inFilePath)
{qInfo() << "EncytionSha256 EncytonFile" << inFilePath;unsigned int len = 0;EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr);FILE *fp = nullptr;fp = fopen(inFilePath.toStdString().c_str(), "rb+");if (nullptr == fp) {return "";}char szDataBuff[SHA256_DIGEST_LENGTH];unsigned long nLineLen;unsigned long a = 1;while (!feof(fp)) {memset(szDataBuff, 0x00, sizeof(szDataBuff));nLineLen = fread(szDataBuff, a,static_cast<unsigned long>(SHA256_DIGEST_LENGTH), fp);if (nLineLen) {EVP_DigestUpdate(ctx, szDataBuff, static_cast<int>(nLineLen));}}fclose(fp);unsigned char result[SHA256_DIGEST_LENGTH] = {};EVP_DigestFinal_ex(ctx, result, &len);EVP_MD_CTX_free(ctx);QString res = Tools::CharToHex(result, len);return res;
}

4.3 sm3算法實現實例。

實現了對數據的sm3散列,以及對文件內容sm3散列。

#include "encytion_sm3.h"
#include <QtDebug>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include <openssl/sm3.h>
#include "tools.h"
EncytionSM3::EncytionSM3(QObject *) {}QString EncytionSM3::EncytonData(QString string)
{qInfo() << "EncytionSM3 " << string;unsigned int len = 0;EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_sm3(), nullptr);// hash計算EVP_DigestUpdate(ctx, string.toStdString().c_str(),string.toStdString().length());unsigned char result[SM3_DIGEST_LENGTH] = {};EVP_DigestFinal_ex(ctx, result, &len);//    EVP_MD_CTX_init(&ctx);QString res = Tools::CharToHex(result, len);EVP_MD_CTX_free(ctx);return res;
}QString EncytionSM3::EncytonFile(QString inFilePath)
{qInfo() << "EncytionSha256 EncytonFile" << inFilePath;unsigned int len = 0;EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_sm3(), nullptr);FILE *fp = nullptr;fp = fopen(inFilePath.toStdString().c_str(), "rb+");if (nullptr == fp) {return "";}char szDataBuff[SM3_DIGEST_LENGTH];unsigned long nLineLen;unsigned long a = 1;while (!feof(fp)) {memset(szDataBuff, 0x00, sizeof(szDataBuff));nLineLen = fread(szDataBuff, a,static_cast<unsigned long>(SM3_DIGEST_LENGTH), fp);if (nLineLen) {EVP_DigestUpdate(ctx, szDataBuff, static_cast<int>(nLineLen));}}fclose(fp);unsigned char result[SM3_DIGEST_LENGTH] = {};EVP_DigestFinal_ex(ctx, result, &len);EVP_MD_CTX_free(ctx);QString res = Tools::CharToHex(result, len);return res;
}

五、源碼地址

GitHub - arv000/cipher: linux操作系統,使用openssl實現加密解密功能。

Chapter3 OpenSSL之EVP(二)——EVP系列函數介紹

原文鏈接:https://blog.csdn.net/scuyxi/article/details/60621075

EVP系列函數
摘要函數
典型的摘要函數主要有:
1) EVP_md5
返回 md5 的 EVP_MD。
2) EVP_sha1
返回 sha1 的 EVP_MD。
3) EVP_sha256
返回 sha256 的 EVP_MD。
4) EVP_DigestInit
摘要初使化函數,需要有 EVP_MD 作為輸入參數。
5) EVP_DigestUpdate 和 EVP_DigestInit_ex
摘要 Update 函數,用于進行多次摘要。
6) EVP_DigestFinal 和 EVP_DigestFinal_ex
摘要 Final 函數,用戶得到最終結果。
7) EVP_Digest
對一個數據進行摘要,它依次調用了上述三個函數。

對稱加解密函數
典型的加解密函數主要有:
1) EVP_CIPHER_CTX_init
初始化對稱計算上下文。
2) EVP_CIPHER_CTX_cleanup
清除對稱算法上下文數據, 它調用用戶提供的銷毀函數銷清除內部密鑰以及其他數據。
3) EVP_des_ede3_ecb
返回一個 EVP_CIPHER;
4) EVP_EncryptInit 和 EVP_EncryptInit_ex
加密初始化函數,本函數調用具體算法的 init 回調函數,將外送密鑰 key 轉換為內部密鑰形式,將初始化向量 iv 拷貝到 ctx 結構中。
5) EVP_EncryptUpdate
加密函數,用于多次計算,它調用了具體算法的 do_cipher 回調函數。
6) EVP_EncryptFinal 和 EVP_EncryptFinal_ex
獲取加密結果,函數可能涉及填充,它調用了具體算法的do_cipher 回調函數。
7) EVP_DecryptInit 和 EVP_DecryptInit_ex
解密初始化函數。
8) EVP_DecryptUpdate
解密函數,用于多次計算,它調用了具體算法的 do_cipher 回調函數。
9) EVP_DecryptFinal 和 EVP_DecryptFinal_ex
獲取解密結果,函數可能涉及去填充,它調用了具體算法的do_cipher 回調函數。
10) EVP_BytesToKey
計算密鑰函數,它根據算法類型、摘要算法、 salt 以及輸入數據計算出一個對稱密鑰和初始化向量 iv。
11) PKCS5_PBE_keyivgen 和 PKCS5_v2_PBE_keyivgen
實現了 PKCS5 基于口令生成密鑰和初始化向量的算法。
12) PKCS5_PBE_add
加載所有 openssl 實現的基于口令生成密鑰的算法。
13) EVP_PBE_alg_add
添加一個 PBE 算法。

對稱加密過程
對稱加密過程如下:

1) EVP_EncryptInit:
設置 buf_len 為 0,表明臨時緩沖區 buf 沒有數據。

2) EVP_EncryptUpdate:
ctx 結構中的 buf 緩沖區用于存放上次 EVP_EncryptUpdate 遺留下來的未加密的數據, buf_len 指明其長度。如果 buf_len 為 0,加密的時候先加密輸入數據的整數倍,將余下的數據拷貝到 buf 緩沖區。如果 buf_len 不為 0,先加密 buf 里面的數據和輸入數據的一部分(湊足一個分組的長度),然后用上面的方法加密,輸出結
果是加過密的數據。

3) EVP_ EncryptFinal
加密 ctx 的 buf 中余下的數據,如果長度不夠一個分組(分組長度不為 1),則填充,然后再加密,輸出結果。
總之,加密大塊數據(比如一個大的文件,多出調用 EVP_EncryptUpdate)的結果等效于將所有的數據一次性讀入內存進行加密的結果。加密和解密時每次計算的數據塊的大
小不影響其運算結果。

非對稱函數
典型的非對稱函數有:
1) EVP_PKEY_encrypt
公鑰加密。
2) EVP_PKEY_decrypt
私鑰解密。
3) EVP_PKEY_assign
設置 EVP_PKEY 中具體的密鑰結構,使它代表該密鑰。
4) EVP_PKEY_assign_RSA/ EVP_PKEY_set1_RSA
設置 EVP_PKEY 中的 RSA 密鑰結構,使它代表該 RSA 密鑰。
5) EVP_PKEY_get1_RSA
獲取 EVP_PKEY 的 RSA 密鑰結構。
6) EVP_SignFinal
簽名操作,輸入參數必須有私鑰(EVP_PKEY)。
7) EVP_VerifyFinal
驗證簽名,輸入參數必須有公鑰(EVP_PKEY)。
8) int EVP_OpenInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,const unsigned
char *ek, int ekl, const unsigned char *iv,EVP_PKEY *priv)
解數字信封初始化操作,type為對稱加密算法,ek為密鑰密文,ekl為密
鑰密文長度,iv為填充值,priv為用戶私鑰。
9) EVP_OpenUpdate
做解密運算。
10) EVP_OpenFinal
做解密運算,解開數字信封。
11) int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, unsigned char **ek,int *ekl, unsigned char *iv, EVP_PKEY **pubk, int npubk)
type為對稱算法,ek數組用來存放多個公鑰對密鑰加密的結果,ekl用于存放ek數組中每個密鑰密文的長度,iv為填充值,pubk數組用來存放多個公鑰,npubk為公鑰個數,本函數用多個公鑰分別加密密鑰,并做加密初始化。
12)EVP_SealUpdate
做加密運算。
13)EVP_SealFinal
做加密運算,制作數字信封。

BASE64 編解碼函數

  1. EVP_EncodeInit
    BASE64 編碼初始化。
  2. EVP_EncodeUpdate
    BASE64 編碼,可多次調用。
  3. EVP_EncodeFinal
    BASE64 編碼,并獲取最終結果。
  4. EVP_DecodeInit
    BASE64 解碼初始化。
  5. EVP_DecodeUpdate
    輸入數據長度不能大于 80 字節。 BASE64 解碼可多次調用,注意,本函數的輸入數據不能太長。
  6. EVP_DecodeFinal
    BASE64 解碼,并獲取最終結果。
    7) EVP_EncodeBlock
    BASE64 編碼函數,本函數可單獨調用。
    8) EVP_DecodeBlock
    BASE64 解碼,本函數可單獨調用,對輸入數據長度無要求。

其他函數
1) EVP_add_cipher
將對稱算法加入到全局變量,以供調用。
2) EVP_add_digest
將摘要算法加入到全局變量中,以供調用
3) EVP_CIPHER_CTX_ctrl
對稱算法控制函數,它調用了用戶實現的 ctrl 回調函數。
4) EVP_CIPHER_CTX_set_key_length
當對稱算法密鑰長度為可變長時,設置對稱算法的密鑰長度。
5) EVP_CIPHER_CTX_set_padding
設置對稱算法的填充,對稱算法有時候會涉及填充。加密分組長度大于一時,用戶輸入數據不是加密分組的整數倍時,會涉及到填充。填充在最后一個分組來完成, openssl 分組填充時,如果有 n 個填充,則將最后一個分組用 n 來填滿。
6) EVP_CIPHER_get_asn1_iv
獲取原始 iv,存放在 ASN1_TYPE 結構中。
7) EVP_CIPHER_param_to_asn1
設置對稱算法參數,參數存放在 ASN1_TYPE 類型中,它調用用戶實現的回調函數 set_asn1_parameters 來實現。
8) EVP_CIPHER_type
獲取對稱算法的類型。
9) EVP_CipherInit/EVP_CipherInit_ex
對稱算法計算(加/解密)初始化函數, _ex 函數多了硬件 enginge 參數,EVP_EncryptInit 和 EVP_DecryptInit 函數也調用本函數。
10) EVP_CipherUpdate
對稱計算 (加/解密)函數, 它調用了 EVP_EncryptUpdate 和 EVP_DecryptUpdate函數。
11) EVP_CipherFinal/EVP_CipherFinal_ex
對 稱 計 算 ( 加 / 解 ) 函 數 , 調 用 了 EVP_EncryptFinal (_ex ) 和EVP_DecryptFinal(_ex);本函數主要用來處理最后加密分組,可能會有對稱計算。
12) EVP_cleanup
清除加載的各種算法,包括對稱算法、摘要算法以及 PBE 算法,并清除這些算法相關的哈希表的內容。
13) EVP_get_cipherbyname
根據字串名字來獲取一種對稱算法(EVP_CIPHER),本函數查詢對稱算法哈希表。
14) EVP_get_digestbyname
根據字串獲取摘要算法(EVP_MD),本函數查詢摘要算法哈希表。
15) EVP_get_pw_prompt
獲取口令提示信息字符串.
16) int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
PBE 初始化函數。本函數用口令生成對稱算法的密鑰和初始化向量,并作加/解密初始化操作。本函數再加上后續的 EVP_CipherUpdate 以及 EVP_CipherFinal_ex
構成一個完整的加密過程(可參考 crypto/p12_decr.c 的 PKCS12_pbe_crypt 函數) .
17) EVP_PBE_cleanup
刪除所有的 PBE 信息,釋放全局堆棧中的信息.
18) EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8)
將 PKCS8_PRIV_KEY_INFO(x509.h 中定義)中保存的私鑰轉換為 EVP_PKEY結構。
19) EVP_PKEY2PKCS8/EVP_PKEY2PKCS8_broken
將 EVP_PKEY 結構中的私鑰轉換為 PKCS8_PRIV_KEY_INFO 數據結構存儲。
20) EVP_PKEY_bits
非對稱密鑰大小,為比特數。
21) EVP_PKEY_cmp_parameters
比較非對稱密鑰的密鑰參數,用于 DSA 和 ECC 密鑰。
22) EVP_PKEY_copy_parameters
拷貝非對稱密鑰的密鑰參數,用于 DSA 和 ECC 密鑰。
23) EVP_PKEY_free
釋放非對稱密鑰數據結構。
24) EVP_PKEY_get1_DH/EVP_PKEY_set1_DH
獲取/設置 EVP_PKEY 中的 DH 密鑰。
25) EVP_PKEY_get1_DSA/EVP_PKEY_set1_DSA
獲取/設置 EVP_PKEY 中的 DSA 密鑰。
26) EVP_PKEY_get1_RSA/EVP_PKEY_set1_RSA
獲取/設置 EVP_PKEY 中結構中的 RSA 結構密鑰。
27) EVP_PKEY_missing_parameters
檢查非對稱密鑰參數是否齊全,用于 DSA 和 ECC 密鑰。
28) EVP_PKEY_new
生成一個 EVP_PKEY 結構。
29) EVP_PKEY_size
獲取非對稱密鑰的字節大小。
30) EVP_PKEY_type
獲取 EVP_PKEY 中表示的非對稱密鑰的類型。
31) int EVP_read_pw_string(char *buf,int length,const char *prompt,int verify)
獲取用戶輸入的口令;buf 用來存放用戶輸入的口令,length 為 buf 長度,prompt為提示給用戶的信息,如果為空,它采用內置的提示信息, verify 為 0 時,不要求驗證用戶輸入的口令,否則回要求用戶輸入兩遍。返回 0 表示成功。
32) EVP_set_pw_prompt
設置內置的提示信息,用于需要用戶輸入口令的場合。

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/39925.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/39925.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/39925.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL】數據庫——備份與恢復,日志管理

一、數據備份的重要性 1.備份的主要目的是災難恢復 在生產環境中&#xff0c;數據的安全性至關重要 任何數據的丟失都可能產生嚴重的后果造成數據丟失的原因&#xff1a; 程序錯誤人為,操作錯誤運算錯誤磁盤故障災難&#xff08;如火災、地震&#xff09;和盜竊 2.數據庫備份…

【5G射頻基本架構】

平臺框架 平臺演進及搭配 5G NR頻譜 NSA/SA/ENDC 在雙連接中&#xff0c;UE在連接狀態下可同時使用至少兩個不同基站的無線資源。對于Sprint&#xff0c;ENDC將允許設備在相同的頻段&#xff08;41 / 2.5 GHz頻段&#xff09;上同時訪問LTE和5G。 手機硬件實現ENDC方式—類似LT…

動態住宅代理IP的優勢是什么?什么地方用到?

在大數據時代的背景下&#xff0c;代理IP成為了很多企業順利開展的重要工具。代理IP地址可以分為住宅代理IP地址和數據中心代理IP地址。選擇住宅代理IP的好處是可以實現真正的高匿名性&#xff0c;而使用數據中心代理IP可能會暴露自己使用代理的情況。 住宅代理IP是指互聯網服務…

數據庫系統概論 | 觸發器代碼 | 行級觸發器 | 語句級觸發器

觸發器 這篇博客拿兩個例子來解釋一下什么是行級觸發器和語句級觸發器。 **例子1&#xff1a;**當對表SC的Grade屬性進行修改時&#xff0c;若分數增加了10%&#xff0c;則將此次操作記錄到另一個表SC_U&#xff08;Sno CHAR(8)、Cno CHAR(5)、Oldgrade SMALLINT、Newgrade S…

Flink 窗口觸發器(Trigger)(一)

Flink 窗口觸發器(Trigger)(一) Flink 窗口觸發器(Trigger)(二) Flink的窗口觸發器&#xff08;Trigger&#xff09;是流處理中一個非常關鍵的概念&#xff0c;它定義了窗口何時被觸發并決定觸發后的行為&#xff08;如進行窗口數據的計算或清理&#xff09;。 一、基本概念 …

[數據集][目標檢測]人員狀態跑睡抽煙打電話跌倒檢測數據集4943張5類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;4943 標注數量(xml文件個數)&#xff1a;4943 標注數量(txt文件個數)&#xff1a;4943 標注…

[Leetcode 136][Easy]-只出現一次的數字

目錄 題目描述 具體思路 題目描述 原題鏈接 具體思路 ①首先看到數組中重復的數字&#xff0c;想到快慢指針&#xff0c;但是數組的元素是亂序的不好求。因此先對數組排序。使用了STL庫的sort函數&#xff0c;時間復雜度O(nlogn)不符合題目要求&#xff0c;空間復雜度O(1)。…

Pytorch學習之torch.split函數

Pytorch學習之torch.split函數 一、簡介 torch.split用于將一個張量&#xff08;tensor&#xff09;沿指定維度&#xff08;dim&#xff09;拆分為多個子張量。這個函數對于處理需要按塊拆分數據的任務非常有用&#xff0c;例如在自然語言處理和圖像處理中的數據預處理。 二…

RXMH2 RK223 069 AS大容量中間繼電器 板前接線 約瑟JOSEF

RXMH2大容量中間繼電器型號&#xff1a; RXMH2 RK 223 067大容量中間繼電器&#xff1b; RXMH2 RK 223 068大容量中間繼電器&#xff1b; RXMH2 RK 223 069大容量中間繼電器&#xff1b; RXMH2 RK 223 070大容量中間繼電器&#xff1b; 用途 用于電力系統二次回路及工業自…

基于Hadoop平臺的電信客服數據的處理與分析③項目開發:搭建Kafka大數據運算環境---任務11:基礎環境準備

任務描述 任務主要是安裝配置基礎環境&#xff0c;主要內容包括&#xff1a; 1、安裝java Kafka和ZooKeeper都需要安裝Java環境&#xff0c;推薦至少Java8及以上版本 2、安裝ZooKeeper ZooKeeper是Kafka集群的必要組件 3、安裝kafka Kafka版本包括使用的scala語言版本和kafka版…

Ubuntu22.04上Docker的安裝

1. 使用APT安裝 首先安裝HTTPS傳輸的軟件包和CA證書&#xff0c;確保軟件下載過程中不被篡改。 sudo apt-get updatesudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release -y然后&#xff0c;使用國內源&#xff0c;并添加軟件源的 GPG 密鑰以防…

Java面試題:討論持續集成/持續部署的重要性,并描述如何在項目中實施CI/CD流程

持續集成/持續部署&#xff08;CI/CD&#xff09;的重要性 持續集成&#xff08;Continuous Integration, CI&#xff09; 和 持續部署&#xff08;Continuous Deployment, CD&#xff09; 是現代軟件開發的重要實踐。這些方法通過自動化構建、測試和部署過程&#xff0c;顯著…

Ubuntu 用戶配置

環境信息 系統版本Ubuntu16.04.1-Ubuntu x86_64 創建用戶組 新建一個用戶組&#xff0c;GID為888。 sudo addgroup –g 888 組名刪除用戶組 sudo delgroup 組名創建用戶 username 為用戶名&#xff0c;執行后系統會提示輸入新用戶的密碼&#xff0c;后續輸入其他信息&#xff0…

代碼隨想錄day34 貪心(5)

56. 合并區間 - 力扣&#xff08;LeetCode&#xff09; 寫法一&#xff1a;維護right和left兩個數作為當前區間的左右邊界 class Solution:def merge(self, intervals: List[List[int]]) -> List[List[int]]:intervals.sort(key lambda x: x[0])left intervals[0][0]ri…

番外1:企業數據

數據類別說明 企業中除了主數據和次級數據外,企業中還有其他一些常見的數據分類,這些數據類型根據其特定的用途和性質,在企業的各個功能和部門中起著重要作用。 主數據(Master Data) 主數據是企業中核心、長期存在且在整個組織中廣泛使用的關鍵數據。主數據具有以下特征:…

Vue2和Vue3的區別Vue3的組合式API

一、Vue2和Vue3的區別 1、創建方式的不同&#xff1a; &#xff08;1&#xff09;、vue2:是一個構造函數&#xff0c;通過該構造函數創建一個Vue實例 new Vue({})&#xff08;2&#xff09;、Vue3:是一個對象。并通過該對象的createApp()方法&#xff0c;創建一個vue實例。 Vue…

RAG技術下的文檔智能檢索

在數字化浪潮的推動下&#xff0c;信息檢索已成為我們日常生活中不可或缺的一部分。然而&#xff0c;隨著數據量的爆炸式增長&#xff0c;如何快速精準地從海量文檔中檢索出有價值的信息&#xff0c;成為了一個巨大的挑戰。本文將帶您走進 Pinecone 向量數據庫的世界&#xff0…

AIGC到底如何改變創意設計?

在當今數字化時代&#xff0c;AIGC&#xff08;生成式人工智能&#xff09;技術的崛起對創意設計領域產生了深遠的影響。AIGC不僅為設計師提供了新的工具和方法&#xff0c;還改變了傳統的設計流程和思維方式。 傳統的設計過程中&#xff0c;設計師需要耗費大量時間在繪圖、修…

npm install puppeteer 報錯 npm ERR! PUPPETEER_DOWNLOAD_HOST is deprecated解決辦法

npm install puppeteer 報錯如下&#xff1a; npm ERR! PUPPETEER_DOWNLOAD_HOST is deprecated. Use PUPPETEER_DOWNLOAD_BASE_URL instead. npm ERR! Error: ERROR: Failed to set up Chrome v126.0.6478.126! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to sk…

【Linux進程】僵尸進程與孤兒進程

前言 僵尸進程和孤兒進程是Linux中極為重要的兩個種進程狀態, 本文將會圍繞這三個問題: 是什么? 為什么? 如何產生的? 詳細的介紹這兩種進程; 以及一些使用場景. 僵尸進程 在了解孤兒進程之前, 需要先引入僵尸進程的概念; 什么是僵尸進程? 僵尸進程: 就是處于僵死狀態的進…