3DES crypt helper

今天同事让写一个DLL给他,3DES+BASE64 加解密接口2个。
以前做的实验,做了半边(java加密,C解密),因为那次就半边的需求。
这次都要由C这边来做(C加密,C解密), 磨叽了2个小时。
其实正确的姿势是,以前就应该将实验做全的,这次应该拿过来就好用。
又杯具一次, 一个愉快的周末没开个好头.

对于基础代码,如果最开始没写好测试用例,以后有可能会写错。会怀疑到接口实现的问题上,在调试上容易浪费时间。

openssl代码维护真容易,都是自解释的函数名和参数名,而且参数摆放规律一致,如果有一个可用的加密函数,很容易维护出一个可用的解密函数。

实验

工程下载点

src_3DESCryptHelper_2017_0528_0026.zip

工程输出

2017/05/28  00:24    <DIR>          .
2017/05/28  00:24    <DIR>          ..
2017/05/28  00:24            12,800 3DESCryptHelper.dll
2017/05/28  00:24             1,041 3DESCryptHelper.exp
2017/05/28  00:24             2,280 3DESCryptHelper.lib
2017/04/08  11:27         1,183,232 libeay32.dll
2017/04/08  11:27           270,848 ssleay32.dll
2017/05/28  00:24            10,240 test3DESCryptHelper.exe
               6 个文件      1,480,441 字节

接口测试程序

// test3DESCryptHelper.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <atlconv.h>
#include <string>
#include "../dll/IF_3DESCryptHelper.h"
#pragma comment(lib, "3DESCryptHelper.lib")

#define _3DES_CRYPT_KEY "123456781234567812345678"

int _tmain(int argc, _TCHAR* argv[])
{
    USES_CONVERSION;
    std::string strEncBase64 = "";
    std::string strPlainTxt = "";

    strEncBase64 = IF_3DES_CryptHlerper_encrypt("hello", _3DES_CRYPT_KEY);
    printf("strEncBase64 = %s\n", strEncBase64.c_str());

    strPlainTxt = IF_3DES_CryptHlerper_decrypt(strEncBase64.c_str(), _3DES_CRYPT_KEY);
    printf("strPlainTxt = %s\n", strPlainTxt.c_str());

	system("pause");
	return 0;
}

运行效果

strEncBase64 = sRjgl3qfUBnbhZgumtlVgtCN+YQap6PM
strPlainTxt = hello
请按任意键继续. . .

接口定义

// @file IF_3DESCryptHelper.h
// @brief 接口文件

#ifndef __IF_3DES_CRYPT_HELPER_H__
#define __IF_3DES_CRYPT_HELPER_H__

#ifndef _3DES_CRYPT_HELPER_EXPORTS
#define _3DES_CRYPT_HELPER_API __declspec(dllimport)
#else
#define _3DES_CRYPT_HELPER_API __declspec(dllexport)
#endif

// =============================================================================
// 错误码定义
// =============================================================================
#define IF_OK 0

#define IF_ERR_BASE IF_OK // 接口执行成功

#define IF_ERR_PARAM1_INVALID (IF_ERR_BASE + 1) // 参数1无效
#define IF_ERR_PARAM2_INVALID (IF_ERR_BASE + 2)  // 参数2无效
#define IF_ERR_PARAM3_INVALID (IF_ERR_BASE + 3)  // 参数3无效

#define IF_ERR_PARAM1_LEN_TOO_SMALL (IF_ERR_BASE + 4)  // 参数1缓冲区长度太短了
#define IF_ERR_PARAM2_LEN_TOO_SMALL (IF_ERR_BASE + 5)  // 参数2缓冲区长度太短了
#define IF_ERR_PARAM3_LEN_TOO_SMALL (IF_ERR_BASE + 6)  // 参数3缓冲区长度太短了

#define IF_ERR_NOT_IMP (IF_ERR_BASE + 7)  // 接口未实现

#define IF_ERR_UNKNOWN (IF_ERR_BASE + 0x1000)  // 未知错误

