IT点滴

我不去想是否能够成功 既然选择了远方 便只顾风雨兼程
  博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

OpenSSL对称加密算法中如何添加新算法

Posted on 2007-09-20 07:07  Ady Lee  阅读(1471)  评论(0编辑  收藏  举报
 

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)中添加相应的实现算法!