本人在撰写代码时遇到需要对一些用户信息进行加密处理的情形。经过查阅资料,当然主要是报大腿成功解决了。下面做一些记录总结。
参考文章:
https://blog.csdn.net/yasi_xi/article/details/9066003
https://en.wikipedia.org/wiki/HMAC
环境完善:
该版本需要调用libssl.so.1.0.0,编译、运行时需要拷贝该库文件到lib目录。 检查存在 lib/libssl.so.1.0.0 及 libssl.so文件链接,如:
lrwxrwxrwx 1 ****** users 15 8月 2 21:01 libssl.so -> libssl.so.1.0.0
-rwxr-xr-x 1 ****** users 478235 8月 2 21:01 libssl.so.1.0.0
代码编写:
在需要调用加密的.c文件里添加头文件#include "./openssl/hmac.h"并定义宏MAX_INFOR_LENGTH
在该.c文件的同层新建文件夹openssl,并从openssl官网下载的openssl1.0.0里的一些相关头文件拷贝进去,多拷贝一些也没问题。
在软件初始化的时候把秘钥添加进去。秘钥可以做成配置项,以便动态的修改。
Strcpy(gConfig.mackey, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
设计以下三个函数,调用最后一个函数可以对内容进行加密。由于这是linux下的库,所以添加添加了条件编译的判断代码。
函数一:HMAC加密核心处理函数
#ifndef _WIN32
int HmacEncode(const char * input, unsigned int inlen, unsigned char * output, unsigned int* outlen,const char * algo)
{
unsigned char mdstr[MAX_INFOR_LENGTH+1] = {0};
unsigned int mdlen = MAX_INFOR_LENGTH+1, keylen, tmplen;
EVP_MD * engine = NULL;
HMAC_CTX ctx;
if(strcasecmp("sha512", algo) == 0) {
engine = EVP_sha512();
}
else if(strcasecmp("sha256", algo) == 0) {
engine = EVP_sha256();
}
else if(strcasecmp("sha1", algo) == 0) {
engine = EVP_sha1();
}
else if(strcasecmp("md5", algo) == 0) {
engine = EVP_md5();
}
else if(strcasecmp("sha224", algo) == 0) {
engine = EVP_sha224();
}
else if(strcasecmp("sha384", algo) == 0) {
engine = EVP_sha384();
}
else if(strcasecmp("sha", algo) == 0) {
engine = EVP_sha();
}
else if(strcasecmp("md2", algo) == 0) {
engine = EVP_md2();
}
else {
LOG_printf( "Algorithm %s is not supported by this program!", algo);
return -1;
}
keylen = strlen((char *)gConfig.mackey);
// 加密
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, (char *)gConfig.mackey, keylen, engine, NULL);
HMAC_Update(&ctx, (unsigned char*)input, inlen);
HMAC_Final(&ctx, mdstr, &mdlen);
// 转换成16进制字符串
tmplen = *outlen;
if (*outlen == 0)
{
*outlen = inlen;
tmplen = MAX_SENS_INFOR_LEN;
}
sagBinToHex(output, tmplen, mdstr, mdlen, 1);
// 后释放,防止ssl版本不对mdstr被清除
HMAC_CTX_cleanup(&ctx);
*outlen = strlen((char *)output);
LOG_printf("inlen[%d] mdlen[%d] outlen[%d] output[%s]", inlen, mdlen, *outlen, output);
// 长度保持与输入一致
if (inlen < *outlen)
{
output[inlen] = '\0';
*outlen = inlen;
}
LOG_printf("input[%s] inlen[%d] mdlen[%d] outlen[%d] output[%s]", input, inlen, mdlen, *outlen, output);
return 0;
}
#endif
函数二:转换成16进制字符串函数
unsigned char * sagBinToHex(unsigned char * out, unsigned intoutLen, const unsigned char * in, unsigned intinLen, unsigned char flag)
{
char buf[4];
UINT32 i, prnLen, sepLen;
out[0] = 0;
prnLen = 0;
if (flag == 1)
sepLen = 2;
else
sepLen = 3;
for (i = 0; i < inLen; ++ i)
{
sprintf(buf, "%02x", (unsigned char)in[i]);
if (flag == 2) // 以空格分隔
strcpy(char *)buf, " ");
if (prnLen + sepLen >= outLen)
{
out[prnLen] = '\0';
return out;
}
prnLen += sepLen;
strcat((char *)out, buf);
}
*(out + 3 * inLen) = '\0';
return out;
}
函数三:代码中直接调用的函数
int HmacShaEncrypt(unsigned char * out, unsigned intoutLen, const unsigned char * in, unsigned char * hmac_type)
{
#ifndef _WIN32
if (gConfig.mackey[0] != '\0')
{
unsigned char strmd[MAX_INFOR_LENGTH+1];
unsigned int mdlen = MAX_INFOR_LENGTH+1;
HmacEncode(in, strlen(in), strmd, &mdlen,hmac_type);
if (mdlen < MAX_INFOR_LENGTH)
strmd[mdlen] = '\0';
else
strmd[MAX_INFOR_LENGTH] = '\0';
strcpy(out, strmd);
return out;
}
#endif
}
编译时makefile里需要添加LDLIBS=……-lssl……
调试自测日志:
test sensitive result:f1474d23b