我最近工作上在与前端web程序员对接时,经常会遇到把数据库密码用MD5加密,把后台的文件名和文件夹用MD5加密。
因为不是工科出身,泥腿子转行一个,我理解能力比较差,今天整理了一下。
从书中找到一个实例
- 实例说明
密码加密是软件系统所应具备的基本功能,许多程序设计人员为了方便只是将用户设定的密码以明文的形式存入数据库或文件中。这样做非常严重的危害了系统运行的安全性,所以用户设置的密码很容易就会被发现。所以为了增加系统的安全性,最好对用户设置的密码进行加密,这样别人即使看到了密码也只是加密后的密码。该实例使用的是MD5算法,该算法是一个不能返向解密的算法,如图1所示。
- 技术要点
许多程序设计人员认为MD5算法是一个非常复杂的算法,所以设有自已去实现,其实只要按照MD5算法的原理设计程序并不是一件复杂的事。MD5算法以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由4个32位分组组成,将这4个32位分组级联后将生成一个128位散列值(16个字符)。
在MD5中首先定义4个32位的16进制数,被称为链接变量。定义代码如下:
#define MD5_INIT_STATE_0 0x67452301 #define MD5_INIT_STATE_1 0xefcdab89 #define MD5_INIT_STATE_2 0x98badcfe #define MD5_INIT_STATE_3 0x10325476
当4个链接变量设置完成后就可以对输入的数据进行4轮主循环了,而每轮主循环又进行16次操作。每轮循环对应了一个操作函数通过参数的不同返回4个32位的变量值,当所有循环结束后再将最终得到的4个32位变量值与链接变量相加赋给对应的链接变量。这4个操作函数的算法如下:
FF(X,Y,Z) =(X&Y)|((~X)&Z) //第一轮调用 GG(X,Y,Z) =(X&Z)|(Y&(~Z)) //第二轮调用 HH(X,Y,Z) =X^Y^Z //第3轮调用 II(X,Y,Z)=Y^(X|(~Z)) //第4轮调用
在上面的算法中X、Y和Z的取值分别是从用户输入数据、MD5_S数组和MD5_T数组中取得,其中X值是跟据XINDEX数组中的值做为索引获取的。XINDEX数组和MD5_S数组中的值可由程序员自行修改来改变MD5加密的结果。而MD5_T组数中的数据是固定义是由4294967296(2的32次方)*abs(fsin(索引值))计算得来的。这3个数组的定义分别如下:
//参加运算的S盒 static DWORD MD5_S[4][16] = { {7,12,17,22,9,6,8,5,7,4,17,3,7,2,17,10}, {5,9,14,20,7,4,10,12,5,8,14,6,5,9,3,20}, {4,11,16,23,5,8,10,12,4,7,9,23,8,11,22,14}, {6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21} }; //获取加密数据的索引表 static int XINDEX[4][16] = { {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12}, {5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2}, {0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9} }; //参加运算的数组 static DWORD MD5_T[64] = { 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, 0x6b901122,0xfd987193,0xa679438e,0x49b40821, 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa, 0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed, 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a, 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70, 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039, 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1, 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 };
- 实现过程
(1)新建一个基于对话框的工程。
(2)在对话框上添加二个文本编辑框控件和一个按钮控件。
(3)首先对MD5加密类进行定义。实现代码如下:
两个封装好的MD5函数文件,在网上也可以百度搜到别人的,拿来直接调用。
md5_encode.h
#pragma once /* ******************************************************* * brief: md5 encryption * author: Monkey.Knight ******************************************************* */ #ifndef __MD5_ENCODE_H__ #define __MD5_ENCODE_H__ // std #include <string> // define #define UInt32 unsigned int #define BIT_OF_BYTE 8 #define BIT_OF_GROUP 512 #define SRC_DATA_LEN 64 // 四个非线性函数宏定义 #define DEF_F(X, Y, Z ) ((( (X) & (Y) )|((~X)&(Z)))) #define DEF_G(X, Y, Z) (((X)&(Z))|((Y)&(~Z))) #define DEF_H(X, Y, Z) ((X)^(Y)^(Z)) #define DEF_I(X, Y, Z) ((Y)^((X)|(~Z))) // 求链接数函数宏定义 #define FF(a, b, c, d, Mj, s, ti) (a = b + CycleMoveLeft((a + DEF_F(b,c,d) + Mj + ti),s)); #define GG(a, b, c, d, Mj, s, ti) (a = b + CycleMoveLeft((a + DEF_G(b,c,d) + Mj + ti),s)); #define HH(a, b, c, d, Mj, s, ti) (a = b + CycleMoveLeft((a + DEF_H(b,c,d) + Mj + ti),s)); #define II(a, b, c, d, Mj, s, ti) (a = b + CycleMoveLeft((a + DEF_I(b,c,d) + Mj + ti),s)); class Md5Encode { public: // 4轮循环算法 struct ParamDynamic{ UInt32 ua_; UInt32 ub_; UInt32 uc_; UInt32 ud_; UInt32 va_last_; UInt32 vb_last_; UInt32 vc_last_; UInt32 vd_last_; }; public: Md5Encode() { } std::string Encode(std::string src_info); protected: UInt32 CycleMoveLeft(UInt32 src_num, int bit_num_to_move); UInt32 FillData(const char *in_data_ptr, int data_byte_len, char** out_data_ptr); void RoundF(char *data_512_ptr, ParamDynamic & param); void RoundG(char *data_512_ptr, ParamDynamic & param); void RoundH(char *data_512_ptr, ParamDynamic & param); void RoundI(char *data_512_ptr, ParamDynamic & param); void RotationCalculate(char *data_512_ptr, ParamDynamic & param); std::string GetHexStr(unsigned int num_str); private: // 幻数定义 static const int kA; static const int kB; static const int kC; static const int kD; static const unsigned long long k_ti_num_integer; }; #endif
md5_encode.cpp
#include "StdAfx.h" #include "md5_encode.h" #include <iostream> #include<math.h> // 幻数定义 const int Md5Encode::kA = 0x67452301; const int Md5Encode::kB = 0xefcdab89; const int Md5Encode::kC = 0x98badcfe; const int Md5Encode::kD = 0x10325476; const unsigned long long Md5Encode::k_ti_num_integer = 4294967296; // function: CycleMoveLeft // @param src_num:要左移的数 // @param bit_num_to_move:要移动的bit位数 // @return 循环左移后的结果数 UInt32 Md5Encode::CycleMoveLeft(UInt32 src_num, int bit_num_to_move) { UInt32 src_num1 = src_num; UInt32 src_num2 = src_num; if (0 >= bit_num_to_move) { return src_num; } UInt32 num1 = src_num1 << bit_num_to_move; UInt32 num2 = src_num2 >> (32 - bit_num_to_move); return ((src_num1 << bit_num_to_move) | (src_num2 >> (32 - bit_num_to_move))); } // function: FillData // @param in_data_ptr: 要加密的信息数据 // @param data_byte_len: 数据的字节数 // @param out_data_ptr: 填充必要信息后的数据 // return : 填充信息后的数据长度,以字节为单位 UInt32 Md5Encode::FillData(const char *in_data_ptr, int data_byte_len, char** out_data_ptr) { int bit_num = data_byte_len*BIT_OF_BYTE; int grop_num = bit_num / BIT_OF_GROUP; int mod_bit_num = bit_num % BIT_OF_GROUP; int bit_need_fill = 0; if (mod_bit_num > (BIT_OF_GROUP - SRC_DATA_LEN)) { bit_need_fill = (BIT_OF_GROUP - mod_bit_num); bit_need_fill += (BIT_OF_GROUP - SRC_DATA_LEN); } else { bit_need_fill = (BIT_OF_GROUP - SRC_DATA_LEN) - mod_bit_num; // 这里多加了一个BIT_OF_GROUP,避免bit_need_fill正好等于0,暂时不加 } int all_bit = bit_num + bit_need_fill; if (0 < bit_need_fill) { *out_data_ptr = new char[all_bit / BIT_OF_BYTE + SRC_DATA_LEN / BIT_OF_BYTE]; memset(*out_data_ptr, 0, all_bit / BIT_OF_BYTE + SRC_DATA_LEN / BIT_OF_BYTE); // copy data memcpy(*out_data_ptr, in_data_ptr, data_byte_len); // fill rest data unsigned char *tmp = reinterpret_cast<unsigned char *>(*out_data_ptr); tmp += data_byte_len; // fill 1 and 0 *tmp = 0x80; // fill origin data len unsigned long long * origin_num = (unsigned long long *)((*out_data_ptr) + ((all_bit / BIT_OF_BYTE))); *origin_num = data_byte_len*BIT_OF_BYTE; } return (all_bit / BIT_OF_BYTE + SRC_DATA_LEN / BIT_OF_BYTE); } void Md5Encode::RoundF(char *data_BIT_OF_GROUP_ptr, ParamDynamic & param) { UInt32 *M = reinterpret_cast<UInt32*>(data_BIT_OF_GROUP_ptr); int s[] = { 7, 12, 17, 22 }; for (int i = 0; i < 16; ++i) { UInt32 ti = k_ti_num_integer * abs(sin(double(i + 1))); if (i % 4 == 0) { FF(param.ua_, param.ub_, param.uc_, param.ud_, M[i], s[i % 4], ti); } else if (i % 4 == 1) { FF(param.ud_, param.ua_, param.ub_, param.uc_, M[i], s[i % 4], ti); } else if (i % 4 == 2) { FF(param.uc_, param.ud_, param.ua_, param.ub_, M[i], s[i % 4], ti); } else if (i % 4 == 3) { FF(param.ub_, param.uc_, param.ud_, param.ua_, M[i], s[i % 4], ti); } } } void Md5Encode::RoundG(char *data_BIT_OF_GROUP_ptr, ParamDynamic & param) { UInt32 *M = reinterpret_cast<UInt32*>(data_BIT_OF_GROUP_ptr); int s[] = { 5, 9, 14, 20 }; for (int i = 0; i < 16; ++i) { UInt32 ti = k_ti_num_integer * abs(sin(double(i + 1 + 16))); int index = (i * 5 + 1) % 16; if (i % 4 == 0) { GG(param.ua_, param.ub_, param.uc_, param.ud_, M[index], s[i % 4], ti); } else if (i % 4 == 1) { GG(param.ud_, param.ua_, param.ub_, param.uc_, M[index], s[i % 4], ti); } else if (i % 4 == 2) { GG(param.uc_, param.ud_, param.ua_, param.ub_, M[index], s[i % 4], ti); } else if (i % 4 == 3) { GG(param.ub_, param.uc_, param.ud_, param.ua_, M[index], s[i % 4], ti); } } } void Md5Encode::RoundH(char *data_BIT_OF_GROUP_ptr, ParamDynamic & param) { UInt32 *M = reinterpret_cast<UInt32*>(data_BIT_OF_GROUP_ptr); int s[] = { 4, 11, 16, 23 }; for (int i = 0; i < 16; ++i) { UInt32 ti = k_ti_num_integer * abs(sin(double(i + 1 + 32))); int index = (i * 3 + 5) % 16; if (i % 4 == 0) { HH(param.ua_, param.ub_, param.uc_, param.ud_, M[index], s[i % 4], ti); } else if (i % 4 == 1) { HH(param.ud_, param.ua_, param.ub_, param.uc_, M[index], s[i % 4], ti); } else if (i % 4 == 2) { HH(param.uc_, param.ud_, param.ua_, param.ub_, M[index], s[i % 4], ti); } else if (i % 4 == 3) { HH(param.ub_, param.uc_, param.ud_, param.ua_, M[index], s[i % 4], ti); } } } void Md5Encode::RoundI(char *data_BIT_OF_GROUP_ptr, ParamDynamic & param) { UInt32 *M = reinterpret_cast<UInt32*>(data_BIT_OF_GROUP_ptr); int s[] = { 6, 10, 15, 21 }; for (int i = 0; i < 16; ++i) { UInt32 ti = k_ti_num_integer * abs(sin(double(i + 1 + 48))); int index = (i * 7 + 0) % 16; if (i % 4 == 0) { II(param.ua_, param.ub_, param.uc_, param.ud_, M[index], s[i % 4], ti); } else if (i % 4 == 1) { II(param.ud_, param.ua_, param.ub_, param.uc_, M[index], s[i % 4], ti); } else if (i % 4 == 2) { II(param.uc_, param.ud_, param.ua_, param.ub_, M[index], s[i % 4], ti); } else if (i % 4 == 3) { II(param.ub_, param.uc_, param.ud_, param.ua_, M[index], s[i % 4], ti); } } } void Md5Encode::RotationCalculate(char *data_512_ptr, ParamDynamic & param) { if (NULL == data_512_ptr) { return; } RoundF(data_512_ptr, param); RoundG(data_512_ptr, param); RoundH(data_512_ptr, param); RoundI(data_512_ptr, param); param.ua_ = param.va_last_ + param.ua_; param.ub_ = param.vb_last_ + param.ub_; param.uc_ = param.vc_last_ + param.uc_; param.ud_ = param.vd_last_ + param.ud_; param.va_last_ = param.ua_; param.vb_last_ = param.ub_; param.vc_last_ = param.uc_; param.vd_last_ = param.ud_; } // 转换成十六进制字符串输出 std::string Md5Encode::GetHexStr(unsigned int num_str) { std::string hexstr = ""; char szch[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; unsigned char *tmptr = (unsigned char *)&num_str; int len = sizeof(num_str); // 小端字节序,逆序打印 for (int i = 0; i < len; i++){ unsigned char ch = tmptr[i] & 0xF0; ch = ch >> 4; hexstr.append(1, szch[ch]); ch = tmptr[i] & 0x0F; hexstr.append(1, szch[ch]); } return hexstr; } // function: Encode // @param src_info:要加密的信息 // return :加密后的MD5值 std::string Md5Encode::Encode(std::string src_info) { ParamDynamic param; param.ua_ = kA; param.ub_ = kB; param.uc_ = kC; param.ud_ = kD; param.va_last_ = kA; param.vb_last_ = kB; param.vc_last_ = kC; param.vd_last_ = kD; std::string result; const char *src_data = src_info.c_str(); char *out_data_ptr = NULL; int total_byte = FillData(src_data, strlen(src_data), &out_data_ptr); //char * data_BIT_OF_GROUP = out_data_ptr; for (int i = 0; i < total_byte / (BIT_OF_GROUP / BIT_OF_BYTE); ++i) { char * data_BIT_OF_GROUP = out_data_ptr; data_BIT_OF_GROUP += i*(BIT_OF_GROUP / BIT_OF_BYTE); RotationCalculate(data_BIT_OF_GROUP, param); } if (NULL != out_data_ptr) { delete[] out_data_ptr, out_data_ptr = NULL; } result.append(GetHexStr(param.ua_)); result.append(GetHexStr(param.ub_)); result.append(GetHexStr(param.uc_)); result.append(GetHexStr(param.ud_)); return result; }
- 源代码
#include "md5_encode.h" #include <string.h> using namespace std; void CMFCApplication1Dlg::OnBnClickedButtonOk() { // TODO: 在此添加控件通知处理程序代码 //获得输入的加密密码 TCHAR hex_md5[256]; GetDlgItem(IDC_EDIT_INPUT)->GetWindowText(hex_md5, 256); //开始MD5加密 string Password_md5 = md5_encode_public.Encode(hex_md5); //将加密结果显示到对话框 SetDlgItemText(IDC_EDIT_OUTPUT, Password_md5.c_str()); }
- 演示
参考资料
https://www.cnblogs.com/zousc/p/11118916.html
https://www.cnblogs.com/orangebook/p/3558334.html
Caesar卢尚宇
2021年3月1日