openssl 之EVP系列 PART III(14~20)



openssl 之EVP 系列之14---EVP_Encode 系列函数介绍
根据自己的理解写成( 作者: DragonKing, Mail: wzhah@263.net , 发布于:http://openssl.126.com 之openssl 专业论坛,版本:openssl-0.9.7)
该系列函数主要对数据进行BASE64 编码,为此,它定义了一个简单的EVP_ENCODE_CTX
结构类型,由于该结构比较简单,主要包括了长度信息以及数据缓存,大家可以参考evp.h,
这里不再做介绍。
EVP_Encode 系列函数定义如下(openssl\evp.h):
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,unsigned char*in,int inl);
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl);
int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n);


【EVP_EncodeInit】

该函数初始化一个用来进行base64 编码的结构,事实上,该函数只是简单设置了结构里面几个常量的长度。


【EVP_EncodeUpdate】

该函数将参数in 里面的inl 自己数据拷贝到结构体ctx 里面,如果结构体里面有数据,就同时将结构体里面的数据进行BASE64 编码并输出到参数out 指向的缓存里面,输出数据的长度保存在outl 里面。注意,在第一次调用本函数的时候,虽然往结构体里面拷贝数据了,但是结构体ctx 里面开始是没有输入数据存在并且输入数据长度不超出ctx内部存储数据的最长限制,就不会有任何数据被进行BASE64 编码,也就是说,不会有任何数据输出;但是如果输入数据长度比内部存储的数据长,那么就会输出部分经过BASE64 编码的数据。数据输出总是在下一层输入前完成的。


【EVP_EncodeFinal】

该函数将结构体ctx 里面剩余数据进行BASE64 编码并写入到参数out里面去,输出数据的长度保存在outl 里面。


【EVP_EncodeBlock】

该函数将参数f 里面的字符串里面的n 个字节的字符串进行BASE64编码并输出到参数t 里面。返回数据的字节长度。事实上,在函数EVP_EncodeUpdate 和EVP_EncodeFinal 里面就调用了该函数完成BASE64 编码功能。




openssl 之EVP 系列之15---EVP_Decode 系列函数介绍
---根据自己的理解写成(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl专业论坛,版本:openssl-0.9.7)
本系列函数与EVP_Encode 系列函数相对,对数据进行BASE64 解码。其定义的函数如下(openssl\evp.h):
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,unsigned char *in, int inl);
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);
int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);
【EVP_DecodeInit】
该函数初始化一个用来进行BASE64 解码的数据结构。


【EVP_DecodeUpdate】
该函数将参数in 里面inl 字节的数据拷贝到结构体ctx 里面。如果结构体里面已经有数据,那么这些数据就会先进行BASE64 解码,然后输出到参数out 指向的内存中,输出的字节数保存在参数outl 里面。输入数据为满行的数据时,返回为1;如果输入数据是最后一行数据的时候,返回0;返回-1 则表明出错了。


【EVP_DecodeFinal】
该函数将结构体ctx 里面剩余的数据进行BASE64 解码并输出到参数out 指向的内存中,输出数据长度为outl 字节。成功返回1,否则返回-1。


【EVP_DecodeBlock】
该函数将字符串f 中的n 字节数据进行BASE64 解码,并输出到out 指向的内存中,输出数据长度为outl。成功返回解码的数据长度,返回返回-1。




openssl 之EVP 系列之16---EVP_PKEY 系列函数详解(-)
---根据自己的理解写成(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl专业论坛,版本:openssl-0.9.7)
EVP_PKEY 系列函数定义了一个密钥管理的结构体,其定义如下(openssl\evp.h):


typedef struct evp_pkey_st
{
   int type;
   int save_type;
   int references;
   union
   {
      char *ptr;
       #ifndef OPENSSL_NO_RSA
          struct rsa_st *rsa; /* RSA */
       #endif
      #ifndef OPENSSL_NO_DSA
          struct dsa_st *dsa; /* DSA */
      #endif
      #ifndef OPENSSL_NO_DH
         struct dh_st *dh; /* DH */
      #endif
   } pkey;
   int save_parameters;
    STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
}EVP_PKEY;


