zoukankan      html  css  js  c++  java
  • 在OpenSSL中添加自定义加密算法

    OpenSSL中添加自定义加密算法

     

    1.加密算法的加载

    2.密码算法接口的定义

    3.示例

     

    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_baseOBJ_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_baseNID_base之间的对应关系。

    obj_mac.h 用来提供c语言类型SN_base, LN_base, NID_baseOBJ_base定义。

    objects.h 同样提供了c语言类型SN_base, LN_base, NID_baseOBJ_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 <stdio.h>

    #include "cryptlib.h"

     

    #ifndef OPENSSL_NO_RC4

     

    #include <openssl/evp.h>

    #include <openssl/objects.h>

    #include <openssl/rc4.h>

     

    /* 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测试实例!^_^

  • 相关阅读:
    拦截器
    Mysql修改字段类型,修改字段名
    1.Spring对JDBC整合支持
    由system.currentTimeMillis() 获得当前的时间
    spring 对jdbc的简化
    spring对JDBC的整合支持
    java 运行时异常与非运行时异常理解
    MySQL5.7 的新特点
    基于 SSL 的 Nginx 反向代理
    如何使用 lsyncd 实时同步并执行 shell 命令
  • 原文地址:https://www.cnblogs.com/adylee/p/893436.html
Copyright © 2011-2022 走看看