// =============================================================================
// 接口定义
// =============================================================================
#ifdef __cplusplus
extern "C" {
#endif

// @fn _CryptHlerper_encrypt
// @brief 文本加密接口
//	给定明文和密钥, 输出密文(3DES加密+base64)
// @param psz_plain_txt, 明文文本
// @param psz_key, 密钥
// @return const char*, 密文
_3DES_CRYPT_HELPER_API const char* __stdcall IF_3DES_CryptHlerper_encrypt(/*IN*/ const char* psz_plain_txt, /*IN*/ const char* psz_key);

// @fn 3DES_CryptHlerper_decrypt
// @brief 文本解密接口
//	给定加密接口输出的密文和密钥,输出明文(3DES解密+unbase64)
// @param psz_cipher_txt, 密文(3DES_CryptHlerper_encrypt的输出)
// @param psz_key, 密钥
// @return const char*, 明文文本
_3DES_CRYPT_HELPER_API const char* __stdcall IF_3DES_CryptHlerper_decrypt(/*IN*/ const char* psz_cipher_txt, /*IN*/ const char* psz_key);

#ifdef __cplusplus
}
#endif

#endif // #ifndef __IF_3DES_CRYPT_HELPER_H__

// LsBase64.h: interface for the LsBase64 class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_LSBASE64_H__28E02995_79BF_48B8_9809_9A575CB7E700__INCLUDED_)
#define AFX_LSBASE64_H__28E02995_79BF_48B8_9809_9A575CB7E700__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

namespace ns_ls
{
    unsigned int base64_encode(const unsigned char* bytes_to_encode, unsigned int in_len, unsigned char* encoded_buffer, unsigned int& out_len);
    unsigned int base64_decode(const unsigned char* encoded_string, unsigned int in_len, unsigned char* decoded_buffer, unsigned int& out_len);
}

#endif // !defined(AFX_LSBASE64_H__28E02995_79BF_48B8_9809_9A575CB7E700__INCLUDED_)

接口实现

// 3DESCryptHelper.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include <atlconv.h>
#include <string>
#include <WinSock2.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib")
#include "IF_3DESCryptHelper.h"
#include "LsBase64.h"

#include "openssl\evp.h"
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")

// iv is 20170528
#define FILL_MY_IV iv[0] = 2; \
    iv[1] = 0; \
    iv[2] = 1; \
    iv[3] = 7; \
    iv[4] = 0; \
    iv[5] = 5; \
    iv[6] = 2; \
    iv[7] = 8;

std::string g_str_txt_was_encrypt = ""; // 加密后的密文
std::string g_str_txt_was_decrypt = ""; // 解密后的明文

static void fn_copy_by_end_char(WCHAR * pDst, WCHAR * pSrc, WCHAR cEndChar);
int des3_DecryptBuffer(unsigned char* key, unsigned char* iv, unsigned char* in_dec, unsigned char* out_dec, int in_len, int* out_len);
int des3_EncryptBuffer(unsigned char* key, unsigned char* iv, unsigned char* in_enc, unsigned char* out_enc, int in_len, int* out_len);

BOOL php_time_2_systemtime(long lPhpTime, SYSTEMTIME* pst)  
{  
    BOOL        bRc = FALSE;  
    time_t      tmt = -1;  
    struct tm*  pGmt = NULL;  

    do   
    {  
        if (NULL == pst)  
            break;  

        tmt = lPhpTime;  
        pGmt = gmtime(&tmt);  

        if (NULL == pGmt)  
            break;  

        pst->wYear = 1900 + pGmt->tm_year;  
        pst->wMonth = 1 + pGmt->tm_mon;  
        pst->wDay = pGmt->tm_mday;  
        pst->wHour = pGmt->tm_hour;  
        pst->wMinute = pGmt->tm_min;  
        pst->wSecond = pGmt->tm_sec;  
        pst->wDayOfWeek = pGmt->tm_wday;  

        bRc = TRUE;  
    } while (0);  

    return bRc;  
}  

static void fn_copy_by_end_char(WCHAR * pDst, WCHAR * pSrc, WCHAR cEndChar)
{
	DWORD dwIndex = 0;

	if((NULL != pDst) && (NULL != pSrc))
	{
		do
		{
			if((L'\0' == pSrc[dwIndex]) || (cEndChar == pSrc[dwIndex]))
			{
				break;
			}

			pDst[dwIndex] = pSrc[dwIndex];
			dwIndex++;
		}
		while(1);
	}
}

