MD5&Application In PassWord

本文介绍了一种基于MD5算法的加密程序实现方法,并详细解释了其工作流程和技术细节。通过对输入信息进行预处理、分组及多轮迭代运算等步骤,最终生成固定长度的密文。

MD5 Program

根据老师的PPT讲解和RFC1321白皮书,我写了一个可执行的MD5加密程序。

Analysis

具体的思想为:

  1. 先逐个地接收信息字符,然后将每一个字符转化成长度为8位的阿斯克码二进制字符串,然后,加到现有的字符串中,当现有的字符串长度达到512bits时,对它进行处理,然后继续接收下一个512bits长度的字符串,直到最后一个字符输入,然后对最后一段做padding处理,留下最后64位作为长度记录。
  2. padding的时候有三种情况:现在的长度小于448,长度等于448,长度大于448,然后长度小于448的就直接补到448,长度等于或者大于448的就要补到下一个512分组的448位处,才能够把长度填入。
  3. 长度的填入是低位存在前32位,高位存在后32位。
  4. 把每一个512位的分组分成16个32位的无符号整数。之前我们传入的时候是按字符二进制传入的,现在把每四个字符的二进制字符串分为一组,按照小端规则变成16个无符号整数。
  5. 对每一个512位分组,按照下面的规则做4轮FGHI每轮16次迭代,得出这个分组后的结果:
    这里写图片描述
    这里写图片描述

具体的代码和实验结果如下:

Code

MD5.hpp

#ifndef MD5_HPP
#define MD5_HPP
class MD5
{
public:
    MD5();
    ~MD5();
    int SwitchIterationIndex(int i, int j);
    unsigned int ShiftLeft(unsigned int in, int b);
    void InitVector();
    void InitShiftAmount();
    void HMD5(unsigned int* in);
    void MessageDealing(string s);
    void PaddingDealing(string s);
    unsigned int add(unsigned int a, unsigned int b);
    unsigned int GBCD(int turn, unsigned int b, unsigned int c, unsigned int d);
    void Print();
    void GetXArray(string s);
private:
    unsigned int input[4];
    int s[64];
    unsigned int x[16];
    unsigned long  long count;
};
#endif

MD5.cpp

#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include "MD5.hpp"
using namespace std;


MD5::MD5() {
    count = 0;
    InitVector();
    InitShiftAmount();
}

int MD5::SwitchIterationIndex(int i, int j) {
    int f;
    switch (i) {
    case 0:
        f = j;
        break;
    case 1:
        f = (1 + 5 * j) % 16;
        break;
    case 2:
        f = (5 + 3 * j) % 16;
        break;
    case 3:
        f = (7 * j) % 16;
        break;
    }
    return f;
}

unsigned int MD5::ShiftLeft(unsigned int in, int b) {
    return (unsigned int)(((unsigned long long)in) << b) | (((unsigned long long)in) >> (32 - b));
}

void MD5::InitVector() {
    input[0] = 0x67452301;
    input[1] = 0xEFCDAB89;
    input[2] = 0x98BADCFE;
    input[3] = 0x10325476;
}

