Chinaunix首页 | 论坛 | 博客
  • 博客访问: 658506
  • 博文数量: 78
  • 博客积分: 4990
  • 博客等级: 上校
  • 技术积分: 1386
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-13 19:25
文章分类

全部博文(78)

文章存档

2010年(6)

2009年(25)

2008年(47)

我的朋友

分类: LINUX

2008-03-30 01:03:18

在OpenSSL中添加自定义加密算法

1.加密算法的加载      1
2.密码算法接口的定义      4
3.示例      8

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注册。 */

以下是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头文件。

我们可以通过在objects.txt中的注册算法OID,就可以使用命令perl objects.pl objects.txt obj_mac.num obj_mac.h来生成自定义算法的一系列声明.
以下是我们添加的算法
在其中添加一行条目
rsadsi 3 255   : SSF33   : ssf33
分别生成以下声明
obj_dat.h:780:0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x81,0x7F,/* [5001] OBJ_ssf33 */
obj_dat.h:1949:{"SSF33","ssf33",NID_ssf33,9,&(lvalues[5001]),0},
obj_dat.h:3418:&(nid_objs[751]),/* "ssf33" */
obj_dat.h:3958:&(nid_objs[751]),/* OBJ_ssf33                 1 2 840 113549 3 255 */
objects.txt:1046:rsadsi 3 255   : SSF33       : ssf33
obj_mac.h:3294:#define SN_ssf33       "SSF33"
obj_mac.h:3295:#define LN_ssf33       "ssf33"
obj_mac.h:3296:#define NID_ssf33           751
obj_mac.h:3297:#define OBJ_ssf33           OBJ_rsadsi,3L,255L
obj_mac.num:751:ssf33       751

2.密码算法接口的定义
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;
};

3.示例
熟悉了这些结构,我们就可以通过这些ssf33的算法的申明添加自定义算法了,这里我们以RC4算法为模板只是修改名字来创建我们的算法.
在crypto\evp\下添加e_ssf33.c,内容如下
#include
#include "cryptlib.h"

#ifndef OPENSSL_NO_RC4

#include
#include
#include

/* FIXME: surely this is available elsewhere? */
#define EVP_SSF33_KEY_SIZE     16

typedef struct
  {
  RC4_KEY ks; /* working key */
  } EVP_SSF33_KEY;

#define data(ctx) ((EVP_SSF33_KEY *)(ctx)->cipher_data)

static int ssf33_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
        const unsigned char *iv,int enc);
static int ssf33_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
        const unsigned char *in, unsigned int inl);
static const EVP_CIPHER ssf33_evp_cipher=
  {
  NID_ssf33,
  1,EVP_SSF33_KEY_SIZE,0,
  EVP_CIPH_VARIABLE_LENGTH,
  ssf33_init_key,
  ssf33_cipher,
  NULL,
  sizeof(EVP_SSF33_KEY),
  NULL,
  NULL,
  NULL,
  NULL
  };
const EVP_CIPHER *EVP_ssf33(void)
  {
  return(&ssf33_evp_cipher);
  }

static int ssf33_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
        const unsigned char *iv, int enc)
  {
  RC4_set_key(&data(ctx)->ks,EVP_CIPHER_CTX_key_length(ctx),
        key);
  return 1;
  }

static int ssf33_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
        const unsigned char *in, unsigned int inl)
  {
  RC4(&data(ctx)->ks,inl,in,out);
  return 1;
  }
#endif
接下来在evp.h中添加对算法的声明
evp.h:const EVP_CIPHER *EVP_ssf33(void);
这样我们只要在c_allc.c文件中修改OpenSSL_add_all_ciphers函数,使用EVP_add_cipher注册加密函数就可以了.
EVP_add_cipher(EVP_ssf33());
就可以使用此函数了!可以通过evp_test测试实例!

以上是我的经验,拿出来与大家分享!
^_^
阅读(2045) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~