/*
* key:加密密钥,3DES密钥size = 24
* iv:加密初始向量
* in_dec:密文数组,输入数组
* out_dec:解密后的数组,输出数组
* in_len:密文长度
* out_len:明文长度
* */
//解密函数
int des3_DecryptBuffer(unsigned char* key, unsigned char* iv, unsigned char* in_dec, unsigned char* out_dec, int in_len, int* out_len)
{
    int out1 = 0;  //第一次使用update解密的数据长度
    int out2 = 0; //剩余的字段,经过final解密并去除填充后的长度
    int rv = 0;
    EVP_CIPHER_CTX ctx;
    //初始化ctx
    EVP_CIPHER_CTX_init(&ctx);
    //设置解密的算法、key和iv
    // java端加密模式采用, "DESede/CBC/PKCS5Padding", so 参数2为EVP_des_ede3_cbc()
    rv = EVP_DecryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, key, iv);

    if (rv != 1) {
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }

    //循环读取原文,解密后后保存到明文文件。
    rv = EVP_DecryptUpdate(&ctx, out_dec, &out1, in_dec, in_len);//解密

    if (rv != 1) {
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }

    //解密结束
    rv = EVP_DecryptFinal_ex(&ctx, out_dec + out1, &out2);

    if (rv != 1) {
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }

    *out_len = (out1 + out2);
    EVP_CIPHER_CTX_cleanup(&ctx);//清除EVP加密上下文环境

    return 0;
}

int des3_EncryptBuffer(unsigned char* key, unsigned char* iv, unsigned char* in_enc, unsigned char* out_enc, int in_len, int* out_len)
{
    int out1 = 0;  //第一次使用update解密的数据长度
    int out2 = 0; //剩余的字段,经过final解密并去除填充后的长度
    int rv = 0;
    EVP_CIPHER_CTX ctx;
    //初始化ctx
    EVP_CIPHER_CTX_init(&ctx);
    //设置解密的算法、key和iv
    // java端加密模式采用, "DESede/CBC/PKCS5Padding", so 参数2为EVP_des_ede3_cbc()
    rv = EVP_EncryptInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, key, iv);

    if (rv != 1) {
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }

    //循环读取原文,解密后后保存到明文文件。
    rv = EVP_EncryptUpdate(&ctx, out_enc, &out1, in_enc, in_len);//解密

    if (rv != 1) {
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }

    //解密结束
    rv = EVP_EncryptFinal_ex(&ctx, out_enc + out1, &out2);

    if (rv != 1) {
        EVP_CIPHER_CTX_cleanup(&ctx);
        return -1;
    }

    *out_len = (out1 + out2);
    EVP_CIPHER_CTX_cleanup(&ctx);//清除EVP加密上下文环境

    return 0;
}

