1.关于加密算法的加载
在调用加密算法之前,通过调用OpenSSL_add_all_algorithms来加载加密算法函数和单向散列算法函数
void OpenSSL_add_all_algorithms(void)
{
OpenSSL_add_all_ciphers(); /* 加载加密算法 */
OpenSSL_add_all_digests(); /* 加载单向散列函数 */
}
void OpenSSL_add_all_ciphers(void)函数实现如下:
void OpenSSL_add_all_ciphers(void)
{
EVP_add_cipher(EVP_rc2_cfb());
。。。。。。
PKCS12_PBE_add();
PKCS5_PBE_add();
}
/* 这个过程的主要任务是向全局变量,static LHASH *names_lh,注册加密算法,如果添加了新的加密算法,必需向names_lh注册。 */
由于DES算法接口内容较多,所以我们从IDEA算法的接口开始研究!
#ifndef NO_IDEA
EVP_add_cipher(EVP_idea_ecb()); /*添加EBC加密模式 */
EVP_add_cipher(EVP_idea_cfb()); /*添加CFB加密模式 */
EVP_add_cipher(EVP_idea_ofb()); /*添加OCF加密模式 */
EVP_add_cipher(EVP_idea_cbc()); /*添加CBC加密模式 */
EVP_add_cipher_alias(SN_idea_cbc,"IDEA"); /*添加cbc加密算法的别名 “IDEA” */
EVP_add_cipher_alias(SN_idea_cbc,"idea"); /*添加cbc加密算法的别名 “idea” */
#endif
在包括IDEA加密算法的情况下,OpenSSL将会选择IDAE加密算法模块!
下面来看看EVP_add_cipher函数是怎么实现的,
int EVP_add_cipher(EVP_CIPHER *c)
{
int r;
r=OBJ_NAME_add(OBJ_nid2sn(c->nid),OBJ_NAME_TYPE_CIPHER_METH,(char *)c);
if (r == 0) return(0);
r=OBJ_NAME_add(OBJ_nid2ln(c->nid),OBJ_NAME_TYPE_CIPHER_METH,(char *)c);
return(r);
}
/* 向全决变量names_lh 注册 obj_name_types 变量的过程 */
int OBJ_NAME_add(const char *name, int type, const char *data)
{
OBJ_NAME *onp,*ret;
int alias;
if ((names_lh == NULL) && !OBJ_NAME_init()) return(0);
alias=type&OBJ_NAME_ALIAS;
type&= ~OBJ_NAME_ALIAS;
onp=(OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME));
if (onp == NULL)
{
/* ERROR */
return(0);
}
onp->name=name;
onp->alias=alias;
onp->type=type;
onp->data=data;
ret=(OBJ_NAME *)lh_insert(names_lh,onp);
if (ret != NULL)
{
/* free things */
if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
{
/* XXX: I'm not sure I understand why the free
* function should get three arguments...
* -- Richard Levitte
*/
sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
->free_func(ret->name,ret->type,ret->data);
}
OPENSSL_free(ret);
}
else
{
if (lh_error(names_lh))
{
/* ERROR */
return(0);
}
}
return(1);
}
names_lh 是 LHASH的全局变量,用于维护obj_name_types的类型的变量。(在crypt/objects/o_names.c中定义)
(crypt/objects/obj_dat.h)相关的全局变量
static unsigned char lvalues[2896] 全局变量,已经初始化,存放了OpenSSL所有Object的相关信息。
nid_objs 是ASN1_OBJECT结构的数组全局变量,已经初始化,记录了所有OpenSSL用到的类型的名字
static ASN1_OBJECT *sn_objs[NUM_SN] 全局变量,已经初始化。
static ASN1_OBJECT *ln_objs[NUM_LN] 全局变量,已经初始化。
crypt/object/objects.h 中定义的结构
typedef struct obj_name_st
{
int type;
int alias;
const char *name;
const char *data;
} OBJ_NAME;
注意:crypto/objects 目录下面维护整个OpenSSL模块化的重要的程序,下面逐个做出介绍。
objects.txt 按照一定的语法结构,定义了SN_base, LN_base, NID_base,OBJ_base。经过perl程序objects.pl通过命令perl objects.pl objects.txt obj_mac.num obj_mac.h 处理后,生成了obj_mac.num 和obj_mac.h两个文件。
obj_mac.num 用来查阅 OBJ_base与NID_base之间的对应关系。
obj_mac.h 用来提供c语言类型SN_base, LN_base, NID_base,OBJ_base定义。
objects.h 同样提供了c语言类型SN_base, LN_base, NID_base,OBJ_base定义,在obj_mac.h 更新之后,必须对对应的objects.h 中的内容作出同步,及保持与obj_mac.h的定义一至,同时objects.h中也声明了一些对OBJ_name的操作函数。
objects.h 经过perl程序perl obj_dat.pl objects.h obj_dat.h处理之后,生成obj_dat.h头文件。
obj_dat.h 中定义了如下的全局变量。
#define NUM_NID 393
#define NUM_SN 392
#define NUM_LN 392
#define NUM_OBJ 366
static unsigned char lvalues[2896],
static ASN1_OBJECT nid_objs[NUM_NID],
static ASN1_OBJECT *sn_objs[NUM_SN],
static ASN1_OBJECT *ln_objs[NUM_LN],
static ASN1_OBJECT *obj_objs[NUM_OBJ],
这些变量多有ASN1_OBJECT有关,在objects.txt中定义的所有的对象都会体现出来,具体的作用还不太清楚,需要继续研究!
对OpenSSL中宏的研究
密码算法接口的定义
typedef struct evp_cipher_st EVP_CIPHER;
/* 加密算法后被names_lh来管理,可以通算法的名称或别名来检索 */
struct evp_cipher_st
{
int nid; /*加密算法的nid*/
int block_size; /*数据块的大小 */
int key_len; /* Default value for variable length ciphers */
int iv_len; /* 对于CBC,CFB,OFB的加密算法初始化矢量*/
unsigned long flags; /* Various flags */
int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc); /* init key */
int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, unsigned int inl);/* encrypt/decrypt data */
int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */
int ctx_size; /* how big the ctx needs to be */
int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Populate a ASN1_TYPE with parameters */
int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */
int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Miscellaneous operations */
void *app_data; /* Application data */
};
如果正确定义了EVP_CIPHER变量,这个算法就可以被OpenSSL所接受了。
下面的宏将定义ECB,CBC,CFB,OFB算法EVP_CIPHER定义。
#define BLOCK_CIPHER_defs(cname, kstruct, \
nid, block_size, key_len, iv_len, flags,\
init_key, cleanup, set_asn1, get_asn1, ctrl)\
static EVP_CIPHER cname##_cbc = {\
nid##_cbc, block_size, key_len, iv_len, \
flags | EVP_CIPH_CBC_MODE,\
init_key,\
cname##_cbc_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
set_asn1, get_asn1,\
ctrl, \
NULL \
};\
EVP_CIPHER *EVP_##cname##_cbc(void) { return &cname##_cbc; }\
static EVP_CIPHER cname##_cfb = {\
nid##_cfb64, 1, key_len, iv_len, \
flags | EVP_CIPH_CFB_MODE,\
init_key,\
cname##_cfb_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
set_asn1, get_asn1,\
ctrl,\
NULL \
};\
EVP_CIPHER *EVP_##cname##_cfb(void) { return &cname##_cfb; }\
static EVP_CIPHER cname##_ofb = {\
nid##_ofb64, 1, key_len, iv_len, \
flags | EVP_CIPH_OFB_MODE,\
init_key,\
cname##_ofb_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
set_asn1, get_asn1,\
ctrl,\
NULL \
};\
EVP_CIPHER *EVP_##cname##_ofb(void) { return &cname##_ofb; }\
static EVP_CIPHER cname##_ecb = {\
nid##_ecb, block_size, key_len, iv_len, \
flags | EVP_CIPH_ECB_MODE,\
init_key,\
cname##_ecb_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
(ctx_size 其中有联合的结构,如何获取EVP_CIPHER_CTX数据长度)
set_asn1, get_asn1,\
ctrl,\
NULL \
};\
EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
上面的宏在经过处理之后,变成了四中加密模式的EVP_CIPHER定义,这个结构中封装了加密操作汉书,密钥初始化函数,以及密钥的清理函数。除了实现加密算法之外,还比需实现对应的密钥结构!
EVP_CIPHER_CTX就是密钥结构,完成对加密算法密钥的管理。
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
struct evp_cipher_ctx_st
{
const EVP_CIPHER *cipher;
int encrypt; /* encrypt or decrypt */
int buf_len; /* number we have left */
unsigned char oiv[EVP_MAX_IV_LENGTH]; /* original iv */
unsigned char iv[EVP_MAX_IV_LENGTH]; /* working iv */
unsigned char buf[EVP_MAX_IV_LENGTH]; /* saved partial block */
int num; /* used by cfb/ofb mode */
void *app_data; /* application stuff */
int key_len; /* May change for variable length cipher */
/* 通过联合的方式管理密钥,对各种密钥实现灵活的管理 */
union {
#ifndef NO_RC4
struct
{
unsigned char key[EVP_RC4_KEY_SIZE];
RC4_KEY ks; /* working key */
} rc4;
#endif
#ifndef NO_DES
des_key_schedule des_ks;/* key schedule */
struct
{
des_key_schedule ks;/* key schedule */
des_cblock inw;
des_cblock outw;
} desx_cbc;
struct
{
des_key_schedule ks1;/* key schedule */
des_key_schedule ks2;/* key schedule (for ede) */
des_key_schedule ks3;/* key schedule (for ede3) */
} des_ede;
#endif
#ifndef NO_IDEA
IDEA_KEY_SCHEDULE idea_ks;/* key schedule */
#endif
#ifndef NO_RC2
struct {
int key_bits; /* effective key bits */
RC2_KEY ks;/* key schedule */
} rc2;
#endif
#ifndef NO_RC5
struct {
int rounds; /* number of rounds */
RC5_32_KEY ks;/* key schedule */
} rc5;
#endif
#ifndef NO_BF
BF_KEY bf_ks;/* key schedule */
#endif
#ifndef NO_CAST
CAST_KEY cast_ks;/* key schedule */
#endif
} c;
};
下面的函数用来实现设定加密密钥和解密密钥。
void set_encrypt_key(const unsigned char *key, KEY_SCHEDULE *ks)
void set_decrypt_key(const unsigned char *key, KEY_SCHEDULE *ks)
在这两个函数的基础上实现EVP_CIPHER中密钥初始化函数。
static int init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
if(!enc)
{
if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE) enc = 1;
else if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB_MODE) enc = 1;
}
if (enc)
set_encrypt_key(key,&(ctx->c. ks));
else
{
set_decrypt_key(key,&(ctx->c. ks));
}
return 1;
}
/* 清除保留在内存中的密码 */
static int clean_key(EVP_CIPHER_CTX *ctx)
{
if(ctx)
memset(&(ctx-c.ks),0,sizeof(ctx->c.ks));
return 1;
}
如果加密算法结构EVP_CIPHER是通过BLOCK_CIPHER_defs宏定义的,则四种模式的算法接口必须何处理宏之后的接口一样:
int cname_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
int cname_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
int cname_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
int cname_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
二:四种加密模式的实现
四种加密模式与基本加解密算法之间的关系!
假设加密算法和解密算法的实现函数接口如下
void encrypt(const unsigned char *in, unsigned char *out, const KEY *key, int *length)
void decrypt(const unsigned char *in, unsigned char *out, const KEY *key, int *length)
void ecb_ encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int enc)
{/* 电子密码本: Electronic Code Book */
register int i;
int len = 8;
register long l = length;
unsigned char buf[8];
if(enc)/*encryption*/
{
for(i=0;i<=l;i+=8)
{
encrypt(&in[i], &out[i], key, &len);/*len == 8 will always be true here*/
}
else
{
for(i=0;i<=l;i+=8)
{
decrypt(&in[i], &out[i], key, &len);/*len == 8 will always be true here*/
}
}
}
void cbc_encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int enc)
{/* 密钥分组连接模式 */
register int i;
int len = 8;
register long l = length;
unsigned char buf[8];
if(enc)/*encryption*/
{
for(l-=8; l>=0; l-=8, in+=8, out+=8)
{
for(i=0; i<8;>
buf[i] = in[i] ^ iv[i];
encrypt(buf, iv, key, &len);/*len == 8 will always be true here*/
for(i=0; i<8;>
out[i] = iv[i];
}
/*final block*/
if(l != -8)
{
for(i=0; i
buf[i] = in[i] ^ iv[i];
for(; i<8;>
buf[i] = iv[i];
encrypt(buf, iv, key, &len);/*len == 8 here*/
for(i=0; i<8;>
out[i] = iv[i];
}
/* 加密输出为做下一次得iv ,iv与in异或运算的结果作为加密输入*/
}
else/*decryption*/
{
for(l-=8; l>=0; l-=8, in+=8, out +=8)
{
decrypt(in, buf, key, &len);
for(i=0; i<8;>
out[i] = buf[i] ^ iv[i];
for(i=0; i<8;>
iv[i] = in[i];
}
/*final block*/
if(l != -8)
{
decrypt(in, buf, key, &len);
for(i=0; i
out[i] = buf[i] ^ iv[i];
for(i=0; i<8;>
iv[i] = in[i];
}
}
l = 0;
i = 0;
}
void cfb64_encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int *num, int enc)
{/* 密码反馈模式 */
register long l = length;
unsigned char buf[8];
register int i, save = 0, n = *num;/*start from previously saved processing position*/
int len = 8;
/*restore from previously saved iv*/
for(i=n; i<8;>
buf[i] = iv[i];
if(enc)
{
while(l--)
{
if(n == 0)
{
encrypt(iv, buf, key, &len);
save = 1;
}
*(out++) = iv[n] = *(in++) ^ buf[n];
n = (n+1)&0x07;
}
}
else
{
while(l--)
{
if(n == 0)
{
encrypt(iv, buf, key, &len);
save = 1;
}
*(out++) = (iv[n]=*(in++)) ^ buf[n];
n = (n+1)&0x07;
}
}
if(save)/*store encrypted data into iv for next encryption*/
for(i=n; i<8;>
iv[i] = buf[i];
/* cfb加密输出得结果作为下次得IV, in与加密IV的结果作异或运算的结果作为cfb加密的输出 */
*num = n;/*store current processing position as entry of next encryption*/
save = i = n = 0;
}
void ofb64_encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int *num)
{/* 输出反馈模式 */
register long l = length;
register int i, n = *num;/*start from previously saved processing position*/
int len = 8;
unsigned char buf[8];
/*restore from previously saved iv*/
if(n != 0)
for(i=n; i<8;>
buf[i] = iv[i];
while(l--)
{
if(n == 0)
{
encrypt(iv, buf, key, &len);
for(i=0; i<8;>
iv[i] = buf[i];
}
*(out++) = *(in++) ^ buf[n];
n = (n+1)&0x07; /* n=(n+1)%0x08*/
/* iv加密输出结果作魏下一次iv, iv与in异或运算的结果作为ofb加密输出 */
}
*num = n;/*store current processing position as entry of next encryption*/
i = n = 0;
}
三:如何在SSL协议中添加新的加密算法!
首先,我们来看相关的全局变量 ssl3_ciphers[],在ssl/s3_lib.c中定义
变量的类型定义如下:
typedef struct ssl_cipher_st
{
int valid;
const char *name; /* text name */
unsigned long id; /* id, 4 bytes, first is version */
unsigned long algorithms; /* what ciphers are used */
unsigned long algo_strength; /* strength and export flags */
unsigned long algorithm2; /* Extra flags */
int strength_bits; /* Number of bits really used */
int alg_bits; /* Number of bits for algorithm */
unsigned long mask; /* used for matching */
unsigned long mask_strength; /* also used for matching */
} SSL_CIPHER;
举例来说明
/* Cipher 03 */
{
1,
SSL3_TXT_RSA_RC4_40_MD5, //字符串,在ssl3.h中定义!
SSL3_CK_RSA_RC4_40_MD5, //整形,在ssl3.h中定义
SSL_kRSA|SSL_aRSA|SSL_RC4 |SSL_MD5 |SSL_SSLV3,(在ssl_loal.h中定义)
//密钥交换算法|身份认证算法|加密算法|消息摘要算法|ssl协议版本号
SSL_EXPORT|SSL_EXP40,
0,
40,
128,
SSL_ALL_CIPHERS,
SSL_ALL_STRENGTHS,
},
如果增加了新的加密算法,必须注意定义的所数值是否可用,如果涉及到位与运算,还必须更改相应的掩码!
EVP_CIPHER *ssl_cipher_methods在ssl_ciph中定义,在函数void load_ciphers(void) 中完成对ssl_cipher_methods的初始化工作!
请在这里添加新的加密算法!并且在int ssl_cipher_get_evp(SSL_SESSION *s, const EVP_CIPHER **enc, const EVP_MD **md, SSL_COMP **comp)和static unsigned long ssl_cipher_get_disabled(void)中添加相应的实现算法!