void MD5::HMD5(unsigned int* in) {
    for (int k = 0; k < 4; k++) {
        for (int q = 0; q < 16; q++) {
            unsigned int tmps = add(GBCD(k, in[1], in[2], in[3]), in[0]);

            unsigned int tmp1 = (unsigned int)floor(((unsigned long long)0x100000000)*abs(sin(k * 16 + q+1)));


            tmps = add(tmps, x[SwitchIterationIndex(k,k*16+q)]);

            tmps = add(tmps, tmp1);


            tmp1 = ShiftLeft(tmps, s[k*16+q]);

            tmps = tmp1 + in[1];

            in[0] = in[3];
            in[3] = in[2];
            in[2] = in[1];
            in[1] = tmps;

        }
    }

    input[0] = input[0] + in[0];
    input[1] = input[1] + in[1];
    input[2] = input[2] + in[2];
    input[3] = input[3] + in[3];
}
void MD5::GetXArray(string s) {
    string tmp1 = "",tmp2 = "",tmp3 = "",tmp4 = "";
    for (int k = 0; k < 16; k++) {
        tmp1 = s.substr(32 * k, 8);
        tmp2 = s.substr(32 * k+8, 8);
        tmp3 = s.substr(32 * k+16, 8);
        tmp4 = s.substr(32 * k+24, 8);
        x[k] = strtol(tmp4.c_str(), NULL, 2) << 24;
        x[k] += strtol(tmp3.c_str(), NULL, 2) << 16;
        x[k] += strtol(tmp2.c_str(), NULL, 2) << 8;
        x[k] += strtol(tmp1.c_str(), NULL, 2);
    }
}
void MD5::MessageDealing(string s) {
    count += s.size();
    string tmp1 = "",tmp2 = "",tmp3 = "",tmp4 = "", another = "";
    if (s.size() < 512) {

        int a = s.size() % 512;

        if (a == 448) {
            s += "1";
            for (int i = 1; i < 512; i++) {
                s += "0";
            }
            another = s.substr(512,448);
            GetXArray(s);
        } else if (a < 448) {
            s += "1";
            for (int i = 0; i < (447 - a); i++) {
                    s += "0";
                }
                for (int k = 0; k < 14; k++) {
                tmp1 = s.substr(32 * k, 8);
                tmp2 = s.substr(32 * k+8, 8);
                tmp3 = s.substr(32 * k+16, 8);
                tmp4 = s.substr(32 * k+24, 8);
                x[k] = strtol(tmp4.c_str(), NULL, 2) << 24;
                x[k] += strtol(tmp3.c_str(), NULL, 2) << 16;
                x[k] += strtol(tmp2.c_str(), NULL, 2) << 8;
                x[k] += strtol(tmp1.c_str(), NULL, 2);
            }
            x[14] =(unsigned int)(count&(unsigned int)0xFFFFFFFF);
            x[15] = (count>>32);
        } else {
            s += "1";
            for (int i = 1; i < (960-a); i++) {
                s += "0";
            }
            another = s.substr(512,448);
            GetXArray(s);
        }
    } else {
        GetXArray(s);
    }

    unsigned int temp[4];
    for (int k = 0; k < 4; k++) {
        temp[k] = input[k];
    }
    HMD5(temp);
    if (s.size() > 512) PaddingDealing(another);
}
void MD5::PaddingDealing(string s) {
    string tmp1 = "",tmp2 = "",tmp3 = "",tmp4 = "";
    for (int k = 0; k < 14; k++) {
        tmp1 = s.substr(32 * k, 8);
        tmp2 = s.substr(32 * k+8, 8);
        tmp3 = s.substr(32 * k+16, 8);
        tmp4 = s.substr(32 * k+24, 8);
        x[k] = strtol(tmp4.c_str(), NULL, 2) << 24;
        x[k] += strtol(tmp3.c_str(), NULL, 2) << 16;
        x[k] += strtol(tmp2.c_str(), NULL, 2) << 8;
        x[k] += strtol(tmp1.c_str(), NULL, 2);
    }
    x[14] =(unsigned int)(count&(unsigned int)0xFFFFFFFF);
    x[15] = (count>>32);
    unsigned int temp[4];
    for (int k = 0; k < 4; k++) {
        temp[k] = input[k];
    }
    HMD5(temp);
}
unsigned int MD5::add(unsigned int a, unsigned int b) {
    unsigned int c = 0xFFFFFFFF;
    return (unsigned int)(((unsigned long)a + (unsigned long)b));
}

unsigned int MD5::GBCD(int turn, unsigned int b, unsigned int c, unsigned int d) {
    unsigned int f;
    switch (turn) {
    case 0:
        f = ((b)&(c)) | ((~b)&(d));
        break;
    case 1:
        f = ((b)&(d)) | ((c)&(~d));
        break;
    case 2:
        f = ((b)^(c) ^ (d));
        break;
    case 3:
        f = ((c)^ ((b) | (~d)));
        break;
    }
    return f;
}

void MD5::InitShiftAmount() {
    s[0] = s[4] = s[8] = s[12] = 7;
    s[1] = s[5] = s[9] = s[13] = 12;
    s[2] = s[6] = s[10] = s[14] = 17;
    s[3] = s[7] = s[11] = s[15] = 22;
    s[16] = s[20] = s[24] = s[28] = 5;
    s[17] = s[21] = s[25] = s[29] = 9;
    s[18] = s[22] = s[26] = s[30] = 14;
    s[19] = s[23] = s[27] = s[31] = 20;
    s[32] = s[36] = s[40] = s[44] = 4;
    s[33] = s[37] = s[41] = s[45] = 11;
    s[34] = s[38] = s[42] = s[46] = 16;
    s[35] = s[39] = s[43] = s[47] = 23;
    s[48] = s[52] = s[56] = s[60] = 6;
    s[49] = s[53] = s[57] = s[61] = 10;
    s[50] = s[54] = s[58] = s[62] = 15;
    s[51] = s[55] = s[59] = s[63] = 21;
}