该密钥结构既可以用来存储公钥,也可以用来存储私钥。该结构其实是一个在openssl 中很通用的结构,在许多算法中使用了该结构作为存储体。基于该结构定义的EVP_PKEY 系列函数有如下几个常用的:
EVP_PKEY * EVP_PKEY_new(void);
void EVP_PKEY_free(EVP_PKEY *pkey);
int EVP_PKEY_type(int type);
int EVP_PKEY_bits(EVP_PKEY *pkey);
int EVP_PKEY_size(EVP_PKEY *pkey);
这些函数的实现主要在文件evp\p_lib.c 里面,大家如果要看源代码,就可以看该文件了。
下面对这些函数分别进行简单的介绍。


【EVP_PKEY_new】
本函数生成并返回一个EVP_PKEY 结构体,并对该结构体元素进行初始化,如果成功调用返回该结构体的指针,否则返回NULL。因为该函数返回的只是一个空结构体,所以还要使用下面的一些相关函数进行设置,如EVP_PKEY_set1_RSA 之类的函数。


【EVP_PKEY_free】
该函数用来释放EVP_PKEY 结构里面指针指向的内存空间。


【EVP_PKEY_type】
该函数返回输入结构密钥的类型, 目前之支持RSA ( EVP_PKEY_RSA )、DSA(EVP_PKEY_DSA)以及DH(EVP_PKEY_DH)类型的密钥,如果为其它类型,则返回
NID_undef。典型使用方式是EVP_PKEY_type(pkey->type)。


【EVP_PKEY_size】
该函数返回EVP_PKEY 结构中密钥的字节长度,只对RSA 和DSA 类型的密钥有效,如果输入的参数为NULL 或其它密钥类型,则返回0。

【EVP_PKEY_bits】

该函数返回EVP_PKEY 结构中密钥的比特长度,只对RSA 和DSA 类型的密钥有效,如果输入的参数没有初始化或其它密钥类型,则返回0。





openssl 之EVP 系列之17---EVP_PKEY 系列函数详解(二)
---根据自己的理解写成(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl专业论坛,版本:openssl-0.9.7)
接着前面介绍的EVP_PKEY 系列函数,我们这章介绍的函数如下(openssl\evp.h):
int EVP_PKEY_assign(EVP_PKEY *pkey,int type,char *key);
int EVP_PKEY_assign_RSA(EVP_PKEY *pkey,RSA *key);
int EVP_PKEY_assign_DSA(EVP_PKEY *pkey,DSA *key);
int EVP_PKEY_assign_DH(EVP_PKEY *pkey,DH *key);
int EVP_PKEY_set1_RSA(EVP_PKEY *pkey,RSA *key);
int EVP_PKEY_set1_DSA(EVP_PKEY *pkey,DSA *key);
int EVP_PKEY_set1_DH(EVP_PKEY *pkey,DH *key);
RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); int EVP_PKEY_copy_parameters (EVP_PKEY *to,EVP_PKEY *from);
int EVP_PKEY_missing_parameters(EVP_PKEY *pkey);
int EVP_PKEY_save_parameters(EVP_PKEY *pkey,int mode);
int EVP_PKEY_cmp_parameters(EVP_PKEY *a,EVP_PKEY *b);
int EVP_PKEY_decrypt(unsigned char *dec_key,unsigned char *enc_key,int
enc_key_len,EVP_PKEY *private_key);
int EVP_PKEY_encrypt(unsigned char *enc_key,unsigned char *key,int key_
len,EVP_PKEY *pub_key);


【EVP_PKEY_assign】
该函数通过类型参数type 和密钥值key 给初始化了的EVP_PKEY 结构pkey 设置相应的参数,参数key 的内存是直接跟pkey 结构相关在一起的,所以key 的内存在pkey 使用期间不能改变,pkey 被释放的时候,key 也会被自动释放。当pkey 不为NULL 的时候,返回1,否则返回0。


