openssl相关数据结构的设计

hash表

数据结构:使用链表数组实现

typedef struct lhash_node_st{
    void* data;
    struct lhash_node_st *next;
#ifndef OPENSSL_NO_HASH_COMP
    unsigned long hash;
#endif
}LHASH_NODE;

typedef struct lhash_st{
    LHASH_NODE **b;//整个hash表维护一个链表数组
    LHASH_COMP_FN_TYPE comp;//数据查找的比较函数句柄
    LHASH_HASH_FN_TYPE hash;//用于存放计算hash值函数的地址?
    unsigned int num_nodes;//当前节点数量
    unsigned int num_all_nodes;//节点容量
    unsigned int p;
    unsigned int pmax;
    unsigned long up_load;/*load times 256*/
    unsigned long down_load;/*load times 256*/
    unsigned long num_items;
    unsigned long num_expands;
    unsigned long num_expand_reallocs;
    unsigned long num_contracts;
    unsigned long num_constract_reallocs;
    unsigned long  num_hash_calls;
    unsigned long num_comp_calls;
    unsigned long num_insert;
    unsigned long num_replace;
    unsigned long num_delete;
    unsigned long num_no_delete;
    unsigned long num_retrieve;
    unsigned long num_retrieve_miss;
    unsigned long num_hash_comps;
    int error;
}LHASH;

相关接口

- LHASH *lh_new(LHASH_HASH_FN_TYPE h,LHASH_COMP_FN_TYPE c);
- void *lh_delte(LHASH *lh, const void *data);
- void *lh_doall(LHASH *lh, LHASH_DOALL_FN_TYPE func);
- void *lh_insert(LHASH *lh, void *data);
- void *lh_retrieve(LHASH *lh, const void *data);

内存分配

内存相关数据结构

typedef struct app_mem_info_st{
    unsigned long thread;
    const char *file;
    int line;
    cosnt char *info;
    struct app_mem_info_st *next;
    int references;
    
}APP_INFO;

typedef struct mem_st{
    void *addr;//分配内存的地址
    int num;//分配内存的大小
    const char *file;//分配内存映射的文件
    int line;//分配内存的行号??
    unsigned long thread;//分配内存的线程ID
    unsigned long order;//第几次分配内存
    time_t time;//内存分配时间
    APP_INFO *app_info;//链表。存放用户应用信息,如文件、行号、以及其他
    unsigned int references;//被引用次数
}MEM;

内存操作相关接口

  • CRYPTO_mem_ctrl:控制内存分配时是否记录内存信息,用于查找内存泄漏
  • CRYPTO_is_mem_check_on:检查内存信息记录是否打开
  • CRYPTO_dbg_malloc:用于分配内存
  • CRYPTO_dbg_free:用于释放内存
  • CRYPTO_mem_leaks:将内存泄漏输出到BIO(后面会介绍)
  • CRYPTO_mem_leaks_fp:将内存泄露输出到文件中
  • CRYPTO_mem_leaks_cb:设定自定义内存泄漏处理的回调函数

抽象IO(BIO)

对于io类型的抽象封装,包括:内存、文件、日志、标准输入输出、socket(TCP/UDP)、加解密、摘要、ssl通道等。通过回调函数隐藏了底层的实现细节,所有类型的bio的调用大体上是类似的。BIO中的数据从一个BIO传送到另外一个BIO或者是应用程序。

数据结构

BIO_METHOD:定义各种回调函数,这是一种抽象接口的封装,具体bio对象会实现这些接口的一个子集。
typedef struct bio_method_st{
    int type;
    const char *name;
    int (*bwrite)(BIO *, const char *, int);
    int (*bread)(BIO*, char *, int);
    int (*bputs))BIO *, const char *);
    int (bgets)(BIO *, char *, int);
    int (*ctrl)(BIO *, int, long, void *);
    int (*create)(BIO *);
    int (*destroy)(BIO *);
    long (*callback_ctrl)(BIO *, int, bio_info_cb *);
}BIO_METHOD;

bio_st:实际使用的bio的类
struct bio_st{
    BIO_METHOD *method;
    long (*callback)(struct bio_st *, const char *, int, long, long);
    char *cb_arg;/*回调函数的第一个参数*/
    int init;//句柄初始化标记
    int shutdown;//关闭
    int retry_reason;//socket和ssl BIO中的异步阻塞时重试
    int num;//针对具体BIO而异
    void *ptr;//具体BIO的相关信息
    struct bio_st *next_bio;
    struct bio_st *prev_bio;
    int references;
    unsigned long num_read;//读取的字节数
    unsigned long num_write;//写入的字节数
    CRYPTO_EX_DATA ex_data;//用于存放额外数据
};

相关接口
  • BIO_new:生成一个bio,参数为类型,比如BIO_s_mem(),初始化bio_st的各种参数
  • BIO_new_file:获取新bio,file可以是各种文件类型,针对不同的文件类型,传入的参数不一样,传入的参数一般是原始文件描述符,如BIO_new_socket获取套接字,传入的是监听套接字
  • BIO_get_fd:设置网络链接,获取socket