void MD5::Print() {
    unsigned int a = 0, b = 0, c = 0, d = 0;
    for (int k = 0; k < 4; k++) {
        a = input[k] & 0xFF;
        a = a << 24;
        b = input[k] & 0xFF00;
        b = b << 8;
        c = input[k] & 0xFF0000;
        c = c >> 8;
        d = input[k] & 0xFF000000;
        d = d >> 24;
        input[k] = a + b + c + d;
        cout<<hex <<setfill('0')<<setw(8)<< input[k];
    }
    cout << endl;
}

MD5::~MD5() {}

test.cpp

#include "MD5.hpp"
using namespace std;
string Encode(char c) {
    int num = (int)c;
    int temp = 0;
    string result =  "";
    for (int i = 7; i >= 0; i--) {
        temp = num >> i;
        if (temp % 2 == 0) {
            result += "0";
        } else {
            result += "1";
        }
    }
    return result;
}
int main() {
    MD5* md = new MD5();
    string s = "";
    char c;
    cout << "Please enter the infomation you want to encode and stop by enter ctrl + Z: " << endl;
    int count = 0;
    string str = "MD5 for(\"";
    while (scanf("%c",&c) != EOF) {
        str += c;
        if (count == 64) {
            count = 1;
            md->MessageDealing(s);
            s = "" + Encode(c);

        } else {
            s += Encode(c);
            count++;
        }
    }
    if (str.size() != 9) str = str.substr(0,str.size()-1);
    s =s.substr(0,s.size()-8);
    md->MessageDealing(s);
    str += "\"): ";
    cout << str;
    md->Print();
    delete md;
    return 0;
}

实验结果截图

  1. Case 1
    输入空字符串
    这里写图片描述
    结果为d41d8cd98f00b204e9800998ecf8427e
  2. Case 2
    输入”a”
    这里写图片描述
    结果为:0cc175b9c0f1b6a831c399e269772661
  3. Case 3
    输入”abc”
    这里写图片描述
    结果为:900150983cd24fb0d6963f7d28e17f72
  4. Case 4
    输入”message digest”
    这里写图片描述
    结果为:f96b697d7cb7938d525a2f31aaf161d0
  5. Case 5
    输入”abcdefghijklmnopqrstuvwxyz”
    这里写图片描述
    结果为:c3fcd3d76192e4007dfb496cca67e13b
    6.Case 6
    输入”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789”
    这里写图片描述
    结果为:d174ab98d277d9f5a5611c2c9f419d9f
    7.Case 7
    输入”12345678901234567890123456789012345678901234567890123456789012345678901234567890”
    这里写图片描述
    结果为:57edf4a22be3c955ac49da2e2107b67a

与RFC321白皮书中提到的example一致:
这里写图片描述

MD5 For Password Protection

MD5特性

  1. 因为MD5是把信息转换成一个固定长度的密文,不管明文的长度是多少,密文的长度固定是128位,这样第一点就可以隐藏密码的具体长度。
  2. 第二个特性就是,MD5是不可逆的,具有单向性,就是说,只有密文,攻击者是无法得知明文的,所以这样来说,密码就比较安全,只有持有者才知道。
  3. 第三个就是,虽然MD5不是足够安全的,但是很难找到真正不同的两个消息,使得他们的MD5值相同。

MD5在密码中的应用

  1. 因为密码是检验密码持有者身份的依据,只要verifier知道这个身份是真是假就可以了。所以,verifier(一个公司、网站或其他服务提供商)在将MD5应用于密码校验的时候只需要将密码持有者送来的待校验密码用MD5算法处理,处理后将得到的MD5值与他们数据库中的存储的MD5值进行对比,如果一致,说明验证成功,如果不一致,说明校验失败。最原始的真正的密码在一开始注册的时候就被以MD5的形式存在数据库中。
  2. 以MD5的形式存在于验证方的数据库中,比裸密码要安全得多,因为攻击者如果得到数据库中的信息,要攻破MD5把原来的密码算出来是很困难的,所以相较之要安全很多。
  3. 一般的密码其实都可以用MD5加密,用户名也是可以的(或者说,也是很有必要的),只有当用户名和密码同时校验成功才算是校验成功。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值