信息摘要函数(Hash函数)的设计与性质验证

发布于 2020-12-12  1348 次阅读


1.信息摘要函数(Hash函数)的设计与性质验证实验

2.实验目的:信息摘要函数(Hash函数)的设计与性质验证。

2.1实验设备:PC机 一台/人

2.2实验原理:

2.2.1.信息摘要函数具有固定的输出数位。

2.2.1信息摘要函数满足不可求逆,不可伪造和在可行时间之内找不到碰撞等特性。

3.实验内容及注意事项:

信息摘要函数的设计与Hash值的性质验证

实验步骤:

3.1设计符合原理要求的信息摘要函数H(m)。

3.2对于如下明文信息m:

There was a grocery shop in a town. Plenty of mice lived in that grocery shop. Food was in plenty for them. They ate everything and spoiled all the bags. They also wasted the bread, biscuits and fruits of the shop. The grocer got really worried. So, he thought "I should buy a cat and let it stay at the grocery. Only then I can save my things." He bought a nice, big fat cat and let him stay there. The cat had a nice time hunting the mice and killing them. The mice could not move freely now. They were afraid that anytime the cat would eat them up. The mice wanted to do something. They held a meeting and all of them tweeted "We must get rid of the cat. Can someone give a suggestion"?  All the mice sat and brooded. A smart looking mouse stood up and said, "The cat moves softly. That is the problem. If we can tie a bell around her neck, then things will be fine. We can know the movements of the cat". “Yes, that is answer," stated all the mice. An old mouse slowly stood up and asked, "Who would tie the bell?" After some moments there was no one there to answer this question. 

调用H(m)算法,产生Hash值。

3.3随机改变m的任意一位字符,产生新的Hash值,

如此实验10次,记新的Hash值为 H1,H2,…H10

3.4设计函数计算H0和Hi 的相似度 i=1,2,…10

3.5分析结果,得出结论

4.实验过程

4.1设计 哈希函数Hash(m)的思路

MD5摘要算法是Hash摘要算法中的一种摘要算法,具有不可求逆性,不可伪造性。MD5 算法自诞生之日起,就有很多人试图证明和发现它的不安全之处,即存在碰撞(在对两个不同的内容使用 MD5算法运算的时候,有可能得到一对相同的结果值)。2009年,中国科学院的谢涛和冯登国仅用了 的碰撞算法复杂度,破解了MD5的碰撞抵抗,该攻击在普通计算机上运行只需要数秒钟 。因此MD5算法不具备实验中要求的“在可行时间之内找不到碰撞”这个特性。
​ 根据MD5的存在的缺点,为了加强MD5加密算法的安全性(本身是不可逆的),从而加入了新的算法部分即加盐值,加盐值是随机生成的一组字符串,可以包括随机的大小写字母、数字、字符,位数可以根据要求而不一样,使用不同的加盐值产生的最终密文是不一样的。由于使用加盐值以后的密码相当的安全,即便是你获得了其中的salt和最终密文,破解也是一个耗费相当多时间的过程,可以说是破解单纯MD5的好几倍。并且同一个明文在经过加盐(这个盐是随机的,不同的)后进行MD5算法产生的密文也是不同的。这就使得MD5算法的抗碰撞性得到大幅度增强,因此可以满足本次实验要求。

4.2MD5+盐的实现步骤

1).首先获取需要进行md5普摘要算法的明文text。
2).随机生成加盐值(可以由字母,数字,字符组成,位数可以自己决定,这里使用16位的字符串)salt字符串.
3)将生成的salt字符串追加到明文text中,得到组合的字符串 mergeText = text +salt
4)使用md5普通摘要算法获取mergeText 的hash值得到一个32位的字符串decodeText。
5).将盐salt字符串的每个字符逐个插入到字符串decodeText是 i *3+1(i = 0,1,2,…16)的位置上,得到一个新的48位的字符串 decode。
6)最终的decode字符串就是所要的密文,位长为48个字符。

该代码已经用c++实现,具体请看:C++实现MD5摘要算法加盐salt值

4.3具体代码实现

4.3.1MD5的普通加密算法