//服务器端
sock=BIO_get_accept_socket("2323",0); //获取一个监听的套接字描述符
sbio=BIO_new_socket(sock, BIO_NOCLOSE); //生成一个套接字的bio(被重新设置过的)
ret=BIO_accept(sock,&addr); //从监听的套接字上获取到达的连接请求,并生成新的带有本地标识的客户端描述符
BIO_set_fd(sbio,ret,BIO_NOCLOSE);//将客户端描述符绑定在BIO上,接下来的读取,写入,释放都在此处理
//客户端:
cbio=BIO_new_connect("localhost:http");//用于生成建立连接到本地web服务的BIO
out=BIO_new_fp(stdout,BIO_NOCLOSE);//生成一个输出到屏幕的BIO
//验证连接
if(BIO_do_connect(cbio) <= 0) 
{ 
  fprintf(stderr, "Error connecting to server\n"); 
} 
//发送请求
BIO_puts(cbio, "GET / HTTP/1.0\n\n"); 
for(;;) 
{ 
  len = BIO_read(cbio, tmpbuf, 1024); //从cbio读出到缓存
  if(len <= 0) break; 
  BIO_write(out, tmpbuf, len); //从缓存输出到屏幕
} 
BIO_free(cbio); 
BIO_free(out); 
return 0;
  • BIO_read,BIO_write等对bio的操作

openssl随机数

openssl使用摘要算法来生成随机数。其维护一个内部随机状态数据,通过这些内部数据计算摘要生成随机数。

数据结构

/crypto/rand.h

struct rand_meth_st{
  void (*seed)(const void *buf, int num);//进一步随机化
  int (*bytes)(unsigned char *buf, int num);//生成随机数
  void (*cleanup)(void);//清除函数
  void (*add)(const void *buf, int num, double entropy);//与seed类似,使之更加无序
  int (*pseudorand)(unsigned char *buf, int num);//也是生成随机数,但是做更精细的控制
  int (*status)(void);
}

在同级目录下的主要源码

  • md_rand.c:实现基于摘要的随机数生成
  • rand_lib.c:简单调用了rand_meth中的回调函数
  • rand_win.c/rand_unix.c/rand_os2.c:提供平台相关的RAND_poll函数实现和其他系统特有函数的实现
  • randfile.c:用于从随机文件中加载随机种子等

主要函数

  • int RAND_load_file(const char *file, long bytes):本函数将file指定的随机数文件中的数据读取bytes字节,调用RAND_add进行计算,生成内部随机数
  • RAND_write_file:生成一个随机数文件
  • const char *RAND_file_name(char *file, size_t num):获取随机数文件名,如果随机数文件长度小于num则返回空,否则返回文件名
  • RAND_poll:计算内部随机数,各个平台都有各自的实现
  • RAND_screen/RAND_event:windows特有函数,用来计算内部随机数,其调用了RAND_seed
  • RAND_seed/RAND_add:计算随机数
  • RAND_bytes/RAND_pseudo_bytes:用来计算随机数
  • RAND_cleanup:清除内部随机数
  • RAND_set_rand_method:设置rand_meth,自定义设置
  • RAND_status:用来查看内部随机数熵值是否已到达预定值,如果没有就不生成随机数

BASE64编解码

BASE64是一种常见的将16进制数据转化为可见字符的编码。于ASCII码相比,它占用的空间较小。

编码原理

将数据编码成BASE64编码时,以三字节为一组,转换为24bit的二进制数,将24bit的二进制分为四组,每组6bit。对于每一组,得到一个数字0-63。然而根据这个数字查表即可以得到相应的字符

  • 不够24bit时,在右边用零填充,转化为“=”,解码时直接去掉即可

接口

编码接口
  • EVP_EncodeInit:编码前初始上下文
  • EVP_EncodeUpdate:编码,可多次调用
  • EVP_EncodeFinal:编码并输出结果
  • EVP_EncodeBlock:编码
解码接口
  • EVP_DecodeInit 解码前初始化上下文。
  • EVP_DecodeUpdate BASE64解码,本函数可多次调用。
  • EVP_DecodeFinal BASE64解码,并输出结果。
  • EVP_DecodeBlock BASE64解码,可单独调用。

摘要与HMAC

摘要将任意数据通过计算获取唯一对应值。它是一种多对一的关系。主要用于网络安全领域的身份验证于签名。常见的摘要算法有:sha、sha1、sha256以及md5等

摘要的实现

crypto/目录下存放着各种摘要的源代码

函数说明

  • xxx_Init:初始化上下文,用于多数据摘要
  • xxx_Update:摘要算法的名称,进行摘要计算,可运行多次
  • xxx_final:摘要算法的名称
  • xxx:对一个数据进行摘要,该函数由上述三个函数实现

HMAC

HMAC用于保护消息的完整性,它采用摘要算法对消息、填充、以及秘密进行混合运算。用户将其和消息一并发出去,接收方收到数据进行相同的运算然后对比发来的hmac,验证数据是否被篡改

数据压缩

RSA

RSA算法是一个广泛使用的公钥算法。其密钥包含公钥和私钥。它能用于数字签名、身份认证以及密钥交换。rsa密钥长度一般为1024或者更高。

