RSA基本结构
struct
2.初始化函数
RSA * RSA_new(void);初始化一个RSA结构
3.RSA私钥产生函数
RSA *RSA_generate_key(int num, unsigned long e,void (*callback)(int,int,void *), void *cb_arg);产生一个模为num位的密钥对,e为公开的加密指数,一般为65537(ox10001),假如后两个参数不为NULL,将有些调用。在产生密钥对之前,一般需要指定随机数种子
4.判断位数函数
5.RSA的RSA_METHOD函数
typedef struct rsa_meth_st
const RSA_METHOD *RSA_PKCS1_SSLeay(void);
const RSA_METHOD *RSA_null_method(void);
主要有上面两个函数。第二个函数是定义了RSA_null才会调用,其实要调用这个函数以后几乎什么都不能干,只是输出错误信息。第一个是常用的 METHOD,下面我们看看它的定义
const RSA_METHOD *RSA_PKCS1_SSLeay(void)
static RSA_METHOD rsa_pkcs1_eay_meth={
由此可以看出,一般rsa->meth-> rsa_pub_enc对应于RSA_eay_public_encrypt,刚开始看openssl的时候最难得就是这个指向函数的指针,根本不知道 rsa->meth-> rsa_pub_enc对应于哪里。在openssl里面这种指针很多,到以后也能够看到。下面是设置meth的一些函数应该都很容易理解
void RSA_set_default_method(const RSA_METHOD *meth);
6.加解密函数
int RSA_public_encrypt(int flen, unsigned char *from,
unsigned char *to, RSA *rsa,int padding);
RSA_set_method(rsa, RSA_PKCS1_SSLeay())的话,那RSA_public_encrypt对应于RSA_eay_public_encrypt,这样我们就可以调试公钥加密的过程了。Flen为要加密信息的长度,from为需要加密的信息,to为加密后的信息,一般to至少要申请 BN_num_bytes(rsa->n)大的空间。Padding是采取的加解密方案。PKCS#1中主要提供了两种加密方案,RSAEX- OAEP和PSAES-PKCS1-v1_5(反正就是两种加密过程了,有点复杂,它主要是先对先对需要加密的数据进行了编码,比如RSAES-OAEP
采用EME-OAEP编码,再进行加密或解密)。Openssl中已经编好了编码的函数:
case RSA_PKCS1_PADDING:
#ifndef OPENSSL_NO_SHA
case RSA_PKCS1_OAEP_PADDING:
#endif
case RSA_SSLV23_PADDING:
等上面编好码后,就调用BN_mod_exp_mont来进行模幂了。最后得出值,这也就是具体的加密和解密过程。在这里还可以发现,加密时输入的rsa 有两种方式,一是p,q,...为NULL,只有rsa->d,和rsa->n不为空,这样就直接用rsa->d和rsa->n 进行模幂计算,假如p,q.....都不为空的话,他会调用中国剩余定理来进行加密。
7.签名函数
int RSA_sign(int type, unsigned char *m, unsigned int m_len,
int RSA_verify(int type, unsigned char *m, unsigned int m_len,
其实签名其实和用私钥加密差不多是一回事,所以签名函数最终调用的就是私钥加密的函数,在openssl中这个签名函数很少单独拿出来用的,都是为了给 EVP_SignFinal来调用的。所以假如是利用RSA进行签名的话,RSA_private_encrypt,BN_mod_exp_mont是最基本的,所有的都需要调用他,区别无非就在于在需要签名的信息上做了一下处理(一般将需要签名的信息求取摘要值得到m)
8.写入文件函数
9.其他
int RSA_blinding_on(RSA *rsa, BN_CTX *ctx);
void RSA_blinding_off(RSA *rsa);
为了防止时间攻击,openssl还在签名的时候产生一个随机因子,附加在私钥上。
用私钥对八元组串进行签名,原理同RSA_sign
Openssl有关大数运算函数介绍- -
主要介绍Openssl中的有关大数运算函数,这个对于以后的RSA研究和实现比较有价值
1.初始化函数
BIGNUM *BN_new(void);
void BN_free(BIGNUM *a);
void BN_init(BIGNUM *);
void BN_clear(BIGNUM *a);
void BN_clear_free(BIGNUM *a); 相当与将BN_free和BN_clear综合,要不就赋值0,要不就释放空间。
2.上下文情景函数,存储计算中的中间过程
BN_CTX *BN_CTX_new(void);申请一个新的上下文结构
void BN_CTX_init(BN_CTX *c);将所有的项赋值为0,一般BN_CTX_init(&c)
3.复制以及交换函数
4.取位函数
5.基本计算函数
6.比较函数
7.设置函数
8.随机数函数
int BN_rand_range(BIGNUM *rnd, BIGNUM *range);产生的0<rnd<range
9.产生素数函数
BIGNUM *BN_generate_prime(BIGNUM *ret, int bits,int safe, BIGNUM *add,
判断是否为素数,返回0表示成功,1表示错误概率小于0。25,-1表示错误
10.位数函数
11.与字符串的转换函数
int BN_bn2bin(const BIGNUM *a, unsigned char *to);将abs(a)转化为字符串存入to,to的空间必须大于BN_num_bytes(a)
12.其他函数
下面函数可以进行更有效率的模乘和模除,假如在重复在同一模下重复进行模乘和模除计算,计算r=(a*b)%m 利用了recp=1/m
BN_RECP_CTX *BN_RECP_CTX_new(void);
下面函数采用蒙哥马利算法进行模幂计算,可以提高效率,他也主要应用于在同一模下进行多次幂运算
BN_MONT_CTX *BN_MONT_CTX_new(void);
基于OpenSSL的程序都要遵循以下几个步骤:
(1 ) OpenSSL初始化在使用OpenSSL之前,必须进行相应的协议初始化工作,这可以通过下面的函数实现:
int SSL_library_int(void);
(2 ) 选择会话协议
在利用OpenSSL开始SSL会话之前,需要为客户端和服务器制定本次会话采用的协议,目前能够使用的协议包括TLSv1.0、SSLv2、 SSLv3、SSLv2/v3。
需要注意的是,客户端和服务器必须使用相互兼容的协议,否则SSL会话将无法正常进行。
(3 ) 创建会话环境
在OpenSSL中创建的SSL会话环境称为CTX,使用不同的协议会话,其环境也
不一样的。申请SSL会话环境的OpenSSL函数是:
SSL_CTX *SSL_CTX_new(SSL_METHOD * method);
当SSL会话环境申请成功后,还要根据实际的需要设置CTX的属性,通常的设置是指定SSL握手阶段证书的验证方式和加载自己的证书。制定证书验证方式的函数是:
int SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int(*verify_callback),int(X509_STORE_CTX *));
为SSL会话环境加载CA证书的函数是:
SSL_CTX_load_verify_location(SSL_CTX *ctx,const char *Cafile,const char *Capath);
为SSL会话加载用户证书的函数是:
SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file,int type);
为SSL会话加载用户私钥的函数是:
SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx,const char* file,int type);
在将证书和私钥加载到SSL会话环境之后,就可以调用下面的函数来验证私钥和证书是否相符:
int SSL_CTX_check_private_key(SSL_CTX *ctx);
(4) 建立SSL套接字
SSL套接字是建立在普通的TCP套接字基础之上,在建立SSL套接字时可以使用下面的一些函数:
SSL *SSl_new(SSL_CTX *ctx);
//申请一个SSL套接字
int SSL_set_fd(SSL *ssl,int fd);)
//绑定读写套接字
int SSL_set_rfd(SSL *ssl,int fd);
//绑定只读套接字
int SSL_set_wfd(SSL *ssl,int fd);
//绑定只写套接字
(5) 完成SSL握手
在成功创建SSL套接字后,客户端应使用函数SSL_connect( )替代传统的函数connect( )来完成握手过程:
int SSL_connect(SSL *ssl);
而对服务器来讲,则应使用函数SSL_ accept ( )替代传统的函数accept ( )来完成握手过程:
int SSL_accept(SSL *ssl);
握手过程完成之后,通常需要询问通信双方的证书信息,以便进行相应的验证,这可以借助于下面的函数来实现:
X509 *SSL_get_peer_certificate(SSL *ssl);
该函数可以从SSL套接字中提取对方的证书信息,这些信息已经被SSL验证过了。
X509_NAME *X509_get_subject_name(X509 *a);
该函数得到证书所用者的名字。
(6) 进行数据传输
当SSL握手完成之后,就可以进行安全的数据传输了,在数据传输阶段,需要使用SSL_read( )和SSL_write( )来替代传统的read( )和write( )函数,来完成对套接字的读写操作:
int SSL_read(SSL *ssl,void *buf,int num);
int SSL_write(SSL *ssl,const void *buf,int num);
(7 ) 结束SSL通信
当客户端和服务器之间的数据通信完成之后,调用下面的函数来释放已经申请的SSL资源:
int SSL_shutdown(SSL *ssl);
//关闭SSL套接字
void SSl_free(SSL *ssl);
void SSL_CTX_free(SSL_CTX *ctx);
//释放SSL会话环境
本文详细介绍了RSA加密算法的基本结构、初始化、生成私钥、位数判断、RSA_METHOD函数、加解密函数、签名函数、文件写入函数、其他函数以及与字符串的转换函数等内容。同时,阐述了基于OpenSSL的程序实现步骤,包括SSL初始化、协议选择、创建会话环境、建立SSL套接字、完成SSL握手、进行数据传输和结束SSL通信。
2936