4.3.1.1.将二进制字节数组转换为16进制的字符串
/* Convert byte array to hex string. */
string MD5::bytesToHexString(const byte *input, size_t length) {
    string str;
    str.reserve(length << 1);
    for (size_t i = 0; i < length; i++) {
        int t = input[i];
        int a = t / 16;
        int b = t % 16;
        str.append(1, HEX[a]);
        str.append(1, HEX[b]);
    }
    return str;
}
string EncryptUtil::md5Hex(const string& text) {
    //首先更新md5中需要进行摘要的字符串
    this->md5->update(text);
    //使用md5的方法生成对应的摘要后的字符串
    return this->md5->toString();

}

4.3.2产生盐值字符串的算法

/**
产生盐值字符串salt
*/
string EncryptUtil::createSalt()
{
    //随机生成两个随机数
    int num1 = rand() % 99999999;
    int num2 = rand() % 99999999;
    string salt = "";
    //将这两个随机数转换为字符串后追加到salt中
    salt.append(to_string(num1));
    salt.append(to_string(num2));
    //salt不够十六位就在后面加0
    int len = salt.size();
    if (len < 16) {
        for (int i = 0; i < 16 - len; i++) {
            salt.append("0");
        }
    }
    return salt;
}

4.3.3获取md5普通摘要函数+盐值salt操作后的最终密文

/**
* 加盐MD5
* @param text : 需要进行加盐后摘要的text明文
* @return string:返回进行摘要算法后的字符串
*/
string EncryptUtil::encryptBySalt(const string& text) {
    //产生盐值字符串salt
    string salt = createSalt();
    //将产生的salt追加到需要进行摘要的明文text中,得到由明文text和salt组成的字符串
    string merge_str =  text + salt;
    //使用md5算法进行摘要计算得到相应的32位的密文
    string encodeText = md5Hex(merge_str);
    char cs [48];
    //将32位的密文和产生的16位的salt进行重组形成新的48位的字符串。
    //这里表示,在新的字符数组cs中,salt中的字符添加到cs字符数组中位置是i*3+1的位置,其它位置由摘要密文encodeText中的字符填充
    for (int i = 0; i < 48; i += 3) {
        cs[i] = encodeText[i / 3 * 2];
        char c = salt[i / 3];
        cs[i + 1] = c;
        cs[i + 2] = encodeText[i / 3 * 2 + 1];
    }
    //将组合成的cs字符数组转化为字符串得到48位的加盐后形成的md5摘要密文
    string code = "";
    for (int i = 0; i < 48; i++)
    {
      code.append(1,cs[i]);
    }
    return code;
}

4.3.4校验加盐后是否和原文一致

/**
 * 校验加盐后是否和原文一致
 * @param text : 进行摘要算法的明文
 * @param encryptText  : 进行加盐摘要算法后的密文
 * @return 如果加盐后和原明文text一致则返回true,否则返回false
 */
 bool EncryptUtil::verify( string text,  string encryptText) {
    char md5Text[32];
    char salt[16];
    //首先将加盐后md5算法摘要得到的encryptText密文进行拆分成一个32位的普通md5摘要算法密文md5Text和一个16位的字符串salt。
    //这里就是进行salt和md5摘要密文形成48位新的字符串encryptText时的逆向操作。encryptText中salt[i] =  encryptText[ 3* i + 1], i = 0,1,2,...16
    for (int i = 0; i < 48; i += 3) {
        md5Text[i / 3 * 2] = encryptText[i];
        md5Text[i / 3 * 2 + 1] = encryptText[i + 2];
        salt[i / 3] = encryptText[i + 1];
    }
    //将拆分的16个随机字符串追salt加到明文text中
    for (int  i = 0; i < 16; i++)
    {
        text.append(1,salt[i]);
    }
    //使用md5摘要算法进行生成密文得到enCs2
    string enCs2 = md5Hex(text);
    //比较两个字符串相等,如果相等则返回true,只要有一个字符不相等就返回false
    for (int i = 0; i < enCs2.size(); i++)
    {
        if (enCs2[i] != md5Text[i])
        {
            return false;
        }
    }
    return true;
}

