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结构。
- 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公钥。
未完待续。。。