des/3des对称加密算法在我们日常保护数据或者保护传输时使用得较多的对称加密算法,des的原理不在这里再作详细介绍,des/3des属于一种分组算法,以8个字节为一个分组。例如下面使用3des对一组数据进行加密:
例如:
密钥:0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF 0xEF 0xCD 0xAB 0x89 0x67 0x45 0x01 0x23
数据:0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01
ECB加密过程就是先使用A对数据进行加密:0x61 0x7B 0x3A 0x0C 0xE8 0xF0 0x71 0x00,然后再使用B对A加密的结果进行解密:0x86 0xCF 0xF5 0x18 0xE3 0x0B 0xFA 0x6F,再使用A对B解密的结果进行加密:0xAE 0x94 0xDD 0xAC 0x88 0x9A 0xD1 0x9E
当然还有CBC、CFB等模式的加密方式,但都是大同小异。对于每8个字节分组都是按某特定的步骤进行处理。
下面我们使用openssl的算法库实现以上的流程:
1)产生对称密钥
/*
随机产生DES/3DES密钥
keyLen 8:单倍 16:双倍 24:三倍
返回值:
>0 正确 密钥长度
<=0 错误 相应的错误码
*/
int RandomDesKey(const int keyLen, string& desKey)
{
char key[24];
DES_cblock randKey;
int len = 0, x = 0, ret = 0;
if (keyLen != 8 && keyLen != 16 && keyLen != 24)
return errCodeOffsetOfCommon_CodeParameter;
memset(key, 0, sizeof(key));
for (x=0;x
ret = DES_random_key(&randKey);
if (ret == 0)
{
return errCodeOffsetOfCert_Arithmetic;
}
memcpy(key+x, randKey, 8);
len += 8;
}
string keyBuf(key, len);
desKey = keyBuf;
return len;
}
2)数据加密
/*
使用DES算法对数据加密
desKey 密钥,支持单倍、双倍、三倍
data 源数据 长度必须为8的倍数
mode 加密模式 ECB CBC CFB
iv 仅 CBC CFB两种模式才有此值,长度为8字节
返回值:
>=0 加密数据的长度
<0 错误码
*/
int DesEncryptData(const string &desKey, const string &data, int mode, const string &iv, 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[8192], output[8192];
keyLen = desKey.length();
dataLen = data.length();
if (keyLen == 0 || dataLen == 0)
return -1;
memset(input, 0, 8192);
memset(output, 0, 8192);
memcpy(input, data.c_str(), dataLen);
switch (keyLen)
{
case 8:
memset(ke1, 0, 8);
memcpy(ke1, desKey.c_str(), 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
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.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str(), 8);
}else
{
memcpy(ke1, desKey.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str()+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
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;
break;
}
if (dataLen > 0)
{
string result((char *)output, dataLen);
encData = result;
}
return dataLen;
}
3)数据解密
/*
使用DES算法对数据解密
desKey 密钥,支持单倍、双倍、三倍
data 源数据 长度必须为8的倍数
mode 加密模式 ECB CBC CFB
iv 仅CBC CFB两种模式才有此值
*/
int DesDecryptData(const string &desKey, const string &data, int mode, const string &iv, string &plainData)
{
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[8192], output[8192];
keyLen = desKey.length();
dataLen = data.length();
if (keyLen == 0 || dataLen == 0)
return -1;
memset(input, 0, 8192);
memset(output, 0, 8192);
memcpy(input, data.c_str(), dataLen);
switch (keyLen)
{
case 8:
memset(ke1, 0, 8);
memcpy(ke1, desKey.c_str(), 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
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.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str(), 8);
}else
{
memcpy(ke1, desKey.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str()+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
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;
break;
}
if (dataLen > 0)
{
string result((char *)output, dataLen);
plainData = result;
}
return dataLen;
}
具体源码逐步分享到https://github.com/goodboy168/openssl-lib