4.3.5 逐个比较两个密文相同位置上字符是否相同来计算两个明文进行md5加密后的相似度。

/**
  逐个比较两个密文相同位置上字符是否相同来计算两个明文进行md5加密后的相似度。
 @param str1: md5摘要算法后的字符串
 @param str2:md5摘要算法后的字符串
 @return double: 返回相似度
 */
double EncryptUtil::similarityDegree(const string& str1, const string& str2)
{
    if (str1.size() <= 0 && (str1.size() != str2.size()))
    {
        return 0;
    }
    int count = 0;
    //统计对应位置上字符相同的个数
    for (int i = 0; i < str1.size(); i++)
    {
        if (str1[i] == str2[i])
        {
            count++;
        }
    }
    //计算相似度
    double result = count * 1.0 / str1.size();
    return result;
}

4.3.6为了方便,将明文保存到文件中,然后读取文件内容作为字符串

string loadTextToString(const string textFilePath) {
    ifstream* ism = new ifstream(textFilePath,ios::app|ios::binary);
    if (ism->is_open())
    {
        string text = "";
        char ch;
        while (!ism->eof())
        {
            ism->get(ch);
            text.append(1,ch);
        }
        return text;
    }
    else {
        cout << "打开文件失败!" << endl;
        return "";
    }
}

5.验证实验内容

设计函数验证获取H0到H10的密文,并计算相似度。

string randomReplace(string text,int index,string replaceChar) {
    return text.replace(index,1,replaceChar);
}
void test() {
    string text = loadTextToString("hashtext.txt");
    cout << "需要加密的明文为:\n" << text << endl;
    EncryptUtil util;
    string md0 = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值H0:" + md0 << endl;
    vector<string> vec;
    for (int i = 0; i < 10; i++)
    {
        //替换十个字符,每个原来的字符+1
        string  newStr =    randomReplace(text, i * 5,string(1, text[i * 5] + 1));
        //计算每个替换后字符的hash值
         string encodeText =util.encryptBySalt(newStr);
        vec.push_back(encodeText);
    }
    for (size_t i = 0; i < 10; i++)
    {
        cout << "md5加盐后加密的md5值H"+ to_string(i + 1) + ":" + vec[i]<< endl;
    }
    for (size_t i = 0; i < 10; i++)
    {
        //计算H0和H的相似度
        cout << "H0和H" + to_string(i + 1) + "的相似度:" + to_string(util.similarityDegree(md0, vec[i])) << endl;
    }
}
[外链图片转存中…(img-GMQD1fac-1607789521383)]

md5加盐后加密的md5值H0:051293435697829a9bc1de2ff8ed0cb0a908706504302100
md5加盐后加密的md5值H1:061233445697859a2bc8de3ff0ed0cb0a908706504302100
md5加盐后加密的md5值H2:021203415697819a2bc1de9ff1ed6cb0a908706504302100
md5加盐后加密的md5值H3:091243475677819a6bc4de1ff3ed0cb0a908706504302100
md5加盐后加密的md5值H4:031203425687869a4bc8de6ff3ed0cb0a908706504302100
md5加盐后加密的md5值H5:011253485697809a1bc5de5ff0ed7cb0a908706504302100
md5加盐后加密的md5值H6:031203485607829a1bc5de3ff6ed6cb0a908706504302100
md5加盐后加密的md5值H7:031203425617829a1bc5de0ff8ed0cb0a908706504302100
md5加盐后加密的md5值H8:011293475627869a2bc0de0ff9ed0cb0a908706504302100
md5加盐后加密的md5值H9:021223425667899a1bc2de7ff0ed0cb0a908706504302100
md5加盐后加密的md5值H10:091293415627829a3bc6de5ff5ed0cb0a908706504302100
H0和H1的相似度:0.833333
H0和H2的相似度:0.833333
H0和H3的相似度:0.812500
H0和H4的相似度:0.812500
H0和H5的相似度:0.812500
H0和H6的相似度:0.812500
H0和H7的相似度:0.854167
H0和H8的相似度:0.833333
H0和H9的相似度:0.812500
H0和H10的相似度:0.854167

6.拓展