【EVP_PKEY_assign_RSA、EVP_PKEY_assign_DSA 和EVP_PKEY_assign_DH】
这三个函数都是上面的函数EVP_PKEY_assign 函数的宏定义函数,分别完成RSA、DSA以及DH 类型密钥的pkey 结构初始工作。当pkey 不为NULL 的时候,返回1,否则返回0。


【EVP_PKEY_set1_RSA、EVP_PKEY_set1_DSA 和EVP_PKEY_set1_DH】
这三个函数跟上面函数的功能是一样的,只不过用这些函数设置的pkey 释放的时候,key内存不会被释放。openssl 其实在内部做了一中类似于COM 接口的引用技术,计算key 被引用的次数,从而实现了虽然公用内存,但是却能保持内存不被释放的功能。当pkey 不为NULL的时候,返回1,否则返回0。


【EVP_PKEY_get1_RSA、EVP_PKEY_get1_DSA 和EVP_PKEY_get1_DH】
这三个函数返回pkey 结构相应类型的密钥指针,如果pkey 结构里面的密钥类型跟函数类型不一致,则返回NULL。


【EVP_PKEY_copy_parameters】
该函数将参数from 结构体的参数拷贝到参数to 结构体中,如果两个结构体的密钥类型不一样,则不会拷贝任何东西,产生错误提示,返回0;如果from 中没有参数,则产生错误提示返回0。成功执行返回1。该函数只对DSA 类型的密钥有效,其它类型密钥不会执行任何操作。


【EVP_PKEY_missing_parameters】
如果结构pkey 中的参数 p、q 或g 中有一个没有设置,那么该函数就会返回1,否则就返回0。本函数只对DSA 类型密钥有效。其它类型密钥都返回0。


【EVP_PKEY_save_parameters】
该函数也只对DSA 类型密钥有效,如果密钥为DSA 类型,那么参数pkey->save_param eters就会被设置为参数mode 的值。如果要重用该密钥的参数,mode 应该设置为1。唯一用到本函数功能的好象就是X509_PUBKEY_set 函数。成功调用返回pkey 参数原来的保存标志,其它类型密钥则返回0。


【EVP_PKEY_cmp_parameters】
该函数也仅仅对DSA 类型密钥有效,如果两个密钥的参数p、q 和g 都相同,则返回1,否则返回0。如果两个密钥之中有一个或两个都不为DSA 密钥,则返回-1。


【EVP_PKEY_encrypt】
该函数使用公钥pubkey 将密钥key 加密并保存在enc_key 里面,返回输出值的长度。enc_key 分配的内存必须保证能够容下输出的数据。key 参数的长度又参数key_len 指定。
本函数在EVP_SealInit 中被调用了,并且在PEM_SealInit 中也被间接调用了。如果公钥类型不是RSA,那么本函数返回-1。


【EVP_PKEY_encrypt】
跟上述函数相对应,该函数将参数ek 里面的加密密钥用私钥priv 解密并输出到参数key中,返回输出结果的长度。key 的长度也必须足够大,能够容下输出结果。ek 的长度由参数ekl指定。如果私钥不是RSA 类型,那么本函数返回-1。


【说明】
此外,ASN1 还提供了下列4 个函数,在这里不再介绍,等到介绍ASN1 函数再介绍这些函数。


EVP_PKEY * d2i_PublicKey(int type,EVP_PKEY **a, unsigned char **pp,long length);
int i2d_PublicKey(EVP_PKEY *a, unsigned char **pp);
EVP_PKEY * d2i_PrivateKey(int type,EVP_PKEY **a, unsigned char **pp,long length);
EVP_PKEY * d2i_AutoPrivateKey(EVP_PKEY **a, unsigned char **pp, long length);
int i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp);







