openssl 之EVP 系列之14---EVP_Encode 系列函数介绍
根据自己的理解写成( 作者: DragonKing, Mail: [email protected] , 发布于: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: [email protected] ,发布于: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: [email protected] ,发布于: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: [email protected] ,发布于: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: [email protected] ,发布于: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: [email protected] ,发布于: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: [email protected] ,发布于: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 系列的介绍已经完成,其中肯定有不少错误和不清楚的地方,希望大家指点.