6.1验证md5经过摘要算法后和原来明文一致

void test9() {
    string text = loadTextToString("hashtext.txt");
    EncryptUtil util;
    string encodeText = util.encryptBySalt(text);
    string encodeText1 = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值:" + encodeText << endl;
    cout << "md5加盐后加密的md5值:" + encodeText1 << endl;
    if (encodeText.compare(encodeText1) == 0)
    {
        cout << "两次生成的加盐密文相等!" << endl;
    }
    else {
        cout << "两次生成的加盐密文不相等!" << endl;
    }
    bool fla = util.verify(text, encodeText);
    if (fla == true)
    {
        cout << "原来的明文和加盐后的明文一致得到验证!" << endl;
    }
    else {
        cout << "原来的明文和加盐后的明文不一致!" << endl;
    }

}
[外链图片转存中…(img-eCm0qnl5-1607789521389)]
md5加盐后加密的md5值:071263445647839a7bc0de0ff0ed0cb0a908706504302100
md5加盐后加密的md5值:021253435637849a1bc6de1ff8ed9cb0a908706504302100
两次生成的加盐密文不相等!
原来的明文和加盐后的明文一致得到验证!

由结果知道,虽然加盐后得到的密文不一样,但是相同的明文产生的密文是可以通过验证知道原来的明文是否一致的。

7.完整的代码

#pragma once
#include<iostream>
#include<string>
#include"Md5.h"
#include<time.h>
using namespace std;

class EncryptUtil
{
public:
    EncryptUtil();
/**
*@param text:需要进行普通md5摘要算法计算的明文
*@return string:返回普通md5摘要算计算后的字符串
*/
    string md5Decode(const string& text);
/**
产生盐值字符串salt
*/
    string createSalt();

/**
* 加盐MD5
* @param text : 需要进行加盐后摘要的text明文
* @return string:返回进行摘要算法后的字符串
*/
    string encryptBySalt(const string& text);
/**
 * 获取十六进制字符串形式的MD5摘要
 * @param text: 需要进行摘要算法的明文
 * @return string: 返回进行普通md5摘要后的字符串
 */
    string md5Hex(const string& src);
/**
 * 校验加盐后是否和原文一致
 * @param text : 进行摘要算法的明文
 * @param encryptText  : 进行加盐摘要算法后的密文
 * @return 如果加盐后和原明文text一致则返回true,否则返回false
 */
    bool verify( string text,  string md5Text);
/**
  逐个比较两个密文相同位置上字符是否相同来计算两个进行md5加密后的相似度。
 @param str1: md5摘要算法后的字符串
 @param str2:md5摘要算法后的字符串
 @return double: 返回相似度
 */
    double similarityDegree(const string& str1, const string& str2);
    ~EncryptUtil();
private:
    MD5* md5 = nullptr;

};
#include "EncryptUtil.h"



EncryptUtil::EncryptUtil()
{
    //初始化MD5这个类
    this->md5 = new MD5();
    //设置随机数种子,在产生盐时可以产生随机数。
    srand(time(NULL));
}

/**
*@param text:需要进行普通md5摘要算法计算的明文
*@return string:返回普通md5摘要算计算后的字符串
*/
string EncryptUtil::md5Decode(const string & text)
{
    //调用md5Hex(text)函数即可
     return this->md5Hex(text);
}
/**
产生盐值字符串salt
*/
string EncryptUtil::createSalt()
{
    //随机生成两个随机数
    int num1 = rand() % 99999999;
    int num2 = rand() % 99999999;
    string salt = "";
    //将这两个随机数转换为字符串后追加到salt中
    salt.append(to_string(num1));
    salt.append(to_string(num2));
    //salt不够十六位就在后面加0
    int len = salt.size();
    if (len < 16) {
        for (int i = 0; i < 16 - len; i++) {
            salt.append("0");
        }
    }
    //cout << "产生的盐值字符串为:" <<salt<< endl;
    return salt;
}

