因工作对接需求,需要解析出对方通过http发送过来的字符串(3des+base64加密),而对端(可以理解为客户端)关于这块内容使用的纯jave语言编写,并且调用的是原生的jdk的包,具体见:https://github.com/anylogic/alogic/blob/master/alogiccommon/src/main/java/com/anysoft/util/code/coder/DES3.java
而本端(可以理解为服务端)是使用的nginx+luajit搭建的http服务端。而luajit只能调用通过c语言编写的动态库(通过ffi的方式。具体的细节广大网友可以自行查阅相关资料,这块不作为本文的重点),于是,c语言版的3des+base64加解密源码就显得迫不及待了!
在网上搜罗大量的3des+base64的相关源码,找到了大量的版本(包括c/c++),没有一份能准确无误的解析出对端发送过来的字符串。终于在慢慢探索的道路上,找到了一份能基本解析的c++的版本。为什么说是基本解析,因为里面包含了一些小的瑕疵,真正用在项目上还存在一定的差距。那么,目前摆在面前的有两个问题:

1.将c++版翻译成c版。

源c++版地址:
不做过多的诉说,有一定c/c++基础的同学都能做到。
只是在字符串转16进制和16进制转字符串在这里贴一下代码。
c++是通过流的方式去处理的,与c还是有很大的不同。

//字符串转化为16进制
unsigned char* str_to_hex(const char *str) 
{
    int i;
    unsigned char *buff = NULL;
    int nLen = strlen(str);
    int size = sizeof(unsigned char *) * nLen / 2;
    buff = (unsigned char*) malloc(size);
    memset((void*) buff, 0, size);
    	
    char szTmp[3];
    for(i = 0;i<nLen;i++)
    {   
        sprintf(szTmp,"%02x",(unsigned char)str[i]);
        memcpy(&buff[i*2],szTmp,2);
    }   
    return buff;
}
//16进制转化为字符串
unsigned char * hex_to_str(const char *src)
{
    int i;
    unsigned char hbyte,lbyte;
    int len = strlen(src);
        
    unsigned char *buff = NULL;
    buff = (unsigned char *)malloc(len/2);
            
    for (i=0;i<len;i+=2)
    {
        hbyte = toupper(src[i]);
        lbyte = toupper(src[i+1]);
        
        if (hbyte > 0x39) {
            hbyte -= 0x37;
        } else {
            hbyte -= 0x30;
        }
        if (lbyte > 0x39) {
            lbyte -= 0x37;
        } else {
            lbyte -= 0x30;
        }
        buff[i/2] = (hbyte << 4)|lbyte;
    }
    return buff;
}

2.解决里面的瑕疵。

2.1:不能正确解析出对端发送过来的数据。

走查源码发现了问题了所在。在数组清除的地方存在问题,当然这个要感谢另一个博主,在他的博文中: 有提到:
3des-ecb加密方式:
1.24位密钥,不足24位的右补0x00;
2.加密内容8位补齐,补齐方式为:少1位补一个0x01,少2位补两个0x02,…
3.本身已8位对齐的,后面补八个0x08。
很明显下面c++版清零的补齐处理方式与上面的观点相悖

/************************************************************************
*功能:数组清空
************************************************************************/
void Des::clearBuff(char *buff, int length) {
    for (int i = 0; i < length; i++) {
        buff[i] = '\0';
    }
}

2.修改后的c版

//判断是否是8位对齐。补齐方式为:少1位补一个0x01,少2位补两个0x02,…
    char ch = 0; // 不过本人觉得ch初始化为0的方式有些不妥,是否要初始化为8,这个要留给博友们去验证!
    if (strlen % 8 == 0) {
        block = strlen / 8;
    } else {
        block = strlen / 8 + 1;
        ch = 8 - strlen % 8;
    }
    /************************************************************************
     *功能:数组清空
    ************************************************************************/
    void clearBuff(char *buff, int length, char ch) {
        int i;
        for (i = 0; i < length; i++) {
            buff[i] = ch;
        }
    }

2.2:解密后数据长度存在问题,每次解析出来的数据长度总是为8的倍数。

那么源数据不是8的倍数的时候就会出现问题。默认会填充数据进去。后打印填充数据,发现填充的数据为数字,并且该数字等于填充长度,貌似与加密的处理方式一样。但后面通过大量的实例发现存在小部分的情况不是这样,于是就只能粗暴的处理了,在每次返回解密数据的时候做下面的处理

int s = strlen(out) - 1;
    for(s;s > 0;s--) {
        if (out[s] < 8) {
            out[s] = '\0';
        }
    }

经过上面的处理后,问题得到解决。