openssl 之EVP 系列之18---EVP_BytesToKey 函数介绍

---根据doc\crypto\EVP_BytesToKey.pod 翻译和自己的理解写成(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl 专业
论坛,版本:openssl-0.9.7)


该函数定义如下(openssl\evp.h):
int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md,const unsign ed char* salt, const unsigned char *data,int datal, int count,

                                  unsigned char *key,unsigned char *iv);


该函数实现的功能是通过密码口令产生一个加密密钥和初始化向量IV。参数types 是要使用该密钥和IV 的加密算法,类型位EVP_CIPHER。参数md 是要使用的信息摘要算法。
参数salt 是在提取密钥和IV 的时候要使用的盐值,它应该指向一个8 字节的缓存或者NULL,如果是NULL,就不使用盐值。参数data 是包含了datal 个字节数据的缓存,这些数据用来提取密钥数据。参数count 指定了迭代的次数。提取出来的密钥和IV 向量分别保存在参数key 和iv 里面。函数返回生成的密钥的长度。
本函数使用的提取密钥算法是将产生的D_1,D_2,...,D_i,...等数据串连起来,一直计算到数据长度满足了密钥和IV 的长度。

其中D_i 定义如下:
D_i = HASH^count(D_(i-1) || data || salt)这里的符号||表示数据串连,也就是连接起来。初始的D_0 是空的,也就是说长度为0。HASH
是代表使用的信息摘要算法, HASH^1(data) 就是HASH(data) , HASH^2(data) 是HASH(HASH(data)),其它以此类推。串连出来的数据前面的用来做密钥,后面的用来做IV 值。该函数一个典型的应用就是根据参数data 中的口令来为一个加密算法产生加密密钥。增加参数count 会使算法的执行速度下降,但是却使得使用大量备选密码强力破解的黑客行为难度大大增加。如果密钥和IV 的长度比摘要算法的长度短并且使用了MD5 算法,那么该函数使用的算法就跟PKCS#5 v1.5 标志是兼容的。否则,就会使用非标准的扩展方法来产生其它数据。新的应用程序建议应该使用更标准的算法如PKCS#5 v2.0 来提取加密密钥。






openssl 之EVP 系列之19---EVP 提供对口令管理的函数介绍
---根据自己的理解写成(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl 专业论坛,版本:openssl-0.9.7)


EVP 提供的对口令管理的函数有三个,定义如下(openssl\evp.h):
int EVP_read_pw_string(char *buf,int length,const char *prompt,int verify);
void EVP_set_pw_prompt(char *prompt);
char * EVP_get_pw_prompt(void);


【EVP_read_pw_string】
该函数从标准输入终端读入一个口令数据,其中,读入的参数保存在buf 里面,参数的长度保存在length 里面。prompt 参数里面保存的是输出到显示终端的提示语句;如果verify 参数设置为1,那么口令就会被要求输入两次,如果两次输入相同,才会成功返回0,否则就会返回错误1,返回-1 表示发生了系统错误。值得注意的是,由于历史原因,在openssl 里面,该函数的核心代码是在DES 算法里面实现的,所以如果将DES 算法禁止了,该函数的调用也会失败。


【EVP_set_pw_prompt】

该函数设置在调用EVP_read_pw_string 函数的时候缺省的prompt 参数的值,也就是说如果调用EVP_read_pw_string 函数的时候prompt 参数为NULL,那就会使用本函数设置的缺省的值。需要注意的是,本函数设置的缺省值其实是保存在一个静态的数组变量里面,所以如果在Win16 平台使用的时候,可能会出现莫名其妙的现象;在使用多线程程序的时候也必须小心。


【EVP_get_pw_prompt】
该函数返回一个指向缺省prompt 字符串(一个静态变量)的指针,如果该参数没有设置,那么就返回NULL。