/**
* 加盐MD5
* @param text : 需要进行加盐后摘要的text明文
* @return string:返回进行摘要算法后的字符串
*/
string EncryptUtil::encryptBySalt(const string& text) {
    //产生盐值字符串salt
    string salt = createSalt();
    //将产生的salt追加到需要进行摘要的明文text中,得到由明文text和salt组成的字符串
    string merge_str =  text + salt;
    //使用md5算法进行摘要计算得到相应的32位的密文
    string encodeText = md5Hex(merge_str);
    char cs [48];
    //将32位的密文和产生的16位的salt进行重组形成新的48位的字符串。
    //这里表示,在新的字符数组cs中,salt中的字符添加到cs字符数组中位置是i*3+1的位置,其它位置由摘要密文encodeText中的字符填充
    for (int i = 0; i < 48; i += 3) {
        cs[i] = encodeText[i / 3 * 2];
        char c = salt[i / 3];
        cs[i + 1] = c;
        cs[i + 2] = encodeText[i / 3 * 2 + 1];
    }
    //将组合成的cs字符数组转化为字符串得到48位的加盐后形成的md5摘要密文
    string code = "";
    for (int i = 0; i < 48; i++)
    {
      code.append(1,cs[i]);
    }
    return code;
}
/**
 * 获取十六进制字符串形式的MD5摘要
 * @param text: 需要进行摘要算法的明文
 * @return string: 返回进行普通md5摘要后的字符串
 */
string EncryptUtil::md5Hex(const string& text) {
    //首先更新md5中需要进行摘要的字符串
    this->md5->update(text);
    //使用md5的方法生成对应的摘要后的字符串
    return this->md5->toString();

}
/**
 * 校验加盐后是否和原文一致
 * @param text : 进行摘要算法的明文
 * @param encryptText  : 进行加盐摘要算法后的密文
 * @return 如果加盐后和原明文text一致则返回true,否则返回false
 */
 bool EncryptUtil::verify( string text,  string encryptText) {
    char md5Text[32];
    char salt[16];
    //首先将加盐后md5算法摘要得到的encryptText密文进行拆分成一个32位的普通md5摘要算法密文md5Text和一个16位的字符串salt。
    //这里就是进行salt和md5摘要密文形成48位新的字符串encryptText时的逆向操作。encryptText中salt[i] =  encryptText[ 3* i + 1], i = 0,1,2,...16
    for (int i = 0; i < 48; i += 3) {
        md5Text[i / 3 * 2] = encryptText[i];
        md5Text[i / 3 * 2 + 1] = encryptText[i + 2];
        salt[i / 3] = encryptText[i + 1];
    }
    //将拆分的16个随机字符串追salt加到明文text中
    for (int  i = 0; i < 16; i++)
    {
        text.append(1,salt[i]);
    }
    //使用md5摘要算法进行生成密文得到enCs2
    string enCs2 = md5Hex(text);
    //比较两个字符串相等,如果相等则返回true,只要有一个字符不相等就返回false
    for (int i = 0; i < enCs2.size(); i++)
    {
        if (enCs2[i] != md5Text[i])
        {
            return false;
        }
    }
    return true;
}
 /**
  逐个比较两个密文相同位置上字符是否相同来计算两个明文进行md5加密后的相似度。
 @param str1: md5摘要算法后的字符串
 @param str2:md5摘要算法后的字符串
 @return double: 返回相似度
 */
double EncryptUtil::similarityDegree(const string& str1, const string& str2)
{
    if (str1.size() <= 0 && (str1.size() != str2.size()))
    {
        return 0;
    }
    int count = 0;
    //统计对应位置上字符相同的个数
    for (int i = 0; i < str1.size(); i++)
    {
        if (str1[i] == str2[i])
        {
            count++;
        }
    }
    //计算相似度
    double result = count * 1.0 / str1.size();
    return result;
}



EncryptUtil::~EncryptUtil()
{
}
#pragma once
#ifndef MD5_H
#define MD5_H
#include <string>
#include <fstream>
using namespace std;
/* Type define */
typedef unsigned char byte;
typedef unsigned int uint32;