_3DES_CRYPT_HELPER_API const char* __stdcall IF_3DES_CryptHlerper_encrypt(/*IN*/ const char* psz_plain_txt, /*IN*/ const char* psz_key)
{
    USES_CONVERSION;

	DWORD dwRc = IF_ERR_UNKNOWN;
    unsigned char key[EVP_MAX_KEY_LENGTH]; //保存密钥的数组
    unsigned char iv[EVP_MAX_IV_LENGTH]; //保存初始化向量的数组

    char* psz_plain_txt_new = NULL;
    int ilen_plain_txt_new = 0;

    char* psz_cipher_txt = NULL;
    int ilen_cipher_txt = 0;

    char* psz_base64_txt = NULL;
    int ilen_base64_txt = 0;

    UINT ulRc = 0;
    UINT ulLenOut = 0;
    int iLenEncOut = 0;

    memset(key, 0, sizeof(key));
    memset(iv, 0, sizeof(iv));
    g_str_txt_was_encrypt.clear();

    // 设置IV
    // static final byte m_iv8_byte_ary[] = {0,0,0,0,0,0,0,0};
    // java加密时, iv就8个字节
    memset(iv, 0, sizeof(iv));
	FILL_MY_IV

	do
	{
        if ((NULL == psz_plain_txt) || (strlen(psz_plain_txt) <= 0))
		{
			dwRc = IF_ERR_PARAM1_INVALID;
			break;
		}

		if ((NULL == psz_key) || (strlen(psz_key) != 24))
		{
			dwRc = IF_ERR_PARAM2_INVALID;
			break;
		}

        // 设置key, 3DES Key is 24bytes
        // String str_key = new String("123456781234567812345678");
        memcpy(key, psz_key, 24);

        ilen_plain_txt_new = strlen(psz_plain_txt);
        if (0 != (ilen_plain_txt_new % 16)) {
            ilen_plain_txt_new = ilen_plain_txt_new - (ilen_plain_txt_new % 16) + 16; // base64还会再长一些
        }

        psz_plain_txt_new = new char[ilen_plain_txt_new + 1];
        ZeroMemory(psz_plain_txt_new, ilen_plain_txt_new + 1);
        strcpy(psz_plain_txt_new, psz_plain_txt);

        ilen_cipher_txt = ilen_plain_txt_new * 2;
        psz_cipher_txt = new char[ilen_cipher_txt + 1];
        ZeroMemory(psz_cipher_txt, ilen_cipher_txt + 1);

        ilen_base64_txt = ilen_cipher_txt * 2;
        psz_base64_txt = new char[ilen_base64_txt + 1];
        ZeroMemory(psz_base64_txt, ilen_base64_txt + 1);

        iLenEncOut = ilen_cipher_txt;
        if (0 != des3_EncryptBuffer(key, iv, (BYTE*)psz_plain_txt_new, (BYTE*)psz_cipher_txt, ilen_plain_txt_new, &iLenEncOut)) {
            break;
        }

        // base64
        ulLenOut = 0;
        ulRc = ns_ls::base64_encode((const BYTE *)psz_cipher_txt, iLenEncOut, (BYTE *)psz_base64_txt, ulLenOut);

        // test ok
//         UINT i_tmp_len_out = 0;
//         ZeroMemory(psz_cipher_txt, ilen_cipher_txt + 1);
//         ulRc = ns_ls::base64_decode((const BYTE *)psz_base64_txt, ulLenOut, (BYTE*)psz_cipher_txt, i_tmp_len_out);

        g_str_txt_was_encrypt = psz_base64_txt;
	}
	while(0);

    if (NULL != psz_plain_txt_new) {
        delete[] psz_plain_txt_new;
        psz_plain_txt_new = NULL;
    }

    if (NULL != psz_cipher_txt) {
        delete[] psz_cipher_txt;
        psz_cipher_txt = NULL;
    }

    if (NULL != psz_base64_txt) {
        delete[] psz_base64_txt;
        psz_base64_txt = NULL;
    }

    return g_str_txt_was_encrypt.c_str();
}