openssl 之EVP 系列之20---结束语
(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl 专业论坛,版本:openssl-0.9.7)
openssl 提供的EVP 系列函数,是对openssl 所有各种加密算法做了一个高层的封装,包括了以下几种:
1.对称加密算法(EVP_Encrypt)
2.信息摘要(HASH)算法(EVP_Digest)
3.签名算法(EVP_Sign 和EVP_Verify)
4.公开密钥算法(EVP_Seal 和EVP_Open)
5.BASE64 编码算法(EVP_Encode 和EVP_Decode)
此外,为了提供更加完善的功能,以便实际应用的需要,openssl 的EVP 系列还提供了以下几种辅助功能:
1.不同类型密钥结构的管理(EVP_PKEY)
2.加密密钥和IV 值提取功能(EVP_BytesToKey)
3.口令获取和管理功能
如果能够对EVP 系列函数有一个透彻的了解,那么我们基本上就能的心应手地使用openssl提供的加密函数的功能了。
EVP 系列的介绍已经完成,其中肯定有不少错误和不清楚的地方,希望大家指点.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenSSL中的EVP(Enveloped Data Processing)是一个高级API,提供了一种简单易用的方式来实现各种密码学算法。EVP API支持对称加密、非对称加密、哈希、消息认证码(MAC)和数字签名等功能。 以下是一些使用EVP API的示例: 1. 对称加密 对称加密使用相同的密钥对数据进行加密和解密。以下代码展示了如何使用EVP API进行对称加密: ```c EVP_CIPHER_CTX *ctx; ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv); EVP_EncryptUpdate(ctx, out, &outl, in, inl); EVP_EncryptFinal_ex(ctx, out + outl, &tmpl); EVP_CIPHER_CTX_free(ctx); ``` 其中,key是加密密钥,iv是初始化向量,in是输入数据,inl是输入数据长度,out是输出数据,outl是输出数据长度,tmpl是临时变量。 2. 非对称加密 非对称加密使用公钥加密数据,私钥解密数据。以下代码展示了如何使用EVP API进行非对称加密: ```c EVP_PKEY *pkey; pkey = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pkey, rsa); EVP_PKEY_CTX *ctx; ctx = EVP_PKEY_CTX_new(pkey, NULL); EVP_PKEY_encrypt_init(ctx); EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING); EVP_PKEY_encrypt(ctx, out, &outl, in, inl); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); ``` 其中,rsa是RSA密钥对,in是输入数据,inl是输入数据长度,out是输出数据,outl是输出数据长度。 3. 哈希 哈希函数将任意长度的数据映射为固定长度的摘要值。以下代码展示了如何使用EVP API进行哈希: ```c EVP_MD_CTX *ctx; ctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); EVP_DigestUpdate(ctx, in, inl); EVP_DigestFinal_ex(ctx, out, &outl); EVP_MD_CTX_free(ctx); ``` 其中,in是输入数据,inl是输入数据长度,out是输出数据,outl是输出数据长度。 4. MAC MAC是一种用于验证消息完整性和真实性的技术。以下代码展示了如何使用EVP API进行MAC: ```c EVP_MD_CTX *ctx; ctx = EVP_MD_CTX_new(); EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, pkey); EVP_DigestSignUpdate(ctx, in, inl); EVP_DigestSignFinal(ctx, out, &outl); EVP_MD_CTX_free(ctx); ``` 其中,pkey是私钥,in是输入数据,inl是输入数据长度,out是输出数据,outl是输出数据长度。 5. 数字签名 数字签名是一种用于验证消息来源和完整性的技术。以下代码展示了如何使用EVP API进行数字签名: ```c EVP_MD_CTX *ctx; ctx = EVP_MD_CTX_new(); EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, pkey); EVP_DigestSignUpdate(ctx, in, inl); EVP_DigestSignFinal(ctx, NULL, &slen); EVP_SignFinal(ctx, out, &outl, pkey); EVP_MD_CTX_free(ctx); ``` 其中,pkey是私钥,in是输入数据,inl是输入数据长度,out是输出数据,outl是输出数据长度,slen是临时变量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值