/* MD5 declaration. */
class MD5 {
public:
    MD5();
    MD5(const void *input, size_t length);
    MD5(const string &str);
    MD5(ifstream &in);
    void update(const void *input, size_t length);
    void update(const string &str);
    void update(ifstream &in);
    const byte* digest();
    string toString();

private:
    void reset();
    void update(const byte *input, size_t length);
    void final();
    void transform(const byte block[64]);
    void encode(const uint32 *input, byte *output, size_t length);
    void decode(const byte *input, uint32 *output, size_t length);
    string bytesToHexString(const byte *input, size_t length);
    /* class uncopyable */
    MD5(const MD5&);
    MD5& operator=(const MD5&);
private:
    uint32 _state[4];   /* state (ABCD) */
    uint32 _count[2];   /* number of bits, modulo 2^64 (low-order word first) */
    byte _buffer[64];   /* input buffer */
    byte _digest[16];   /* message digest */
    bool _finished;     /* calculate finished ? */
    static const byte PADDING[64];  /* padding for calculate */
    static const char HEX[16];
    static const size_t BUFFER_SIZE = 1024;
};

#endif/*MD5_H*/
#include "md5.h"



/* Constants for MD5Transform routine. */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21


/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
    (a) += F ((b), (c), (d)) + (x) + ac; \
    (a) = ROTATE_LEFT ((a), (s)); \
    (a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
    (a) += G ((b), (c), (d)) + (x) + ac; \
    (a) = ROTATE_LEFT ((a), (s)); \
    (a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
    (a) += H ((b), (c), (d)) + (x) + ac; \
    (a) = ROTATE_LEFT ((a), (s)); \
    (a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
    (a) += I ((b), (c), (d)) + (x) + ac; \
    (a) = ROTATE_LEFT ((a), (s)); \
    (a) += (b); \
}
const byte MD5::PADDING[64] = { 0x80 };
const char MD5::HEX[16] = {
    '0', '1', '2', '3',
    '4', '5', '6', '7',
    '8', '9', 'a', 'b',
    'c', 'd', 'e', 'f'
};

/* Default construct. */
MD5::MD5() {
    reset();
}

/* Construct a MD5 object with a input buffer. */
MD5::MD5(const void *input, size_t length) {
    reset();
    update(input, length);
}

/* Construct a MD5 object with a string. */
MD5::MD5(const string &str) {
    reset();
    update(str);
}

/* Construct a MD5 object with a file. */
MD5::MD5(ifstream &in) {
    reset();
    update(in);
}

/* Return the message-digest */
const byte* MD5::digest() {
    if (!_finished) {
        _finished = true;
        final();
    }
    return _digest;
}

/* Reset the calculate state */
void MD5::reset() {

    _finished = false;
    /* reset number of bits. */
    _count[0] = _count[1] = 0;
    /* Load magic initialization constants. */
    _state[0] = 0x67452301;
    _state[1] = 0xefcdab89;
    _state[2] = 0x98badcfe;
    _state[3] = 0x10325476;

}

/* Updating the context with a input buffer. */
void MD5::update(const void *input, size_t length) {
    update((const byte*)input, length);
}

/* Updating the context with a string. */
void MD5::update(const string &str) {
    update((const byte*)str.c_str(), str.length());
}

/* Updating the context with a file. */
void MD5::update(ifstream &in) {

    if (!in)
        return;

    std::streamsize length;
    char buffer[BUFFER_SIZE];
    while (!in.eof()) {
        in.read(buffer, BUFFER_SIZE);
        length = in.gcount();
        if (length > 0)
            update(buffer, length);
    }
    in.close();
}

/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5::update(const byte *input, size_t length) {

    uint32 i, index, partLen;

    //_finished = false;
    this->reset();
    /* Compute number of bytes mod 64 */
    index = (uint32)((_count[0] >> 3) & 0x3f);

    /* update number of bits */
    if ((_count[0] += ((uint32)length << 3)) < ((uint32)length << 3))
        _count[1]++;
    _count[1] += ((uint32)length >> 29);

    partLen = 64 - index;

    /* transform as many times as possible. */
    if (length >= partLen) {

        memcpy(&_buffer[index], input, partLen);
        transform(_buffer);

        for (i = partLen; i + 63 < length; i += 64)
            transform(&input[i]);
        index = 0;

    }
    else {
        i = 0;
    }

    /* Buffer remaining input */
    memcpy(&_buffer[index], &input[i], length - i);
}

/* MD5 finalization. Ends an MD5 message-_digest operation, writing the
the message _digest and zeroizing the context.
*/
void MD5::final() {

    byte bits[8];
    uint32 oldState[4];
    uint32 oldCount[2];
    uint32 index, padLen;

    /* Save current state and count. */
    memcpy(oldState, _state, 16);
    memcpy(oldCount, _count, 8);

    /* Save number of bits */
    encode(_count, bits, 8);

    /* Pad out to 56 mod 64. */
    index = (uint32)((_count[0] >> 3) & 0x3f);
    padLen = (index < 56) ? (56 - index) : (120 - index);
    update(PADDING, padLen);

    /* Append length (before padding) */
    update(bits, 8);

    /* Store state in digest */
    encode(_state, _digest, 16);

    /* Restore current state and count. */
    memcpy(_state, oldState, 16);
    memcpy(_count, oldCount, 8);
}

/* MD5 basic transformation. Transforms _state based on block. */
void MD5::transform(const byte block[64]) {

    uint32 a = _state[0], b = _state[1], c = _state[2], d = _state[3], x[16];

    decode(block, x, 64);

    /* Round 1 */
    FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
    FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
    FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
    FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
    FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
    FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
    FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
    FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
    FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
    FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
    FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

    /* Round 2 */
    GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
    GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
    GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
    GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
    GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
    GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
    GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
    GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
    GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
    GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
    GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
    GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

    /* Round 3 */
    HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
    HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
    HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
    HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
    HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
    HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
    HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
    HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
    HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
    HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */

    /* Round 4 */
    II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
    II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
    II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
    II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
    II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
    II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
    II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
    II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
    II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
    II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */

    _state[0] += a;
    _state[1] += b;
    _state[2] += c;
    _state[3] += d;
}

/* Encodes input (ulong) into output (byte). Assumes length is
a multiple of 4.
*/
void MD5::encode(const uint32 *input, byte *output, size_t length) {

    for (size_t i = 0, j = 0; j < length; i++, j += 4) {
        output[j] = (byte)(input[i] & 0xff);
        output[j + 1] = (byte)((input[i] >> 8) & 0xff);
        output[j + 2] = (byte)((input[i] >> 16) & 0xff);
        output[j + 3] = (byte)((input[i] >> 24) & 0xff);
    }
}

/* Decodes input (byte) into output (ulong). Assumes length is
a multiple of 4.
*/
void MD5::decode(const byte *input, uint32 *output, size_t length) {

    for (size_t i = 0, j = 0; j < length; i++, j += 4) {
        output[i] = ((uint32)input[j]) | (((uint32)input[j + 1]) << 8) |
            (((uint32)input[j + 2]) << 16) | (((uint32)input[j + 3]) << 24);
    }
}

/* Convert byte array to hex string. */
string MD5::bytesToHexString(const byte *input, size_t length) {
    string str;
    str.reserve(length << 1);
    for (size_t i = 0; i < length; i++) {
        int t = input[i];
        int a = t / 16;
        int b = t % 16;
        str.append(1, HEX[a]);
        str.append(1, HEX[b]);
    }
    return str;
}

MD5 & MD5::operator=(const MD5 &)
{
    return *this;
}

/* Convert digest to string value */
string MD5::toString() {
    return bytesToHexString(digest(), 16);
}

测试文件

#include<iostream>
#include"Md5.h"
#include<string>
#include<fstream>
#include"EncryptUtil.h"
#include<time.h>
#include<vector>
using namespace std;

string loadTextToString(const string textFilePath) {
    ifstream* ism = new ifstream(textFilePath,ios::app|ios::binary);
    if (ism->is_open())
    {

        string text = "";
        char ch;
        while (!ism->eof())
        {
            ism->get(ch);
            text.append(1,ch);
        }
        return text;
    }
    else {
        cout << "打开文件失败!" << endl;
        return "";
    }
}

void test2() {


}
void test1() {
    string text = loadTextToString("hashtext.txt");
    MD5 md5(text);
    cout << md5.toString();
}
void test3() {
    string s = "11";
    s.append(to_string(121));
    cout << s;
}
void test4() {
    string text = loadTextToString("hashtext.txt");
    EncryptUtil util;
    string str = util.md5Decode(text);
    cout << "\n普通加密后的md5值:" + str << endl;
    cout << "普通加密后的md5值:" + util.md5Decode(text) << endl;
    string encodeText =util.encryptBySalt(text);
    string encodeText1 = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值:" + encodeText << endl;
    cout << "md5加盐后加密的md5值:" + encodeText1 << endl;
    if (encodeText.compare(encodeText1) == 0)
    {
        cout << "两次生成的加盐秘钥相等!" << endl;
    }
    else {
        cout << "两次生成的加盐秘钥不相等!" << endl;
    }
    bool fla = util.verify(text,encodeText);
    if (fla == true)
    {
        cout << "相等!"<<endl;
    }
    else {
        cout << "不相等" << endl;
    }

}
void test5() {
    string text = loadTextToString("hashtext.txt");
    cout << endl;

}
void test6() {
    srand(time(NULL));
    cout << rand() % 99999999 <<"  "<<  rand()% 99999999 <<endl;
    cout << rand() % 99999999 << "  " << rand() % 99999999 << endl;
}
void test7() {
    string text = loadTextToString("hashtext.txt");
    cout << "需要加密的明文为:\n" << text<<endl;
    EncryptUtil util;
    string encodeText = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值:" + encodeText << endl;


}
string randomReplace(string text,int index,string replaceChar) {



    return text.replace(index,1,replaceChar);
}
void test() {
    string text = loadTextToString("hashtext.txt");
    cout << "需要加密的明文为:\n" << text << endl;
    EncryptUtil util;
    string md0 = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值H0:" + md0 << endl;
    vector<string> vec;
    for (int i = 0; i < 10; i++)
    {
        //替换十个字符,每个原来的字符+1
        string  newStr =    randomReplace(text, i * 5,string(1, text[i * 5] + 1));
        //计算每个替换后字符的hash值
         string encodeText =util.encryptBySalt(newStr);
        vec.push_back(encodeText);
    }
    for (size_t i = 0; i < 10; i++)
    {
        cout << "md5加盐后加密的md5值H"+ to_string(i + 1) + ":" + vec[i]<< endl;
    }
    for (size_t i = 0; i < 10; i++)
    {
        //计算H0和H的相似度
        cout << "H0和H" + to_string(i + 1) + "的相似度:" + to_string(util.similarityDegree(md0, vec[i])) << endl;
    }
}
void test8() {
    string text = loadTextToString("hashtext.txt");
    cout << "需要加密的明文为:\n" << text << endl;
    EncryptUtil util;
    string md0 = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值H0:" + md0 << endl;
    string text1 =  text.replace(10,1,"a");
    string md1 = util.encryptBySalt(text1);
    cout << "md5加盐后加密的md5值H1:" + md1 << endl;
    cout << "md0和md1相似度:" << util.similarityDegree(md0,md1)<<endl;

}
void test9() {
    string text = loadTextToString("hashtext.txt");
    EncryptUtil util;
    string encodeText = util.encryptBySalt(text);
    string encodeText1 = util.encryptBySalt(text);
    cout << "md5加盐后加密的md5值:" + encodeText << endl;
    cout << "md5加盐后加密的md5值:" + encodeText1 << endl;
    if (encodeText.compare(encodeText1) == 0)
    {
        cout << "两次生成的加盐密文相等!" << endl;
    }
    else {
        cout << "两次生成的加盐密文不相等!" << endl;
    }
    bool fla = util.verify(text, encodeText);
    if (fla == true)
    {
        cout << "原来的明文和加盐后的明文一致得到验证!" << endl;
    }
    else {
        cout << "原来的明文和加盐后的明文不一致!" << endl;
    }

}
int main() {
    // test8();


    test9();
    system("pause");
    return 0;
}

8.看完记得点赞哦,笔记整理不易。


繁华落尽,雪花漫天飞舞。