最近在做一个基于https的项目,因为业务数据需要安全保障,于是需要一定的加解密工作,数据的安全也是现代互联网发展的保障。
下面几种加解密机制:
- DES、3DES加密
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。需要注意的是,在某些文献中,作为算法的DES称为数据加密算法(Data Encryption Algorithm,DEA),已与作为标准的DES区分开来。
DES对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的密钥,信息的发送者和信息的接收者在进行信息的传输与处理时,必须共同持有该密码(称为对称密码),是一种对称加密算法。
DES 的常见变体是三重 DES,使用 168 位的密钥对资料进行三次加密的一种机制;它通常(但非始终)提供极其强大的安全性。如果三个 56 位的子元素都相同,则三重 DES 向后兼容 DES。
DES加密过程:
#include <openssl/des.h>
#include <openssl/rand.h>
/*
注意:传进传出的参数皆为16进制字符数据
使用DES算法对数据加密
desKey 密钥,支持单倍、双倍、三倍
data 源数据 长度必须为8的倍数
mode 加密模式 ECB CBC CFB
iv 仅 CBC CFB两种模式才有此值,长度为8字节
返回值:
>=0 加密数据的长度
<0 错误码
*/
int DesEncryptData(const std::string &desKeyHexStr, const std::string &dataHexStr, int mode, const std::string &iv, std::string &encDataHexStr)
{
BYTE desKey[MAX_SIZE_L] = {0};
std::string data ;
std::string encData;
int keyLen = 0, x = 0;
long dataLen = 0;
DES_key_schedule ks1, ks2, ks3;
unsigned char tmpData[8], ke1[8], ke2[8], ke3[8], ivec[8];
unsigned char input[MAX_SIZE_L], output[MAX_SIZE_L];
keyLen = desKeyHexStr.length()/2;
dataLen = dataHexStr.length()/2;
if (keyLen == 0 || dataLen == 0)
return -1;//errCodeOffsetOfCommon_CodeParameter;
memset(input, 0, MAX_SIZE_L);
memset(output, 0, MAX_SIZE_L);
memset(desKey, 0, MAX_SIZE_L);
hexToBytes(dataHexStr,input);
hexToBytes(desKeyHexStr,desKey);
switch (keyLen)
{
case 8:
memset(ke1, 0, 8);
memcpy(ke1, desKey, 8);
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_cbc_encrypt(input, output, dataLen, &ks1, (DES_cblock *)ivec, DES_ENCRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_cfb_encrypt(input, output, 8, dataLen, &ks1, (DES_cblock *)ivec, DES_ENCRYPT);
break;
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, DES_ENCRYPT);
}
break;
}
break;
case 16:
case 24:
memset(ke1, 0, 8);
memset(ke2, 0, 8);
memset(ke3, 0, 8);
if (keyLen == 16)
{
memcpy(ke1, desKey, 8);
memcpy(ke2, desKey+8, 8);
memcpy(ke3, desKey, 8);
}else
{
memcpy(ke1, desKey, 8);
memcpy(ke2, desKey+8, 8);
memcpy(ke3, desKey+16, 8);
}
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
DES_set_key_unchecked((const_DES_cblock*)ke2, &ks2);
DES_set_key_unchecked((const_DES_cblock*)ke3, &ks3);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cbc_encrypt(input, output, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_ENCRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cfb_encrypt(input, output, 8, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_ENCRYPT);
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb3_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, &ks2, &ks3, DES_ENCRYPT);
}
break;
}
break;
default:
dataLen = -1;//errCodeOffsetOfCommon_CodeParameter;
break;
}
if (dataLen > 0)
{
encDataHexStr = bytesToHexString(output,dataLen);
}
return encDataHexStr.length();
}
//密钥key:4a776d4e5ba6a68aec14abc9d7df9714
//加密原数据:hello,world!
//转换成16进制字符的80pad:68656c6c6f2c776f726c642180000000
//80pad转换成16进制字符串data:3638363536633663366632633737366637323663363432313830303030303030
//将data和key传参进去,
std::string enData;
int len = DesEncryptData(key,data,ECB,"",enData);
//得到3Des加密后的结果是enData:547f98962becbd93897b96aa44971c384853b21511529e2dceb58a11940ca037
解密过程:
/*
使用DES算法对数据解密
desKey 密钥,支持单倍、双倍、三倍
data 源数据 长度必须为8的倍数
mode 加密模式 ECB CBC CFB
iv 仅CBC CFB两种模式才有此值
*/
int DesDecryptData(const std::string &desKeyHexStr, const std::string &dataHexStr, int mode, const std::string &iv, std::string &plainDataHexStr)
{
BYTE desKey[MAX_SIZE_L];
//std::string desKey;// = hexStringToString(desKeyHexStr);
std::string data;// = hexStringToString(dataHexStr);
int keyLen = 0, x = 0;
long dataLen = 0;
DES_key_schedule ks1, ks2, ks3;
unsigned char tmpData[8], ke1[8], ke2[8], ke3[8], ivec[8];
unsigned char input[MAX_SIZE_L], output[MAX_SIZE_L];
keyLen = desKeyHexStr.length()/2;
dataLen = dataHexStr.length()/2;
if (keyLen == 0 || dataLen == 0)
return -1;//errCodeOffsetOfCommon_CodeParameter;
memset(desKey,0,MAX_SIZE_L);
memset(input, 0, MAX_SIZE_L);
memset(output, 0, MAX_SIZE_L);
//memcpy(input, data.c_str(), dataLen);
hexToBytes(dataHexStr,input);
hexToBytes(desKeyHexStr,desKey);
switch (keyLen)
{
case 8:
memset(ke1, 0, 8);
memcpy(ke1, desKey, 8);
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_cbc_encrypt(input, output, dataLen, &ks1, (DES_cblock *)ivec, DES_DECRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_cfb_encrypt(input, output, 8, dataLen, &ks1, (DES_cblock *)ivec, DES_DECRYPT);
break;
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, DES_DECRYPT);
}
break;
}
break;
case 16:
case 24:
memset(ke1, 0, 8);
memset(ke2, 0, 8);
memset(ke3, 0, 8);
if (keyLen == 16)
{
memcpy(ke1, desKey, 8);
memcpy(ke2, desKey+8, 8);
memcpy(ke3, desKey, 8);
}else
{
memcpy(ke1, desKey, 8);
memcpy(ke2, desKey+8, 8);
memcpy(ke3, desKey+16, 8);
}
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
DES_set_key_unchecked((const_DES_cblock*)ke2, &ks2);
DES_set_key_unchecked((const_DES_cblock*)ke3, &ks3);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cbc_encrypt(input, output, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_DECRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cfb_encrypt(input, output, 8, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_DECRYPT);
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb3_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, &ks2, &ks3, DES_DECRYPT);
}
break;
}
break;
default:
dataLen = -1;//errCodeOffsetOfCommon_CodeParameter;
break;
}
if (dataLen > 0)
{
/*std::string result((char *)output, dataLen);
plainDataHexStr = encodeHexString(result);*/
plainDataHexStr = bytesToHexString(output,dataLen);
}
return plainDataHexStr.length();
}
//解密传参data:547f98962becbd93897b96aa44971c384853b21511529e2dceb58a11940ca037
//key:4a776d4e5ba6a68aec14abc9d7df9714
std::string decData;
int len = DesDecryptData(key,data,ECB,"",decData);
//decData:3638363536633663366632633737366637323663363432313830303030303030
//得到80pad:68656c6c6f2c776f726c642180000000
//转换得到16进制字符串:68656c6c6f2c776f726c6421
//16进制转bytes:hello,world!
- SHA256 (salt)
SHA代表安全哈希算法。SHA-1和SHA-2是该算法不同的两个版本,它们的构造和签名的长度都有所不一样,但可以把SHA-2理解为SHA-1的继承者。
首先,人们一般把哈希值位数长度作为重要的区别,SHA-1是160位的哈希值,而SHA-2是组合值,有不同的位数,其中最受欢迎的是256位。
因为SHA-2有多种不同的位数,导致这个名词有一些混乱。但是无论是“SHA-2”,“SHA-256”或“SHA-256位”,其实都是指同一种加密算法。但是SHA-224”,“SHA-384”或“SHA-512”,表示SHA-2的二进制长度。还要另一种就是会把算法和二进制长度都写上,如“SHA-2
384”。SSL行业选择SHA作为数字签名的散列算法,从2011到2015,一直以SHA-1位主导算法。但随着互联网技术的提升,SHA-1的缺点越来越突显。从去年起,SHA-2成为了新的标准,所以现在签发的SSL证书,必须使用该算法签名。
作者:ROW供享社
加盐算法:其实就是在需要加密的数据后面增加一串随机数进行加密即可。为什么要加盐呢,其实就是为了高安全性。加盐必须随机才有用。
#include "openssl/sha.h"
std::string mingwen = "123456";
unsigned char mdStr[33] = {0};//hash后的值长度为32个字节,也就是256个bit
SHA256((const unsigned char *)mingwen.c_str(),mingwen.length(),mdStr);
std::string res = bytesToHexString(mdStr,32);//字节数组转16进制字符串
//长度64位的16进制字符串res:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92