RSA的组成

  • n:模数
  • e:公钥指数
  • d:私钥指数
  • p:最初的大素数
  • q:最初的大素数
  • dmp1:e*dmp1 = 1 (mod (p-1))
  • dmq1:e*dmq1 = 1 (mod (q-1))
  • iqmp:q*iqmp = 1 (mod p )
    其中公钥为n和e,私钥为n和d;在实际应用中,公钥加密一般用来协商密钥;私钥加密用于签名,供对方验证发送方身份的合法性,防止中间人攻击

openssl的rsa实现

数据结构
struct rsa_meth_st{
    const char *name;
    int (*rsa_pub_enc)(int flen, const unsigned char* from, unsigned char *to, RSA *rsa, int padding);
    int (*rsa_pub_dec)(int flen, const unsigned char* from, unsigned char *to, RSA *rsa, int padding);
    int (*rsa_priv_enc)(int flen,const unsigned char *from, unsigned char *to, RSA *rsa, int padding); 
    int (*rsa_priv_dec)(int flen,const unsigned char *from,unsigned char  *to, RSA *rsa, int padding);
    int (*rsa_sign)(int type,const unsigned char *m, unsigned int m_length,unsigned char *sigret, unsigned int *siglen, const RSA *rsa); 
    int (*rsa_verify)(int dtype,const unsigned char *m, unsigned int m_length,unsigned char *sigbuf, unsigned int siglen, const RSA *rsa); 
    int (*rsa_keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); 
};

struct rsa_st{
  const RSA_METHOD *meth;
  ENGINE *engine;
  BIGNUM *n;
  BIGNUM *e;
  BIGNUM *d;
  BIGNUM *p
  BIGNUM *q;
  BIGNUM *dmp1;
  BIGNUM *dmq1;
  BIGNUM *iqmp;
  CRYPTO_EX_DATA ex_data;
  int references
  ...
}
主要接口

1)RSA_check_key
检查RSA密钥。
2)RSA_new
生成一个RSA密钥结构,并采用默认的rsa_pkcs1_eay_meth RSA_METHOD方法。
3)RSA_free
释放RSA结构。

  1. RSA RSA_generate_key(int bits, unsigned long e_value,
    void (
    callback)(int,int,void *), void *cb_arg)
    生成RSA密钥,bits是模数比特数,e_value是公钥指数e,callback回调函数由用户
    实现,用于干预密钥生成过程中的一些运算,可为空。
    5) RSA_get_default_method
    获取默认的RSA_METHOD,为rsa_pkcs1_eay_meth。 6) RSA_get_ex_data
    获取扩展数据。
    7) RSA_get_method
    获取RSA结构的RSA_METHOD。 8) RSA_padding_add_none
    RSA_padding_add_PKCS1_OAEP
    RSA_padding_add_PKCS1_type_1(私钥加密的填充)
    RSA_padding_add_PKCS1_type_2(公钥加密的填充)
    RSA_padding_add_SSLv23
    各种填充方式函数。
    9) RSA_padding_check_none
    RSA_padding_check_PKCS1_OAEP
    RSA_padding_check_PKCS1_type_1
    RSA_padding_check_PKCS1_type_2
    RSA_padding_check_SSLv23
    RSA_PKCS1_SSLeay
    各种去除填充函数。
    10)int RSA_print(BIO *bp, const RSA *x, int off)
    将RSA信息输出到BIO中,off为输出信息在BIO中的偏移量,比如是屏幕BIO,则表示打印
    信息的位置离左边屏幕边缘的距离。
    11)int DSA_print_fp(FILE *fp, const DSA *x, int off)
    将RSA信息输出到FILE中,off为输出偏移量。
    12)RSA_public_decrypt
    RSA公钥解密。
    13)RSA_public_encrypt
    RSA公钥加密。
    14)RSA_set_default_method/ RSA_set_method
    设置RSA结构中的method,当用户实现了一个RSA_METHOD时,调用此函数来设置,使
    RSA运算采用用户的方法。
    15)RSA_set_ex_data
    设置扩展数据。
    16)RSA_sign
    RSA签名。
    17)RSA_sign_ASN1_OCTET_STRING
    另外一种RSA签名,不涉及摘要算法,它将输入数据作为ASN1_OCTET_STRING进行DER
    编码,然后直接调用RSA_private_encrypt进行计算。
    18)RSA_size
    获取RSA密钥长度字节数。
    19)RSA_up_ref
    给RSA密钥增加一个引用。
    20)RSA_verify
    RSA验证。
    21)RSA_verify_ASN1_OCTET_STRING
    另一种RSA验证,不涉及摘要算法,与RSA_sign_ASN1_OCTET_STRING对应。
    22)RSAPrivateKey_asn1_meth
    获取 RSA 私钥的 ASN1_METHOD,包括 i2d、d2i、new 和 free 函数地址。
    23)RSAPrivateKey_dup
    复制RSA私钥。
    24)RSAPublicKey_dup
    复制RSA公钥。

未完待续。。。

数字签名算法(DSA)

DH算法(通信双方进行密钥协商的协议)

https工作全流程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267