_3DES_CRYPT_HELPER_API const char* __stdcall IF_3DES_CryptHlerper_decrypt(/*IN*/ const char* psz_cipher_txt, /*IN*/ const char* psz_key)
{
    USES_CONVERSION;

    DWORD dwRc = IF_ERR_UNKNOWN;
    unsigned char key[EVP_MAX_KEY_LENGTH]; //保存密钥的数组
    unsigned char iv[EVP_MAX_IV_LENGTH]; //保存初始化向量的数组

    char* psz_un_base64_txt = NULL;
    int ilen_un_base64_txt = 0;

    char* psz_plain_txt = NULL;
    int ilen_plain_txt = 0;

    UINT ulRc = 0;
    UINT ulLenOut = 0;
    int iLenDecOut = 0;

    memset(key, 0, sizeof(key));
    memset(iv, 0, sizeof(iv));
    g_str_txt_was_encrypt.clear();

    // 设置IV
    // static final byte m_iv8_byte_ary[] = {0,0,0,0,0,0,0,0};
    // java加密时, iv就8个字节
    memset(iv, 0, sizeof(iv));
	FILL_MY_IV

    do
    {
        if ((NULL == psz_cipher_txt) || (strlen(psz_cipher_txt) <= 0))
        {
            dwRc = IF_ERR_PARAM1_INVALID;
            break;
        }

        if ((NULL == psz_key) || (strlen(psz_key) != 24))
        {
            dwRc = IF_ERR_PARAM2_INVALID;
            break;
        }

        // 设置key, 3DES Key is 24bytes
        // String str_key = new String("123456781234567812345678");
        memcpy(key, psz_key, 24);

        ilen_un_base64_txt = strlen(psz_cipher_txt);

        psz_un_base64_txt = new char[ilen_un_base64_txt + 1];
        ZeroMemory(psz_un_base64_txt, ilen_un_base64_txt + 1);

        ilen_plain_txt = ilen_un_base64_txt;
        psz_plain_txt = new char[ilen_plain_txt + 1];
        ZeroMemory(psz_plain_txt, ilen_plain_txt + 1);

        // unbase64
        ulLenOut = 0;
        ulRc = ns_ls::base64_decode((const BYTE *)psz_cipher_txt, strlen(psz_cipher_txt), (BYTE *)psz_un_base64_txt, ulLenOut);

        iLenDecOut = ulLenOut;
        if (0 != des3_DecryptBuffer(key, iv, (BYTE*)psz_un_base64_txt, (BYTE*)psz_plain_txt, ulLenOut, &iLenDecOut)) {
            break;
        }

        psz_plain_txt[iLenDecOut] = '\0';
        g_str_txt_was_decrypt = psz_plain_txt;
    }
    while(0);

    if (NULL != psz_un_base64_txt) {
        delete[] psz_un_base64_txt;
        psz_un_base64_txt = NULL;
    }

    if (NULL != psz_plain_txt) {
        delete[] psz_plain_txt;
        psz_plain_txt = NULL;
    }

    return g_str_txt_was_decrypt.c_str();
}
// LsBase64.cpp: implementation of the LsBase64 class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include "LsBase64.h"

// https://www.codeproject.com/Tips/813146/Fast-base-functions-for-encode-decode

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

using namespace std;
namespace ns_ls
{
    static const std::string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";
        
    static inline bool is_base64(unsigned char c)
    {
        return (isalnum(c) || (c == '+') || (c == '/'));
    }
    
    unsigned int base64_encode(const unsigned char* bytes_to_encode, unsigned int in_len, unsigned char* encoded_buffer, unsigned int& out_len)
    {
        int i = 0;
        int j = 0;
        unsigned char char_array_3[3] = { 0, 0, 0 };
        unsigned char char_array_4[4] = { 0, 0, 0, 0 };
        out_len = 0;
        
        while (in_len--) {
            char_array_3[i++] = *(bytes_to_encode++);
            
            if (i == 3) {
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;
                
                for (i = 0; i < 4 ; i++) {
                    encoded_buffer[out_len++] = base64_chars[char_array_4[i]];
                }
                
                i = 0;
            }
        }
        
        if (i) {
            for (j = i; j < 3; j++) {
                char_array_3[j] = '\0';
            }
            
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
            char_array_4[3] = char_array_3[2] & 0x3f;
            
            for (j = 0; j < (i + 1); j++) {
                encoded_buffer[out_len++] = base64_chars[char_array_4[j]];
            }
            
            while (i++ < 3) {
                encoded_buffer[out_len++] = '=';
            }
        }
        
        return out_len;
    }
    
    unsigned int base64_decode(const unsigned char* encoded_string, unsigned int in_len, unsigned char* decoded_buffer, unsigned int& out_len)
    {
        size_t i = 0;
        size_t j = 0;
        int in_ = 0;
        unsigned char char_array_3[3] = { 0, 0, 0 };
        unsigned char char_array_4[4] = { 0, 0, 0, 0 };
        out_len = 0;
        
        while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
            char_array_4[i++] = encoded_string[in_];
            in_++;
            
            if (i == 4) {
                for (i = 0; i < 4; i++) {
                    char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
                }
                
                char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
                
                for (i = 0; i < 3; i++) {
                    decoded_buffer[out_len++] = char_array_3[i];
                }
                
                i = 0;
            }
        }
        
        if (i) {
            for (j = i; j < 4; j++) {
                char_array_4[j] = 0;
            }
            
            for (j = 0; j < 4; j++) {
                char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
            }
            
            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
            
            for (j = 0; (j < i - 1); j++) {
                decoded_buffer[out_len++] = char_array_3[j];
            }
        }
        
        return out_len;
    }
}

猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/72788440
今日推荐