一、 前言
签名讲过使用我们使用AES加密算法与服务端进行数据加解密交互,对AES来说,secret key,如果我们把key硬编码在代码里面,被逆向后也很容易找到对应的key,隐藏我们需要设计一套算法来保证key是动态生成,不是硬编码在代码里。这里我们使用MD5以及DES来增加算法的破解难度,其中的核心是MD5摘要算法,它的出现保证了secret key的产生不是唯一的。
二、具体实现方案
1)MD5介绍
参考百度百科:https://baike.baidu.com/item/MD5/212708?fr=aladdin
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。具有以下特点:
- 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
- 容易计算:从原数据计算出MD5值很容易。
- 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
- 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
MD5作用:
把一个任意长度的字节串变换成一定长的十六进制数字串,只要原始内容不变,产生的摘要内容就不会变。
结合MD5生成一个AES Secret Key
secrete key 的生成原理,对任意一个字符进行MD5,取出MD值,与对应长度key进行位运算,保证产生的index在目标数据的长度范围内,再根据index取出值,从而生成secret key。具体实现代码如下:
#include <string>
#include "openssl/md5.h"
using namespace std;
const char strKey[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
string createKey(const string &key){
unsigned char md[MD5_DIGEST_LENGTH];
const char *tem = key.c_str();
MD5((const unsigned char*)tem, key.length(),(unsigned char*)&md);
int len = MD5_DIGEST_LENGTH;
//key length = 16
char keyChar[len];
int index = 0;
for(int i = 0; i < len; i++){
keyChar[index++] = strKey[(md[i] >> 2) & 0x3D];
}
string rs(keyChar,len);
return rs;
}
1)结合DES
上述方式已经生成了AES的secret key,但是为了增加破解难度,再次结合DES算法,解密一个数据,作为生成key的原始内容。这里DES的实现和AES的实现都相似,采用CBC/PKCS5Padding填充模式,具体实现参考如下代码:
#include "openssl/des.h"
/***
* src:明文
* srcLen:明文长度
* key:密钥
* keyLen:密钥长度
* outLen:密文长度
* 返回值:密文 需要free
*
*/
unsigned char *des_encrypt(unsigned char *src, int srcLen, unsigned char *aesKey, int keyLen, int *outLen)
{
int aes_block_size = 8;
int blockCount = 0;
int quotient = srcLen / aes_block_size;
int mod = srcLen % aes_block_size;
blockCount = quotient + 1;
int allLength = blockCount * aes_block_size;
int padding = aes_block_size - mod;
char *in = (char *)malloc(allLength);
memset(in, padding, allLength);
memcpy(in, src, srcLen);
DES_cblock key;
DES_key_schedule key_schedule;
memcpy(key,aesKey,keyLen);
DES_set_key_unchecked(&key, &key_schedule);
//IV
DES_cblock ivec;
memcpy(ivec, aesKey, keyLen);
//out
char *out = (char *)malloc(allLength);
memset(out, 0x00, allLength);
*outLen = allLength;
DES_ncbc_encrypt((unsigned char*)in, (unsigned char*)out, allLength, &key_schedule, &ivec, DES_ENCRYPT);
free(in);
return (unsigned char*)out;
}
/**
* decrypt
* src:密文
* srcLen:密文长度
* key:密钥
* keyLen:密钥长度
* outLen:明文长度
* 返回值: 明文 需要free
*/
unsigned char *des_decrypt(unsigned char *src, int srcLen, unsigned char *aesKey, int keyLen, int *outLen)
{
DES_cblock key;
DES_key_schedule key_schedule;
memcpy(key,aesKey,keyLen);
DES_set_key_unchecked(&key, &key_schedule);
unsigned char *tmp = (unsigned char *)malloc(srcLen);
memset(tmp,0,srcLen);
//IV
DES_cblock iv;
memcpy(iv, aesKey, keyLen);
DES_ncbc_encrypt((const unsigned char *)src, tmp, srcLen, &key_schedule, &iv, DES_DECRYPT);
int unpadding = tmp[srcLen - 1];
*outLen = srcLen - unpadding;
char *out = (char *)malloc(*outLen);
memcpy(out, tmp, *outLen);
free(tmp);
return (unsigned char*)out;
}
三、总结
- 介绍了MD5的特性
- 如何结合MD5生成AES Secret Key
- DES的实现,对于这两者的结合使用,将在后面的章节介绍