OpenSSL RSA算法 非对称加密


    最近用OpenSSL 的RSA加解密算法,做了个非对称加密的小程序,写上来给大伙儿瞅瞅。

    OpenSSL的下载,编译,配置,略过。

    大概分以下几步:

首先,生成秘钥:

     注意,非对称加密生成一对秘钥,公钥,私钥。公钥加密,私钥解密。私钥解密得有密码,而且我只研究了公钥加密,私钥解密这一种方法。

     公钥生成:

     RSA* rsa = RSA_generate_key(KeyLength, RSA_F4, NULL, NULL);

     KeyLength在这里是密钥长度,256,512,1024,2048等等。

     长度越长,加密后的文件越大,针对同一段文字生成的密文也越长。另外,记下这个长度,后面解密时会用到。RSA_F4是对应的算法。后面两个参数不用,略过。
     BIO *bp = BIO_new(BIO_s_file());

     新搞一个文件指针
     BIO_write_filename(bp, cTemp);

     真正的创建这个文件,调试时发现好象不支持中文路径,不知道是我的问题还是OPENSSL的问题,没有关注。
     PEM_write_bio_RSAPublicKey(bp, rsa);

     rsa 和 bp相关联。
     BIO_free_all(bp);

     释放资源。

     

     私钥生成:

      大致和公钥生成差不多,只是私钥必需要创建密码,否则生成失败。cPassTemp是私钥密码,

bp = BIO_new_file(cTemp, "wb+");

cTemp是密钥路径。
        PEM_write_bio_RSAPrivateKey(bp, rsa, EVP_des_ede3(), (unsigned                                     char*)cPassTemp, strPrivatePassword.GetLength(), NULL, NULL);
  cPassTemp是密码,后面跟着密码长度。
BIO_free_all(bp);
RSA_free(rsa);

释放资源。


第二步,打开公钥(私钥):

        公钥:

        EVP_PKEY* key = NULL;
RSA * m_pRsaPublic = NULL;

BIO *bp = BIO_new(BIO_s_file());;
BIO_read_filename(bp, strKeyFile);

strKeyFile是路径,注意,上文说过,不要有中文字符。
if (NULL == bp)
{
异常处理略过。
}
m_pRsaPublic = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);

        真正的打开操作
if (m_pRsaPublic == NULL)
{
异常处理
}
printf("open_public_key success to PEM_read_bio_RSAPublicKey!\n");


key = EVP_PKEY_new();
if (NULL == key)
{
异常处理
}
EVP_PKEY_assign_RSA(key, m_pRsaPublic);

关联操作


        私钥:

EVP_PKEY* key = NULL;
m_pRsaPrivate = RSA_new();


BIO *bp = NULL;
bp = BIO_new_file(strKeyFile, "rb+");
strKeyFile是路径
if (NULL == bp)
{

异常处理
}
m_pRsaPrivate = PEM_read_bio_RSAPrivateKey(bp, &m_pRsaPrivate, NULL, (void *)strKeyPassWord);

这里要传私钥的密码
if (m_pRsaPrivate == NULL)
{

异常操作
}
key = EVP_PKEY_new();
if (NULL == key)
{

异常操作
}

EVP_PKEY_assign_RSA(key, m_pRsaPrivate);
关联。


最关键的来了,真正的加解密操作:

       加密:

char data[1024];
memset(data, 0, sizeof(data));


//读公钥
int
nLen = RSA_size(pThis->m_pRsaPublic);

        注意,这是最关键的地方,RSA算法每次可加解密的字节长度是受密钥长度

限制的,每次最多能加密的字节数是RSA_size(公钥)减去11个字节,如果传多了就会

加密失败。。。

int Result = fread(data, (nLen - 11), 1, m_pInputFile);

所以每次读文件时要限制一下长度。。。

UINT uReadFileSize = 0;
char * pEncode = NULL;

while ((Result>0) || (uReadFileSize < pThis->m_uInputFileSize))

//这里也是比较恶心的一步,读文件时读到最后一次时,fread会返回失败,但 //是其实是读到内容了,如果不加这个判断则会漏过最后一次读文件的内容
{
int LastLength = (nLen - 11);
if ((pThis->m_uInputFileSize - uReadFileSize) <= (nLen - 11))
{
LastLength = (pThis->m_uInputFileSize - uReadFileSize);
}
pEncode = new char[nLen];
memset(pEncode, 0, (nLen));
//根据读到的内容开一段buffer

int ret = RSA_public_encrypt(LastLength, (const unsigned char *)data,
(unsigned char *)pEncode, pThis->m_pRsaPublic, RSA_PKCS1_PADDING);

//加密操作,有了前面的长度限制,这里一般不会错了。但是注意一点,无 //论传进去的内容有多长,解出来的内容长度是恒定的,传一个字节和传 //所允许的最长字节,解出来的密文长度一样。。。


if (ret >= 0)
{//成功后写文件
//加密内容写入加密文件
fwrite(pEncode, (ret), 1, m_pOutputFile);
uReadFileSize += (LastLength);
}
else
{
//异常处理
}

//输出文件指针到最后
fseek(m_pOutputFile, 0, 2);
//清空buffer
memset(data, 0, sizeof(data));
if (pEncode != NULL)
{
delete[] pEncode;
pEncode = NULL;
}
//继续读文件获取长度
Result = fread(data, (nLen - 11), 1, m_pInputFile);
}
CRYPTO_cleanup_all_ex_data();
RSA_free(pThis->m_pRsaPublic);
//释放资源


解密:

解密必须要有私钥密码,必须和公钥是一对。否则不成功。其它步骤和公钥加密差不多,只是每次可解密的长度和公钥不一样,直接是RSA_size(私钥)不需要减去11个字节

char data[1024];
memset(data, 0, sizeof(data));
//读原始文件
int
nLen = RSA_size(pThis->m_pRsaPrivate);
int Result = fread(data,
nLen, 1, m_pInputFile);


UINT uReadFileSize = 0;
while ((Result>0) || (uReadFileSize < pThis->m_uInputFileSize))
{
int LastLength = (
nLen);
if ((pThis->m_uInputFileSize - uReadFileSize) <= (
nLen))
{
LastLength = (pThis->m_uInputFileSize - uReadFileSize);
}
char *pDecode = new char[nLen];
memset(pDecode, 0, nLen);
//解密
int Dret = RSA_private_decrypt(
nLen, (const unsigned char *)data,
(unsigned char *)pDecode, pThis->m_pRsaPrivate, RSA_PKCS1_PADDING);
uReadFileSize += nLen;
if (Dret >= 0)
{
//写解密文件
fwrite(pDecode, (Dret), 1, m_pOutputFile);
}
//Seek To End
fseek(m_pOutputFile, 0, 2);
//清空Buffer
memset(data, 0, sizeof(data));
delete[] pDecode;
pDecode = NULL;
//继续读文件获取长度
Result = fread(data, nLen, 1, m_pInputFile);
}
CRYPTO_cleanup_all_ex_data();
RSA_free(pThis->m_pRsaPrivate);


OK,写完收工。

Demo程序在这里:

http://download.csdn.net/detail/usualeasy/9525978




已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页