我遇到过以下问题:
1.加密后得内容中带有结束符,cout输出不能正常输出
2.将加密后的内容存到文件,解密的时候再读出来,可能会碰到结束符而提前终止读取文件,导致解密失败
3.将加密后的内容转为十六进制,解密再转回来是完全可以的,但是我将加密后的内容转为二进制会有问题,我看解密的时候具体数据都是一样的,却解密失败。这个我也未解决。
// OpenSSLDemo.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include <windows.h>
#include <string>
#include <iterator>
#include <algorithm>
#include <vector>
#include <sstream>
#include <io.h>
#include <direct.h>
#include "openssl/md5.h"
#include "openssl/sha.h"
#include "openssl/des.h"
#include "openssl/rsa.h"
#include "openssl/pem.h"
#include "base64.h"
#include "memery.h"
using namespace std;
#define KEY_LENGTH 2048
#define PUB_KEY_FILE "pubkey.pem"
#define PRI_KEY_FILE "prikey.pem"
#pragma warning(disable:4996)
void str_to_two(const UCHAR *str,int strLen,UCHAR *twoStr);
void two_to_str(const UCHAR *inData,int inDataLen,UCHAR *outStr);
string string_to_hex(std::string const &str);
string hex_to_string(std::string const &str);
string getMsg(int ret)
{
string message;
switch (ret)
{
case 0:message="失败"; break;
case 1:message="成功"; break;
default: message="未知错误";break;
}
return message;
}
//2进制转16进制
unsigned char char2HexChar(const unsigned char &x)
{
return x>9?(x-10+'A'):x+'0';
}
//sha1加密
string sha1(const string &str)
{
SHA_CTX c;
SHA1_Init(&c);
SHA1_Update(&c,str.c_str(),str.size());
unsigned char szSha1[SHA_DIGEST_LENGTH]={0};
SHA1_Final(szSha1,&c);
string strSha1="";
// unsigned char strTmpHex;
char buf[41] = {0};
char tmp[3] = {0};
for (int i=0;i<SHA_DIGEST_LENGTH;i++)
{
/*strTmpHex=char2HexChar(szSha1[i]/16);
strSha1.append(1,strTmpHex);
strTmpHex=char2HexChar(szSha1[i]%16);
strSha1.append(1,strTmpHex);*/
sprintf_s(tmp,"%02x",szSha1[i]);
strcat_s(buf,tmp);
}
//transform(strSha1.begin(), strSha1.end(), strSha1.begin(), ::tolower);
return buf;
}
string md5(const string &str)
{
unsigned char md[16]={0};
MD5_CTX md5;
MD5_Init(&md5);
MD5_Update(&md5,str.c_str(),str.size());
MD5_Final(md,&md5);
char buf[33]={0};
char tmp[3]={0};
for(int i=0;i<16;i++)
{
sprintf_s(tmp,"%02x",md[i]);
strcat_s(buf,tmp);
}
return buf;
}
//sha256加密
string sha256(const string &srcStr)//, std::string &encodedStr, std::string &encodedHexStr)
{
// 调用sha256哈希
unsigned char mdStr[SHA256_DIGEST_LENGTH] = {0};
SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
// 哈希后的字符串
//encodedStr = std::string((const char *)mdStr);
// 哈希后的十六进制串 32字节
char buf[65] = {0};
char tmp[3] = {0};
string encodedStr;
string encodedHexStr;
for (int i = 0; i < 32; i++)
{
sprintf(tmp, "%02x", mdStr[i]);
strcat(buf, tmp);
}
//buf[32] = '\0'; // 后面都是0,从32字节截断
return buf;
}
//des对称加密
/********************************************************
DES加密原理:
DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位
(每组的第8位作为奇偶校验位),产生最大 64 位的分组大小。
这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将
加密的文本块分成两半。使用子密钥对其中一半应用循环功能,
然后将输出与另一半进行“异或”运算;接着交换这两半,
这一过程会继续下去,但最后一个循环不交换。DES 使用 16
轮循环,使用异或,置换,代换,移位操作四种基本运算。
**********************************************************/
// ecb模式
string des_encrypt(string &text,const string &key)
{
string cipherText; //密文
DES_cblock keyEncrypt;
memset(keyEncrypt,0,8);
if(key.length()<=8) //构造补齐后的秘钥
{
memcpy(keyEncrypt,key.c_str(),key.length());
}
else
{
memcpy(keyEncrypt,key.c_str(),8);
}
//密钥置换
DES_key_schedule keySchedule;
DES_set_key_unchecked(&keyEncrypt,&keySchedule); //设置密码表,不需要校验
//循环加密,每8字节一次
const_DES_cblock inputText;
DES_cblock outputText;
vector<unsigned char> vecCiphertext;
unsigned char tmp[8]={0};
for (size_t i=0;i<text.length()/8;i++)
{
memcpy(inputText,text.c_str()+i*8,8);
DES_ecb_encrypt(&inputText,&outputText,&keySchedule,DES_ENCRYPT);
memcpy(tmp,outputText,8);
for (int j=0;j<8;j++)
{
vecCiphertext.push_back(tmp[j]);
}
}
if(text.length()%8!=0)
{
int tmp1=text.length()/8*8;
int tmp2=text.length()-tmp1;
memset(inputText,0,8);
memcpy(inputText,text.c_str()+tmp1,tmp2);
//加密函数
DES_ecb_encrypt(&inputText,&outputText,&keySchedule,DES_ENCRYPT);
memcpy(tmp,outputText,8);
for (int i=0;i<8;i++)
{
vecCiphertext.push_back(tmp[i]);
}
}
cipherText.clear();
cipherText.assign(vecCiphertext.begin(),vecCiphertext.end());
return cipherText;
}
//解密ecb
string des_decrypt(const string &cipherText,const string &key)
{
string clearText; //明文
DES_cblock keyEncrypt;
memset(keyEncrypt,0,8);
if (key.length()<=8)
{
memcpy(keyEncrypt,key.c_str(),key.length());
}
else
{
memcpy(keyEncrypt,key.c_str(),8);
}
DES_key_schedule keyScheule;
DES_set_key_unchecked(&keyEncrypt,&keyScheule); //设置密码表,不校验
const_DES_cblock inputText;
DES_cblock outputText;
vector<unsigned char> vecClearText;
unsigned char tmp[8];
for (size_t i=0;i<cipherText.length()/8;i++)
{
memcpy(inputText,cipherText.c_str()+i*8,8);
DES_ecb_encrypt(&inputText,&outputText,&keyScheule,DES_DECRYPT);
memcpy(tmp,outputText,8);
for (int j=0;j<8;j++)
{
vecClearText.push_back(tmp[j]);
}
}
if(cipherText.length()%8!=0)
{
int tmp1=cipherText.length()/8*8;
int tmp2=cipherText.length()-tmp1;
memset(inputText,0,8);
memcpy(inputText,cipherText.c_str()+tmp1,tmp2);
//解密函数
DES_ecb_encrypt(&inputText,&outputText,&keyScheule,DES_DECRYPT);
memcpy(tmp,outputText,8);
for (int i=0;i<8;i++)
{
vecClearText.push_back(tmp[i]);
}
}
clearText.clear();
clearText.assign(vecClearText.begin(),vecClearText.end());
return clearText;
}
int writeFile(const char *fileName,const string data)
{
string path="..//file//";
if(access(path.c_str(),0)==-1) //-1为未创建
{
int i=mkdir(path.c_str());
if (i)
{
cout<<"创建目录失败"<<endl;
return 0;
}
}
FILE *f=NULL;
path+=fileName; //文件的完整路径
f=fopen(path.c_str(),"w");
if(f==NULL)
{
cout<<"打开文件失败!"<<endl;
return 0;
}
if(fwrite(data.c_str(),data.size(),1,f)==EOF)
{
cout<<"写入文件错误!"<<endl;
return 0;
}
fclose(f);
return 1;
}
string readFile(const string fileName)
{
string data;
string path="..//file//";
path+=fileName; //完整路径
FILE *f=NULL;
f=fopen(path.c_str(),"rb");
if(f==NULL)
{
cout<<"读取文件失败!"<<endl;
return 0;
}
//char *buf=new char[2048];
unsigned char buf={0};
int i=0;
while (fread(&buf,sizeof(unsigned char),1,f)) //一直读
{
//fgets(buf,2048,f);
//cout<<buf;
//data.append(( char*)buf);
data+=buf;
//memset(buf,0,strlen((char*)buf));
}
fclose(f);
//delete [] buf;
//buf=NULL;
//cout<<data<<endl;
//memcpy((char*)data.c_str(),tmp,i);
return data;
}
/***********************
* rsa非对称加密 **
************************
*/
//生成密钥对
int generateRSAkey()
{
string pubKey;
string priKey;
//公私密钥对
size_t pri_len;
size_t pub_len;
char *pri_key=NULL;
char *pub_key=NULL;
//生成密钥对
RSA *keypair=RSA_generate_key(KEY_LENGTH,RSA_3,NULL,NULL);
BIO *pri=BIO_new(BIO_s_mem());
BIO *pub=BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri,keypair,NULL,NULL,0,NULL,NULL);
PEM_write_bio_RSAPublicKey(pub,keypair);
//获取长度
pri_len=BIO_pending(pri);
pub_len=BIO_pending(pub);
//秘钥对读取到字符串
pri_key=new char[pri_len+1];
pub_key=new char[pub_len+1];
BIO_read(pri,pri_key,pri_len);
BIO_read(pub,pub_key,pub_len);
pri_key[pri_len]='\0';
pub_key[pub_len]='\0';
//存储秘钥对
pubKey=pub_key;
priKey=pri_key;
//存储到磁盘(这种方式)
writeFile(PUB_KEY_FILE,pub_key);
writeFile(PRI_KEY_FILE,pri_key);
//内存释放
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
delete []pri_key;
delete []pub_key;
return 1;
}
//公钥加密
int rsa_pub_encrypt(const string &clearText,const string &pubKey)
{
string strRet;
RSA *rsa=NULL;
BIO *keybio=BIO_new_mem_buf((unsigned char*)pubKey.c_str(),-1);
//三种方式
//1.读取内存里生成的密钥对,再从内存生成rsa
//2.读取磁盘里生成的密钥对文本文件,再从内存生成rsa
//3.直接从读取文件指针生成rsa
RSA *pRSAPublicKey=RSA_new();
rsa=PEM_read_bio_RSAPublicKey(keybio,&rsa,NULL,NULL);
int len=RSA_size(rsa);
char *encryptedText=new char[len+1];
memset(encryptedText,0,len+1);
//加密函数
int ret=RSA_public_encrypt(clearText.length(),(const unsigned char*)clearText.c_str(),(unsigned char*)encryptedText,rsa,RSA_PKCS1_PADDING);
if(ret>=0)
{
strRet=string(encryptedText,ret);
writeFile("rsa_en.txt",strRet);
string strHex=string_to_hex(strRet); //将加密后的内容转为16进制
writeFile("rsa_en_16.txt",strHex);
unsigned char twoArray[5000]={0};
str_to_two((unsigned char*)strRet.c_str(),strRet.size(),twoArray); //将加密后的内容转为2进制
//memcpy((char*)strTwo.c_str(),twoArray,strlen((char*)twoArray));
writeFile("rsa_en_2.txt",string((char*)twoArray));
}
//释放内存
delete []encryptedText;
BIO_free_all(keybio);
RSA_free(rsa);
return 1;
}
//私钥解密
int rsa_pri_decrypt(const string cipherText,const string priKey)
{
//将16进制字符转为原加密后的字符
string en_data=hex_to_string(cipherText); //转换成原 加密后的内容
writeFile("cipherText.txt",en_data);
//以下生成的16进制字符 是为了 和 rsa加密后字符转为16进制字符串 进行比对的文件
string cipherText16=string_to_hex(en_data);
writeFile("A_rsa_de_16.txt",cipherText16);
//一下生成的2进制字符是 为了和之前加密后内容转换成的2进制字符进行比较
unsigned char twoArray[5000]={0};
str_to_two((unsigned char*)en_data.c_str(),en_data.size(),twoArray);
writeFile("A_rsa_de_2.txt",string((char*)twoArray));
string strRet;
RSA *rsa=RSA_new();
//string path="..//file//prikey.pem";
/*FILE *f=fopen(path.c_str(),"rb+");
rsa = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
if(rsa==NULL){
printf("unable to read private key!\n");
return NULL;
} */
BIO *keybio;
keybio=BIO_new_mem_buf((unsigned char*)priKey.c_str(),-1);
//三种方式
//1.读取内存里生成的密钥对,再从内存生成rsa
//2.读取磁盘里生成的密钥对文本文件,再从内存生成rsa
//3.直接从读取文件指针生成rsa
rsa=PEM_read_bio_RSAPrivateKey(keybio,&rsa,NULL,NULL);
// 从文件中读取私钥
int len=RSA_size(rsa);
char *decryptedText=new char[len+1];
memset(decryptedText,0,len+1);
int ret=RSA_private_decrypt(en_data.size(),(unsigned char*)en_data.c_str(),(unsigned char*)decryptedText,rsa,RSA_PKCS1_PADDING);
if(ret>=0)
{
strRet=string(decryptedText,ret);
writeFile("rsa_de.txt",decryptedText);
}
else
return 0;
//释放内存
delete []decryptedText;
BIO_free_all(keybio);
RSA_free(rsa);
return 1;
}
/******************************************
** 功能:字符转二进制
** 参数:
** str:输入的字符
** strLen:输入字符串的长度
** twoStr:字符串转换成的二进制
*******************************************
*/
void str_to_two(const UCHAR *str,int strLen,UCHAR *twoStr)
{
UCHAR k=0x80; //解密按位与运算 128 10000000
for (int i = 0; i < strLen; i++,str++)
{
k = 0x80;
for (int j=1; j<=8; j++, k >>= 1)
{
if (*str & k)
{
*twoStr='1';
twoStr++;
}
else
{
*twoStr='0';
*twoStr++;
}
}
}
twoStr++;
*twoStr='\0'; //结束字符串
}
/******************************************
** 功能:二进制转字符
** 参数:
** inData:输入的二进制数组
** inDataLen:输入二进制数组的长度
** outStr:二进制转换后的字符
*******************************************
*/
void two_to_str(const UCHAR *inData,int inDataLen,UCHAR *outStr)
{
char TwoStr[9]=""; //存放每个字符 8bit
int kk=0; //记录字符串的数量
for(int i=0;i<inDataLen;i=i+8)
{
int l=0;
strncpy(TwoStr,(const char*)inData+i,8);//把每一个字符的8bit 复制给outData
for(int j=0;j<8;j++)
{
l+=(TwoStr[j]-'0')<<(7-j); //转换成十进制
outStr[kk]=l;
}
++kk;
}
outStr[kk]='\0';
}
string string_to_hex(string const &str)
{
string ret;
for (unsigned i = 0; i != str.size(); ++i)
{
char hex[6]={0};
sprintf(hex, "%#.2x ", (unsigned char)str[i]);
ret += hex;
}
return ret;
}
string hex_to_string(string const &str)
{
string ret;
istringstream iss(str);
for (string buf; getline(iss, buf, ' ');)
{
unsigned int value;
sscanf(buf.c_str(), "%x", &value);
ret += ((char)value);
}
return ret;
}
int _tmain(int argc, _TCHAR* argv[])
{
const char* str="shenxuebing hello wordl!沈雪冰**--(1995.5.19)*)(&*%@‘;。《》";
int ret=-1;
cout<<"------------------------------MD5-----------------------------"<<endl;
writeFile("MD5.txt",md5(str));
cout<<md5(str)<<endl;
cout<<"------------------------------SHA1-----------------------------"<<endl;
writeFile("SHA1.txt",sha1(str));
cout<<sha1(str)<<endl;
cout<<"------------------------------SH256----------------------------"<<endl;
writeFile("SHA256.txt",sha256(str));
cout<<sha256(str)<<endl;
cout<<"------------------------------DES_ECB加密----------------------------"<<endl;
string desKey="123456";
string enstr=des_encrypt(string(str),desKey);
writeFile("DES_ECB_en.txt",enstr);
//readFile("DES_ECB.txt");
cout<<"------------------------------DES_ECB解密----------------------------"<<endl;
string destr=des_decrypt(enstr,"123456");
writeFile("DES_ECB_de.txt",destr);
cout<<"------------------------------生成密钥对----------------------------";
ret=generateRSAkey();
cout<<getMsg(ret)<<endl;
cout<<"------------------------------公钥加密----------------------------";
string pubKey;
pubKey=readFile("pubkey.pem");
cout<<getMsg(rsa_pub_encrypt(str,pubKey))<<endl;
cout<<"------------------------------私钥解密----------------------------";
string priKey=readFile("prikey.pem");
string rsa_en_16=readFile("rsa_en_16.txt");
ret=rsa_pri_decrypt(rsa_en_16,priKey);
cout<<getMsg(ret)<<endl;
system("pause");
return 0;
}