hello world!
分类: LINUX
2012-04-25 16:30:37
不同于对称加密算法中加密和解密使用同样的密钥,公钥算法分为加密密钥K1和解密密钥K2两部分,而且从K1很难计算推导出K2。这样就可以保密K2而公布K1,从而大大简化了密钥管理。习惯上K1称为公钥,K2称为私钥。
加密使用公钥,解密使用私钥。
ENC(P,K1)= C
DEC(C,K2)= P
RSA加密算法的步骤是这样的:
(1) 找两个随机大素数p和q;
(2) 计算模n=pq和Euler函数φ(n) =(p-1)(q-1);
(3) 选取数e后用扩展Euclid算法求数d满足ed≡1 mod φ(n);
(4) 保密私钥K2=(d, n),发布公钥K1=(e, n);
(5) 加密明文p时,计算密文c = p^e mod n;
(6) 解密c时,计算p = c^d mod n。
RSA算法也可以用来签名:
(7) 对消息m,其签名s = m^d mod n;
(8) 验证(m,s)即判断m =? s^e mod n。
下面介绍OpenSSL中RSA算法的函数接口。
RSA密钥产生
RSA密钥产生函数RSA_generate_key(),需要指定模长比特数bits和公钥指数e。另外两个参数为NULL即可。
RSA * RSA_generate_key(int bits, unsigned long e, void (*callback) (int,int,void *),void *cb_arg);
目前对于长达663比特的RSA模数已经有成功分解的先例,因此当前典型的应用场合使用1024比特模长的RSA算法,此时一个分组是128字节。
如果从文件中读取密钥,可使用函数PEM_read_bio_PrivateKey()/ PEM_read_bio_PUBKEY(),其中EVP_PKEY 中包含一个RSA结构,可以引用。
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
RSA加密和解密
RSA加密函数RSA_public_encrypt()使用公钥部分,解密函数RSA_private_decrypt()使用私钥。填充方式常用的有两种RSA_PKCS1_PADDING和RSA_PKCS1_OAEP_PADDING。出错时返回-1。输入必须比RSA钥模长短至少11个字节(在RSA_PKCS1_PADDING时?)。输出长度等于RSA钥的模长。
int RSA_public_encrypt(int flen, const unsigned char *from,unsigned char *to, RSA *rsa,int padding);
int RSA_private_decrypt(int flen, const unsigned char *from,unsigned char *to, RSA *rsa,int padding);
RSA签名和验证
签名使用私钥,验证使用公钥。RSA签名操作是把被签署消息的散列值编码后用私钥加密,因此函数中参数type用来指示散列函数的类型,一般是NID_md5或NID_sha1。正确情况下返回0。
int RSA_sign(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, RSA *rsa);
int RSA_verify(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
-------------------------rsa 签名和验证例子
// demo how to sign a piece of data
// by Linden 23:49 2003-4-23
#include
#include
#include
main()
{
#define RSA_KEY_FILE "rsakey.txt"
// > openssl genrsa -out rsakey.txt 1024
RSA* key;
char msg[]="i, i have no data to sign";
unsigned char md[16]; // md5's len
unsigned char sig[128]; // 1024/8
int siglen = sizeof(sig);
int r;
//SSL_library_init();
//SSL_load_error_strings();
//OpenSSL_add_all_algorithms();
key = RSA_new();
#if 1 // gen
puts("genrsa...(maybe a few seconds)");
key = RSA_generate_key(1024, 65537, NULL, NULL);
puts("ok");
#else // read in
{
#if 0 // 曾经ok过吗?忘了
FILE *fp = fopen(RSA_KEY_FILE, "r");
key = PEM_read_RSAPrivateKey(fp, &key, NULL, NULL);
#else
int i;
EVP_PKEY* k;
BIO *in = BIO_new(BIO_s_file_internal());
i = BIO_read_filename(in, RSA_KEY_FILE);
if (i<=0) puts("read key file err");
else
k = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
key = RSAPrivateKey_dup(k->pkey.rsa);
EVP_PKEY_free(k);
BIO_free(in);
#endif
}
#endif
#if 0 // display. there's err
{
//BIO *o = BIO_new_fd(fileno(stdout), BIO_NOCLOSE);
BIO *o = BIO_new(BIO_s_file());
RSA_print(o, key, 0);
BIO_free(o);
}
#endif
//int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
// unsigned char *sigret, unsigned int *siglen, RSA *rsa);
MD5(msg, strlen(msg), md);
r = RSA_sign(NID_md5, md, sizeof(md), sig, &siglen, key);
if (!r)
puts("error in sign");
#if 0
sig[0]++; // 假想的错误
#endif
//int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
// unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
r = RSA_verify(NID_md5, md, sizeof(md), sig, siglen, key);
if (!r)
puts("error in verify");
puts("is there errs? no? ok!");
RSA_free(key);
return 0;
}
-----------------------rsa 加解密例子
// demo how to enc a piece of data using RSA
// by Linden 0:23 2003-11-15
#include
#include
#include
#include
#pragma comment(lib,"libeay32.lib")
#pragma comment(lib,"ssleay32.lib")
#if 0
main()
{
#define RSA_KEY_FILE "rsakey.txt"
// > openssl genrsa -out rsakey.txt 1024
RSA* key;
char msg[]="i, i have no data to enc";
char msg2[256];
char msg3[256];
int r;
//SSL_library_init();
//SSL_load_error_strings();
//OpenSSL_add_all_algorithms();
//key = RSA_new();
#if 1 // gen
puts("genrsa...(maybe a few seconds)");
key = RSA_generate_key(1024, 65537, NULL, NULL);
puts("ok");
#else // read in
{
#if 0 // 曾经ok过吗?忘了
FILE *fp = fopen(RSA_KEY_FILE, "r");
key = PEM_read_RSAPrivateKey(fp, &key, NULL, NULL);
#else
int i;
EVP_PKEY* k;
BIO *in = BIO_new(BIO_s_file_internal());
i = BIO_read_filename(in, RSA_KEY_FILE);
if (i<=0) puts("read key file err");
else
k = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
key = RSAPrivateKey_dup(k->pkey.rsa);
EVP_PKEY_free(k);
BIO_free(in);
#endif
}
#endif
#if 0 // display. there's err
{
//BIO *o = BIO_new_fd(fileno(stdout), BIO_NOCLOSE);
BIO *o = BIO_new(BIO_s_file());
RSA_print(o, key, 0);
BIO_free(o);
}
#endif
r = RSA_public_encrypt(strlen(msg), msg, msg2,
key, RSA_PKCS1_PADDING); // or RSA_PKCS1_OAEP_PADDING
if (!r)
puts("error in enc");
#if 0
sig[0]++; // 假想的错误
#endif
r = RSA_private_decrypt(r, msg2, msg3,
key, RSA_PKCS1_PADDING);
if (!r)
puts("error in dec");
if (memcmp(msg, msg3, strlen(msg)))
puts("ERROR! text2 != text");
else
{
msg3[strlen(msg)] = 0;
printf("解密后的明文:%s", msg3);
}
puts("is there errs? no? ok!");
RSA_free(key);
return 0;
}
#endif