Chinaunix首页 | 论坛 | 博客
  • 博客访问: 596180
  • 博文数量: 95
  • 博客积分: 1573
  • 博客等级: 上尉
  • 技术积分: 1030
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-23 10:46
个人简介

hello world!

文章分类

全部博文(95)

文章存档

2014年(1)

2013年(44)

2012年(50)

分类: LINUX

2012-04-25 16:30:37

不同于对称加密算法中加密和解密使用同样的密钥,公钥算法分为加密密钥K1和解密密钥K2两部分,而且从K1很难计算推导出K2。这样就可以保密K2而公布K1,从而大大简化了密钥管理。习惯上K1称为公钥,K2称为私钥。

    加密使用公钥,解密使用私钥。

           ENCPK1= C

           DECCK2= P

    RSA加密算法的步骤是这样的:

(1)    找两个随机大素数pq

(2)    计算模n=pqEuler函数φ(n) =(p-1)(q-1)

(3)    选取数e后用扩展Euclid算法求数d满足ed1 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)    验证(ms)即判断m =? s^e mod n

下面介绍OpenSSLRSA算法的函数接口。

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_PADDINGRSA_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_md5NID_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

阅读(3063) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~