zoukankan      html  css  js  c++  java
  • 【Delphi】MD5算法(一):实现

    //******************************************************************************
    //MD5算法:实现
    //******************************************************************************
    //作者:Cai
    //日期:2011-10-25
    //修改:2011-11-15 添加 支持大头字节序编译开关,可供Lazarus使用
    //******************************************************************************
    //MD5算法源码
    unit MD5Class;

    interface
    uses
      SysUtils,
      Classes;

    type

    INT4 = Integer;
    UINT4 = Cardinal;
    UINT2 = WORD;

    PUINT4 = ^UINT4;
    TBytes_4 = array[0..4-1] of Byte;
    TBytes_16 = array[0..16-1]of Byte;
    TBytes_32 = array[0..32-1]of Byte;
    TBytes_64 = array[0..64-1]of Byte;

    PBytes_64 = ^TBytes_64;

    TUINT4s_2 = array[0..2-1]of UINT4;
    TUINT4s_4 = array[0..4-1]of UINT4;
    TUINT4s_16 = array[0..16-1]of UINT4;
    TUINT4s = array of UINT4;

    TMD5_CTX = record
    State : TUINT4s_4; // /* state (ABCD) */
    Count : TUINT4s_2; ///* number of bits, modulo 2^64 (lsb first) */
    Buffer: TBytes_64; // /* input buffer */
    end;
    TMD5Context = TMD5_CTX;

    TMD5Digest = TBytes_16;
    PMD5Digest = ^TMD5Digest;

    TMD5Class = Class
    protected
    //MD5核心算法
    procedure MD5Transform(var States: TUINT4s_4; pBlock: PBytes_64);
    procedure Encode(pOutBuf: PByte; iInBuf: PUINT4; iInBufNumOfBytes: UINT4);
    procedure Decode(iOutBuf: PUINT4; pInBuf: PByte; iInBufNumOfBytes: UINT4);
    //其他
    procedure MD5_MemCpy(pDest, pSrc: Pointer; iLen: UINT4);
    procedure MD5_MemSet(P: POINTER; iValue, iLen: UINT4);
    public
    constructor Create(); virtual;
    destructor Destroy; override;
    class function DigestToString(MD5Digest: TMD5Digest):String;
    class function StringToDigest(sMD5Str: string): TMD5Digest;
    //=========MD5算法:实现==============
    procedure MD5Init(var Context: TMD5Context);
    procedure MD5Update(var Context: TMD5Context; pInBuffer: PByte; iInBufLen: UINT4);
    procedure MD5Final(var Digest: TMD5Digest; var Context: TMD5Context);
    end;

    implementation
    //implementation of the CMd5A class.

    function ArrUINT4s(pArrUINT4s: PUINT4; iIndex: UINT4): UINT4;overload;
    begin
    Inc(pArrUINT4s, iIndex);
    Result := pArrUINT4s^;
    end;

    procedure ArrUINT4s(pArrUINT4s: PUINT4; iIndex: UINT4; iValue: UINT4);overload;
    begin
    Inc(pArrUINT4s, iIndex);
    pArrUINT4s^ := iValue;
    end;

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

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

    PADDING: array[0..64-1] of Byte = (
    $80, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0);
    // F, G, H and I are basic MD5 functions.
    (***************************************
    以一下是每次操作中用到的四个非线性函数(每轮一个)。
      F(X,Y,Z) =(X&Y)|((~X)&Z)
      G(X,Y,Z) =(X&Z)|(Y&(~Z))
      H(X,Y,Z) =X^Y^Z
      I(X,Y,Z)=Y^(X|(~Z))
    ****************************************)
    function F(x, y, z: UINT4):UINT4;
    begin
    Result := (x and y) or ((not x) and z);
    end;

    function G(x, y, z: UINT4): UINT4;
    begin
    Result := (x and z) or (y and (not z));
    end;

    function H(x, y, z: UINT4): UINT4;
    begin
    Result := x xor y xor z;
    end;

    function I(x, y, z: UINT4): UINT4;
    begin
    Result := y xor (x or (not z));
    end;

    //rotates x left n bits.
    function ROL_32(xParam, nBits:UINT4):UINT4;
    begin
    Result := (((xParam) shl (nBits)) or ((xParam) shr (32-(nBits))))
    end;

    (****************************************
    FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
    Rotation is separate from addition to prevent recomputation.
    ****************************************)
    procedure FF(var a: UINT4; b, c, d, x, s, ac: UINT4);
    begin
    Inc(a, F(b, c, d) + x + ac);
    a := ROL_32(a, s);
    Inc(a, b);
    end;

    procedure GG(var a: UINT4; b, c, d, x, s, ac: UINT4);
    begin
    Inc(a, G(b, c, d) + x + ac);
    a := ROL_32(a, s);
    Inc(a, b);
    end;

    procedure HH(var a: UINT4; b, c, d, x, s, ac: UINT4);
    begin
    Inc(a, H(b, c, d) + x + ac);
    a := ROL_32(a, s);
    Inc(a, b);
    end;

    procedure II(var a: UINT4; b, c, d, x, s, ac: UINT4);
    begin
    Inc(a, I(b, c, d) + x + ac);
    a := ROL_32(a, s);
    Inc(a, b);
    end;


    const
    SUPPORT_BIG_ENDIAN = FALSE; //编译开关 TRUE为 支持大头字节序 CPU 编译

    {$IF SUPPORT_BIG_ENDIAN}
    //是否小端字节序列
    const
    IsLittleEndian: Boolean = ByteBOOL($00000001);
    (* Code: IsLittleEndian
    function IsLittleEndian():Boolean;
    var
    dwValue: UINT4;
    Bytes_4: TBytes_4;
    begin
    dwValue := $00000001;
    Bytes_4 := TBytes_4(dwValue);
    Result := (Bytes_4[0]=$01);
    end; *)
    (*
    //ntohl, 大头字序转换
    function BigEndianToHostEndian(const nValue: UINT4):UINT4;
    begin
    if IsLittleEndian then
    begin
    TBytes_4(Result)[0] := TBytes_4(nValue)[3];
    TBytes_4(Result)[1] := TBytes_4(nValue)[2];
    TBytes_4(Result)[2] := TBytes_4(nValue)[1];
    TBytes_4(Result)[3] := TBytes_4(nValue)[0];
    end
    else
    begin
    Result := nValue;
    end;
    end; *)

    //小头字节序转换
    function LittleEndianToHostEndian(const nValue: UINT4):UINT4;
    //这里使用函数的方式实现起来简单,但会降低MD5Transform的效率,
    //实际应用中若对效率要求较高,可使用数组在进程初始化时就根据字节序填充即可
    begin
    if IsLittleEndian then
    begin
    Result := nValue;
    end
    else
    begin
    TBytes_4(Result)[0] := TBytes_4(nValue)[3];
    TBytes_4(Result)[1] := TBytes_4(nValue)[2];
    TBytes_4(Result)[2] := TBytes_4(nValue)[1];
    TBytes_4(Result)[3] := TBytes_4(nValue)[0];
    end;
    end;
    {$ELSE}
    type
    LittleEndianToHostEndian = UINT4;//不支持字节序时直接定义为类型强制转换即可
    {$IFEND}

    { TMD5Class }

    constructor TMD5Class.Create;
    begin

    end;

    destructor TMD5Class.Destroy;
    begin

    inherited;
    end;

    //MD5 initialization. Begins an MD5 operation, writing a new context.
    procedure TMD5Class.MD5Init(var Context: TMD5Context);
    begin
    FillChar(Context, SizeOf(TMD5Context), 0);
    (*MD5中有四个32位被称作链接变量(Chaining Variable)的整数参数,他们分别为:
    A=0x01234567,
    B=0x89abcdef,
    C=0xfedcba98,
    D=0x76543210
    // word A: 01 23 45 67
    // word B: 89 ab cd ef
    // word C: fe dc ba 98
    // word D: 76 54 32 10 *)
    //Load magic initialization constants.
    //检查CPU字节序列模式
    //if IsLittleEndian then
    begin // Little endian 小头字节序列
    Context.State[0] := LittleEndianToHostEndian($67452301);
    Context.State[1] := LittleEndianToHostEndian($EFCDAB89);
    Context.State[2] := LittleEndianToHostEndian($98BADCFE);
    Context.State[3] := LittleEndianToHostEndian($10325476);
    end
    (*else
    begin // Big endian 大头字节序列
    Context.State[0] := $01234567;
    Context.State[1] := $89ABCDEF;
    Context.State[2] := $FEDCBA98;
    Context.State[3] := $76543210;
    end;*)
    end;

    (* MD5 block update operation. Continues an MD5 message-digest
    operation, processing another message block, and updating the
    context. MD5数据更新操作*)
    procedure TMD5Class.MD5Update(var Context: TMD5Context; pInBuffer: PByte; iInBufLen: UINT4);
    var
    iIndex,
    iPartLen,
    I: UINT4;
    begin
    // Compute number of bytes mod 64
    iIndex := UINT4((Context.Count[0] shr 3) and $3F); //(Context.Count[0] / 8) mod 64

    // Update number of bits
    Inc(Context.Count[0], UINT4(iInBufLen shl 3)); //iInBufLen * 8
    if Context.Count[0]< UINT4(iInBufLen shl 3) then Inc(Context.Count[1]); //进位
    Context.Count[1] := Context.Count[1] + iInBufLen shr (32 - 3); // iInBufLen + iInBufLen / 2^29
    iPartLen := 64 - iIndex;

    //Transform as many times as possible.
    if (iInBufLen >= iPartLen) then
    begin
    MD5_Memcpy(@Context.Buffer[iIndex], pInBuffer, iPartLen);
    MD5Transform(Context.State, @Context.Buffer);
    I := iPartLen;
    while (I+64<=iInBufLen) do
    begin
    MD5Transform(Context.State, PBytes_64(@PChar(pInBuffer)[I]));
    Inc(I, 64);
    end;
    iIndex := 0;
    end
    else
    I := 0;
    // Buffer remaining input
    Inc(pInBuffer, I);
    MD5_Memcpy(@Context.Buffer[iIndex], pInBuffer, iInBufLen-I);
    end;

    (*
    MD5 finalization. Ends an MD5 message-digest operation, writing the
    the message digest and zeroizing the context.*)
    procedure TMD5Class.MD5Final(var Digest: TBytes_16; var Context: TMD5Context);
    var
    Bits: array[0..8-1]of Byte;
    iIndex, iPadLen: UINT4;
    begin
    //Save number of bits
    Encode(@Bits, @Context.Count, 8);

    //Pad out to 56 mod 64.
    iIndex := UINT4((Context.Count[0] shr 3) and $3F);
    if iIndex < 56 then
    iPadLen := (56 - iIndex)
    else
    iPadLen := (120 - iIndex);
    MD5Update(Context, @PADDING, iPadLen);
    //Append length (before padding)
    MD5Update(Context, @Bits, 8);
    //Store state in digest
    Encode(@Digest, @Context.State, 16);

    //Zeroize sensitive information.
    MD5_MemSet(@Context, 0, SizeOf(TMD5Context));
    end;

    // MD5 basic transformation. Transforms state based on block.
    procedure TMD5Class.MD5Transform(var States: TUINT4s_4; pBlock: PBytes_64);
    var
    //I,
    A, B, C, D: UINT4;
    x: TUINT4s_16;
    begin
    //I := 0;
    a := States[0];
    b := States[1];
    c := States[2];
    d := States[3];
    Decode(@x, PByte(pBlock), 64);
    //Round 1
    FF (a, b, c, d, x[ 0], S11, LittleEndianToHostEndian($d76aa478)); // 1 */
    FF (d, a, b, c, x[ 1], S12, LittleEndianToHostEndian($e8c7b756)); // 2 */
    FF (c, d, a, b, x[ 2], S13, LittleEndianToHostEndian($242070db)); // 3 */
    FF (b, c, d, a, x[ 3], S14, LittleEndianToHostEndian($c1bdceee)); // 4 */
    FF (a, b, c, d, x[ 4], S11, LittleEndianToHostEndian($f57c0faf)); // 5 */
    FF (d, a, b, c, x[ 5], S12, LittleEndianToHostEndian($4787c62a)); // 6 */
    FF (c, d, a, b, x[ 6], S13, LittleEndianToHostEndian($a8304613)); // 7 */
    FF (b, c, d, a, x[ 7], S14, LittleEndianToHostEndian($fd469501)); // 8 */
    FF (a, b, c, d, x[ 8], S11, LittleEndianToHostEndian($698098d8)); // 9 */
    FF (d, a, b, c, x[ 9], S12, LittleEndianToHostEndian($8b44f7af)); // 10 */
    FF (c, d, a, b, x[10], S13, LittleEndianToHostEndian($ffff5bb1)); // 11 */
    FF (b, c, d, a, x[11], S14, LittleEndianToHostEndian($895cd7be)); // 12 */
    FF (a, b, c, d, x[12], S11, LittleEndianToHostEndian($6b901122)); // 13 */
    FF (d, a, b, c, x[13], S12, LittleEndianToHostEndian($fd987193)); // 14 */
    FF (c, d, a, b, x[14], S13, LittleEndianToHostEndian($a679438e)); // 15 */
    FF (b, c, d, a, x[15], S14, LittleEndianToHostEndian($49b40821)); // 16 */
    // Round 2 */
    GG (a, b, c, d, x[ 1], S21, LittleEndianToHostEndian($f61e2562)); // 17 */
    GG (d, a, b, c, x[ 6], S22, LittleEndianToHostEndian($c040b340)); // 18 */
    GG (c, d, a, b, x[11], S23, LittleEndianToHostEndian($265e5a51)); // 19 */
    GG (b, c, d, a, x[ 0], S24, LittleEndianToHostEndian($e9b6c7aa)); // 20 */
    GG (a, b, c, d, x[ 5], S21, LittleEndianToHostEndian($d62f105d)); // 21 */
    GG (d, a, b, c, x[10], S22, LittleEndianToHostEndian($02441453)); // 22 */
    GG (c, d, a, b, x[15], S23, LittleEndianToHostEndian($d8a1e681)); // 23 */
    GG (b, c, d, a, x[ 4], S24, LittleEndianToHostEndian($e7d3fbc8)); // 24 */
    GG (a, b, c, d, x[ 9], S21, LittleEndianToHostEndian($21e1cde6)); // 25 */
    GG (d, a, b, c, x[14], S22, LittleEndianToHostEndian($c33707d6)); // 26 */
    GG (c, d, a, b, x[ 3], S23, LittleEndianToHostEndian($f4d50d87)); // 27 */
    GG (b, c, d, a, x[ 8], S24, LittleEndianToHostEndian($455a14ed)); // 28 */
    GG (a, b, c, d, x[13], S21, LittleEndianToHostEndian($a9e3e905)); // 29 */
    GG (d, a, b, c, x[ 2], S22, LittleEndianToHostEndian($fcefa3f8)); // 30 */
    GG (c, d, a, b, x[ 7], S23, LittleEndianToHostEndian($676f02d9)); // 31 */
    GG (b, c, d, a, x[12], S24, LittleEndianToHostEndian($8d2a4c8a)); // 32 */
    // Round 3 */
    HH (a, b, c, d, x[ 5], S31, LittleEndianToHostEndian($fffa3942)); // 33 */
    HH (d, a, b, c, x[ 8], S32, LittleEndianToHostEndian($8771f681)); // 34 */
    HH (c, d, a, b, x[11], S33, LittleEndianToHostEndian($6d9d6122)); // 35 */
    HH (b, c, d, a, x[14], S34, LittleEndianToHostEndian($fde5380c)); // 36 */
    HH (a, b, c, d, x[ 1], S31, LittleEndianToHostEndian($a4beea44)); // 37 */
    HH (d, a, b, c, x[ 4], S32, LittleEndianToHostEndian($4bdecfa9)); // 38 */
    HH (c, d, a, b, x[ 7], S33, LittleEndianToHostEndian($f6bb4b60)); // 39 */
    HH (b, c, d, a, x[10], S34, LittleEndianToHostEndian($bebfbc70)); // 40 */
    HH (a, b, c, d, x[13], S31, LittleEndianToHostEndian($289b7ec6)); // 41 */
    HH (d, a, b, c, x[ 0], S32, LittleEndianToHostEndian($eaa127fa)); // 42 */
    HH (c, d, a, b, x[ 3], S33, LittleEndianToHostEndian($d4ef3085)); // 43 */
    HH (b, c, d, a, x[ 6], S34, LittleEndianToHostEndian($04881d05)); // 44 */
    HH (a, b, c, d, x[ 9], S31, LittleEndianToHostEndian($d9d4d039)); // 45 */
    HH (d, a, b, c, x[12], S32, LittleEndianToHostEndian($e6db99e5)); // 46 */
    HH (c, d, a, b, x[15], S33, LittleEndianToHostEndian($1fa27cf8)); // 47 */
    HH (b, c, d, a, x[ 2], S34, LittleEndianToHostEndian($c4ac5665)); // 48 */
    // Round 4 */
    II (a, b, c, d, x[ 0], S41, LittleEndianToHostEndian($f4292244)); // 49 */
    II (d, a, b, c, x[ 7], S42, LittleEndianToHostEndian($432aff97)); // 50 */
    II (c, d, a, b, x[14], S43, LittleEndianToHostEndian($ab9423a7)); // 51 */
    II (b, c, d, a, x[ 5], S44, LittleEndianToHostEndian($fc93a039)); // 52 */
    II (a, b, c, d, x[12], S41, LittleEndianToHostEndian($655b59c3)); // 53 */
    II (d, a, b, c, x[ 3], S42, LittleEndianToHostEndian($8f0ccc92)); // 54 */
    II (c, d, a, b, x[10], S43, LittleEndianToHostEndian($ffeff47d)); // 55 */
    II (b, c, d, a, x[ 1], S44, LittleEndianToHostEndian($85845dd1)); // 56 */
    II (a, b, c, d, x[ 8], S41, LittleEndianToHostEndian($6fa87e4f)); // 57 */
    II (d, a, b, c, x[15], S42, LittleEndianToHostEndian($fe2ce6e0)); // 58 */
    II (c, d, a, b, x[ 6], S43, LittleEndianToHostEndian($a3014314)); // 59 */
    II (b, c, d, a, x[13], S44, LittleEndianToHostEndian($4e0811a1)); // 60 */
    II (a, b, c, d, x[ 4], S41, LittleEndianToHostEndian($f7537e82)); // 61 */
    II (d, a, b, c, x[11], S42, LittleEndianToHostEndian($bd3af235)); // 62 */
    II (c, d, a, b, x[ 2], S43, LittleEndianToHostEndian($2ad7d2bb)); // 63 */
    II (b, c, d, a, x[ 9], S44, LittleEndianToHostEndian($eb86d391)); // 64 */

    Inc(States[0], a);
    Inc(States[1], b);
    Inc(States[2], c);
    Inc(States[3], d);

    //Zeroize sensitive information.*/
    MD5_MemSet(@x, 0, SizeOf(x));
    end;

    (* Encodes input (UINT4) into output (unsigned char). Assumes len is
    a multiple of 4. *)
    procedure TMD5Class.Encode(pOutBuf: PByte; iInBuf: PUINT4; iInBufNumOfBytes: UINT4);
    var
    I, J: UINT4;
    begin
    I:=0; J:=0;
    while J<=(iInBufNumOfBytes-1) do
    begin
    Byte(PChar(pOutBuf)[j]) := Byte((ArrUINT4s(iInBuf, i) ) and $ff);
    Byte(PChar(pOutBuf)[j+1]) := Byte((ArrUINT4s(iInBuf, i) shr 8) and $ff);
    Byte(PChar(pOutBuf)[j+2]) := Byte((ArrUINT4s(iInBuf, i) shr 16) and $ff);
    Byte(PChar(pOutBuf)[j+3]) := Byte((ArrUINT4s(iInBuf, i) shr 24) and $ff);
    Inc(I);
    Inc(J, 4);
    end;
    end;

    (* Decodes input (unsigned char) into output (UINT4). Assumes len is
    a multiple of 4.*)
    procedure TMD5Class.Decode(iOutBuf: PUINT4; pInBuf: PByte; iInBufNumOfBytes: UINT4);
    var
    I, J: UINT4;
    begin
    I:=0; J:=0;
    while J<=(iInBufNumOfBytes-1) do
    begin
    try
    ArrUINT4s(iOutBuf, I, (UINT4(PChar(pInBuf)[J]) ) or
    (UINT4(PChar(pInBuf)[J+1]) shl 8) or
    (UINT4(PChar(pInBuf)[J+2]) shl 16) or
    (UINT4(PChar(pInBuf)[J+3]) shl 24));
    except
    Break;
    end;
    Inc(I);
    Inc(J, 4);
    end;
    end;

    // Note: Replace "for loop" with standard memcpy if possible. */
    procedure TMD5Class.MD5_MemCpy (pDest, pSrc: Pointer; iLen: UINT4);
    var
    I: UINT4;
    begin
    if iLen>0 then
    for I := 0 to iLen-1 do
    PChar(pDest)[I] := PChar(pSrc)[I];
    end;

    // Note: Replace "for loop" with standard memset if possible. */
    procedure TMD5Class.MD5_MemSet(P: POINTER; iValue, iLen: UINT4);
    var
    I: UINT4;
    begin
    for I := 0 to iLen-1 do
    PChar(P)[I] := Char(iValue);
    end;

    class function TMD5Class.DigestToString(MD5Digest: TMD5Digest):string;
    var
    pBuf: PChar;
    begin
    pBuf := AllocMem(64);
    try
    BinToHex(@MD5Digest, pBuf, SizeOf(TMD5Digest));
    Result := string(pBuf);
    finally
    FreeMem(pBuf);
    end;
    end;

    class function TMD5Class.StringToDigest(sMD5Str: string): TMD5Digest;
    var
    pBuf: PChar;
    begin
    pBuf := AllocMem(64);
    try
    HexToBin(PChar(sMD5Str), pBuf, 64);
    Result := PMD5Digest(pBuf)^;
    finally
    FreeMem(pBuf);
    end;
    end;

    end.

  • 相关阅读:
    junit所需要的jar包
    【SSH学习笔记】用Struts2实现简单的用户登录
    HIbernate 一对多 多对多
    Hibernate 干货2
    Hibernate 干货
    hibernate学习笔记
    Hibernate 框架学习
    Class的isAssignableFrom方法
    dubbo源码分析1——SPI机制的概要介绍
    Dubbo简介
  • 原文地址:https://www.cnblogs.com/caibirdy1985/p/4232966.html
Copyright © 2011-2022 走看看