根据解密算法代码反推实现加密算法
说明
为保证项目安全,本文章使用的加解密相关的代码变量szSalt,szKey,nrounds,gszKey等变量为修改后的,未经实际应用检测。自测时打印函数请自行修改。
先上已经实现的解密代码
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <errno.h>
const char gszKey[]= "aaabbbcccdddeeefffggg";
#define OK 0
#define ERR -1
#define CIPHER_TEXT_LEN 32
/***************************************************************************
function: GetKey
input:
output:
Description:获取解密需要的key,key的长度是32实际使用27个
代码混淆生成key防止直接硬编码被看出来
****************************************************************************/
void GetKey(char *pcKey)
{
pcKey[0]='6';
pcKey[1]=pcKey[0]-1;
pcKey[2]='1';
pcKey[3]=pcKey[2]+1;
pcKey[4]=pcKey[3]+1;
pcKey[5]='F';
pcKey[6]=pcKey[4]+1;
pcKey[7]=pcKey[1]+1;
pcKey[8]=pcKey[0]+1;
pcKey[9]=pcKey[1];
pcKey[10]=pcKey[6]-1;
pcKey[11]=pcKey[7]+1;
pcKey[12]=pcKey[5]+1;
pcKey[13]=pcKey[5]-1;
pcKey[14]=pcKey[4]-1;
pcKey[15]=pcKey[6];
pcKey[16]=pcKey[6]-1;
pcKey[17]=pcKey[5]-1;
pcKey[18]=pcKey[17]+1;
pcKey[19]=pcKey[18]-1;
pcKey[20]=pcKey[5]-1;
pcKey[21]=pcKey[1];
pcKey[22]=pcKey[1]+1;
pcKey[23]=pcKey[22]+1;
pcKey[24]=pcKey[18]-1;
pcKey[25]=pcKey[5]+1;
pcKey[26]=pcKey[1];
pcKey[27]=pcKey[0]+1;
pcKey[28]=pcKey[12]+1;
pcKey[29]=pcKey[5]+1;
pcKey[30]=pcKey[11]-1;
pcKey[31]=pcKey[6]-1;
return;
}
/***************************************************************************
function: DecryptKey
input:
output:
Description:解密key
****************************************************************************/
unsigned char *DecryptKey(unsigned char *pcCipherText, int lCipherLen)
{
int ret;
int nrounds = 7;
char szKey[32]= {0};
uint szSalt[] = {11111,11111};
uchar key[32] = {0};
uchar iv[32] = {0};
int p_len = 0;
int f_len = 0;
EVP_CIPHER_CTX *pMdCtx = NULL;
uchar *pcPlaintext = NULL;
// 0 准备明文空间和上下文
pcPlaintext = (uchar *)malloc(lCipherLen);
if(NULL == pcPlaintext)
{
LOG(LOG_ERROR, "System have no more memory failed.\n");
return NULL;
}
pMdCtx = EVP_CIPHER_CTX_new();
if(NULL == pMdCtx)
{
free(pcPlaintext);
LOG(LOG_ERROR, "alloc ctx failed.\n");
return NULL;
}
// 1 获取key和iv 然后初始化ctx
GetKey(szKey);
ret = EVP_BytesToKey(EVP_aes_256_cbc(),
EVP_sha1(),
(unsigned char*)szSalt,
(unsigned char*)szKey,
strlen(gszKey),
nrounds,
key,
iv);
LOG(LOG_DEBUG, "key is %d, iv is %d.\n", key, iv);
if(ret != 32)
{
LOG(LOG_ERROR, "Key size is %d bits, it should be 256 bits\n", ret);
EVP_CIPHER_CTX_free(pMdCtx);
free(pcPlaintext);
return NULL;
}
EVP_DecryptInit_ex(pMdCtx, EVP_aes_256_cbc(), NULL, key, iv);
// 2解密
EVP_DecryptUpdate(pMdCtx, pcPlaintext, &p_len, pcCipherText, lCipherLen);
EVP_DecryptFinal_ex(pMdCtx, pcPlaintext + p_len, &f_len);
pcPlaintext[p_len + f_len] = 0;
LOG(LOG_DEBUG, "p_len is %d, f_len is %d, pcPlaintext is %s.\n", p_len, f_len, pcPlaintext);
// 3释放上下文
EVP_CIPHER_CTX_free(pMdCtx);
return pcPlaintext;
}
/***************************************************************************
function: GetMacAddr
input:
output:
Description:获取系统mac地址
****************************************************************************/
int GetMacAddr(char *pcDevName, char *pcBuffer)
{
struct ifreq req;
int s = -1;
int err = -1;
unsigned char szMacAddr[6];
s = socket(AF_INET,SOCK_DGRAM,0);
if(s < 0)
{
LOG(LOG_ERROR, "alloc socket failed.\n");
return ERR;
}
strcpy(req.ifr_name, pcDevName);
err = ioctl(s, SIOCGIFHWADDR, &req);
if(err < 0)
{
LOG(LOG_ERROR, "ioctl failed err:%d.\n", errno);
return ERR;
}
memcpy(szMacAddr, req.ifr_hwaddr.sa_data, 6);
sprintf(pcBuffer,"%02x-%02x-%02x-%02x-%02x-%02xFC-TOP-ROOF",
szMacAddr[0],szMacAddr[1],szMacAddr[2],
szMacAddr[3],szMacAddr[4],szMacAddr[5]);
close(s);
return OK;
}
/***************************************************************************
function: CheckKey
input:
output:
Description:检查设备是否合法
openssl的一些新版本必须要使用EVP_MD_CTX_new申请控制结构,
老版本不支持这里预留新版本的使用方式
****************************************************************************/
int CheckKey()
{
uchar szCipherTxt[CIPHER_TEXT_LEN] = {0};
char *pcKey = NULL;
char szBuffer[32] = {0};
char szPlainText[32] = {0};
int ret = 0;
int fd = 0;
//获取本地MAC
#ifdef A
ret = GetMacAddr("enp3s0", szBuffer);
#endif
#ifdef B
ret = GetMacAddr("eth0", szBuffer);
#endif
#ifdef C
ret = GetMacAddr("eth0", szBuffer);
#endif
if(ret < 0)
{
LOG(LOG_ERROR, "Get Mac failed.\n");
return ERR;
}
//读取key,
// #if 1时支持版本检测到key文件不存在时自动生成KEY
// #if 0则要求key文件必须存在版本才能起
#if 0
fd = open("/mnt/key", O_RDWR);
if(fd < 0)
{
LOG(LOG_ERROR, "original key not found.\n");
strncpy(szPlainText, szBuffer, sizeof(szPlainText));
LOG(LOG_ERROR, "szPlainText:%s, szBuffer:%s.\n", szPlainText, szBuffer);
if(0 < Encrypt(szPlainText, strlen(szPlainText), szCipherTxt))
{
fd = open("/mnt/key", O_RDWR);
if(fd < 0)
{
LOG(LOG_ERROR, "open key file failed.\n");
return ERR;
}
}
}
#else
fd = open("/mnt/key", O_RDWR);
if(fd < 0)
{
LOG(LOG_ERROR, "open key file failed.\n");
return ERR;
}
#endif
ret = read(fd, szCipherTxt, CIPHER_TEXT_LEN);
if(ret != CIPHER_TEXT_LEN)
{
close(fd);
LOG(LOG_ERROR, "can't read key\n");
return ERR;
}
close(fd);
LOG(LOG_DEBUG, "szPlainText:%s, szBuffer:%s.\n", szPlainText, szBuffer);
//解密
pcKey = (char *)DecryptKey(szCipherTxt, CIPHER_TEXT_LEN);
if(NULL == pcKey)
{
LOG(LOG_ERROR, "Decrypt failed.\n");
return ERR;
}
LOG(LOG_DEBUG, "szPlainText:%s, szBuffer:%s.\n", szPlainText, szBuffer);
//校验结果
if(strcmp(szBuffer, pcKey))
{
LOG(LOG_ERROR, "check key is invaild, buffer:%s, key:%s.\n",szBuffer ,pcKey);
free(pcKey);
return ERR;
}
free(pcKey);
return OK;
}
代码略长,稍作解释。CheckKey()通过ESP_GetMacAddr()获取设备的MAC地址,读取/mnt/key文件,用DecryptKey()接口对文件中的密文进行解密,将解密获取的字符串与MAC地址进行比较,若一致,接口返回成功,反之返回失败。
key文件用notepad++打开,更换多种编码方式打开,始终是乱码。
当/mnt/key文件不存在时有如下打印:
open key file fail.
当/mnt/key文件存在时有如下打印:
szPlainText:, szBuffer:11-22-33-44-55-66FA-TOP-ROOF.
key is -108535744, iv is -108535712.
p_len is 16, f_len is 12, pcPlaintext is 11-22-33-44-55-66FA-TOP-ROOF.
szPlainText:, szBuffer:11-22-33-44-55-66FA-TOP-ROOF.
加密接口实现
现在需要实现CheckKey()接口 “#if 0” 中的Encrypt()加密接口内容,实现后改为“#if 1”
上代码
/***************************************************************************
function: Encrypt
input:
output:
Description:加密获取key
****************************************************************************/
int Encrypt(unsigned char *ucPlaintext, int ucPlaintextLen, unsigned char *ucCiphertext)
{
int ret = ESP_ERR;
int p_len = 0;
int f_len = 0;
int ciphertextLen = 0;
uchar key[32] = {0};
uchar iv[32] = {0};
uint szSalt[] = {11111,11111};
int nrounds = 7;
char szKey[32] = {0};
EVP_CIPHER_CTX *pMdCtx;
pMdCtx = EVP_CIPHER_CTX_new();
if(NULL == pMdCtx)
{
LOG(LOG_ERROR, "alloc ctx failed.\n");
return ERR;
}
GetKey(szKey);
ret = EVP_BytesToKey(EVP_aes_256_cbc(),
EVP_sha1(),
(unsigned char*)szSalt,
(unsigned char*)szKey,
strlen(gszKey),
nrounds,
key,
iv);
if(ret != 32)
{
LOG(LOG_ERROR, "Key size is %d bits, it should be 256 bits\n", ret);
EVP_CIPHER_CTX_free(pMdCtx);
return ERR;
}
LOG(LOG_DEBUG, "key is %d, iv is %d.\n", key, iv);
EVP_EncryptInit_ex(pMdCtx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_EncryptUpdate(pMdCtx, ucCiphertext, &p_len, ucPlaintext, ucPlaintextLen);
ciphertextLen = p_len;
EVP_EncryptFinal_ex(pMdCtx, ucCiphertext + p_len, &f_len);
ciphertextLen += f_len;
ucCiphertext[p_len+f_len] = 0;
LOG(LOG_DEBUG, "p_len is %d, f_len is %d, ucCiphertext is %s.\n", p_len, f_len, ucCiphertext);
EVP_CIPHER_CTX_free(pMdCtx);
//写入文件中
FILE *fp = fopen("/mnt/key", "w");
if(fp == NULL)
{
LOG(LOG_ERROR, "generate key file failed!\n");
return ERR;
}
fprintf(fp, "%s", ucCiphertext);
fclose(fp);
return ciphertextLen;
}
接口实现后,打印如下:
original key not found.
szPlainText:11-22-33-44-55-66FA-TOP-ROOF, szBuffer:11-22-33-44-55-66FA-TOP-ROOF.
key is -22147120, iv is -22147088.
p_len is 16, f_len is 16, ucCiphertext is ⚌r⚌A⚌⚌6⚌}⚌48⚌⚌⚌⚌c<P⚌⚌⚌⚌@P⚌_||.
szPlainText:11-22-33-44-55-66FA-TOP-ROOF, szBuffer:.
key is -22147088, iv is -22147056.
p_len is 16, f_len is 12, pcPlaintext is 11-22-33-44-55-66FA-TOP-ROOF.
szPlainText:11-22-33-44-55-66FA-TOP-ROOF, szBuffer:.
check key is invaild, buffer:, key:11-22-33-44-55-66FA-TOP-ROOF.
check key failed.
加密接口中怀疑有数组越界,导致buffer变量丢失,进而check key failed.但是接口成功生成了/mnt/key文件。(热心的朋友可以帮忙查一下哪里越界了)
再次运行程序,打印如下,
szPlainText:, szBuffer:11-22-33-44-55-66FA-TOP-ROOF.
key is -939246448, iv is -939246416.
p_len is 16, f_len is 12, pcPlaintext is 11-22-33-44-55-66FA-TOP-ROOF.
szPlainText:, szBuffer:11-22-33-44-55-66FA-TOP-ROOF.
ESP_CheckKey()接口返回成功,验证上一次生成的/mnt/key文件可用。
参考
https://blog.csdn.net/substitute_coder/article/details/53072100