【技术勘误】用网上流传的“MD5模块”的千万要注意了!

学渣ydm_bd 2013-03-24 06:17:57
加精
现在的MD5计算模块似乎有几种版本,
但是,大部分(甚至包括ASP的版本)存在【文件MD5计算不正确】的现象。
经过我的仔细检查,其中网上流传甚广的两个能计算文件的版本是错误的。
问题发生在计算一些具有特定文件/字符串大小的时候,问题出现几率很高。

举几个例子(百度上随机抽选的)
问题版本1:MD5函数为【Md5_[File/String]_Calc】
http://hi.baidu.com/xlsdg/item/b72dbbbe6adb7f40ba0e12dd
问题版本2:MD5函数为【Digest[File/String]ToHexStr】
http://www.programfan.com/article/772.html

其实,他们的源头都是这一个Robert Hubley的版本
http://www.hackhome.com/InfoView/Article_106283.html

【错误一】
MD5Final函数的一个If语句:

If lngBytesBuffered <= 56 Then
MD5Update 56 - lngBytesBuffered, padding
Else
MD5Update 120 - ByteCounter, padding
End If

应该改为

If lngBytesBuffered <= 56 Then
MD5Update 56 - lngBytesBuffered, padding
Else
MD5Update 120 - lngBytesBuffered, padding
End If

(即ByteCounter改为lngBytesBuffered)

【错误二】
文件计算的读取条件判断出错
DigestFileToHexStr(或者叫Md5_File_Calc)中
If Loc(1) < LOF(1) Then

应该改为:
If Loc(1) <= LOF(1) Then


【经过多次测试,并与权威MD5数据对比,修改后程序给出的MD5数据全部正确】

当然,只有特定的长度才会触发BUG(但是这个范围相当广).
以下是字符串函数的触发长度,包括了56,120-127,184-192....这些范围

集合法表示:字符串BUG长度集合={56}∪{x∈Z|x∈[64n-8,64n-1],2<n}

你自己也可以试试用(56字节)"12345678901234567890123456789012345678901234567890123456"计算,标准数据是49F193ADCE178490E34D1B3A4EC0064C,错误程序结果是29DC63DA78D43A804E8A4D4DCA707CC2

当使用文件函数时,因为问题二,导致长度等于64倍数的文件都会缺少一个字节进行MD5Transform,
即长度等于64倍数的文件也会触发BUG
因为与字符串计算用的是同一个出问题的MD5Final,所以,
集合法表示:文件BUG长度集合=字符串BUG长度集合∪{n∈Z|64n,1≤n}


希望能加精~
警醒使用网络上流传该类代码的人,以免造成大家的损失。

(转自本人'ydm_bd'百度贴吧原文.http://tieba.baidu.com/p/2088917195)
...全文
15892 66 打赏 收藏 转发到动态 举报
写回复
用AI写文章
66 条回复
切换为时间正序
请发表友善的回复…
发表回复
hoodlum1980 2013-08-24
  • 打赏
  • 举报
回复
纠正一下楼主帖子里的说法: “其实,他们的源头都是这一个Robert Hubley的版本” 源头在于哪里,应该是来自国外的人的C语言版本的代码,这个版本的代码是没有问题的。 包括这个 Robert Hubley 的版本也是 C语言版本的。 我使用的是这个版本的代码并未标注是由 Robert Hubley 改动过(估计这是更根源的版本,它的版权信息是:Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.),代码如下: http://www.linuxidc.com/Linux/2011-12/49783.htm 我用这个版本的代码测试你说的字符串的结果是正确的。 所以楼主说的bug是位于经由C版本代码被“翻译”成 VB 代码时引入的,这我不知道是什么人翻译的,既然有这么粗心的错误我倒是有点感觉可能是国人干的。。。(原谅我对国人的治学态度的持怀疑态度)。 最后解答一下,为什么不使用.NET提供的库,答案就是我们可能并没有采用 .net 技术来开发我们的软件。所以就用不上。如果用 .NET 来做,当然没必要再去搜寻相关的源码。
泡泡龙 2013-04-10
  • 打赏
  • 举报
回复
为啥不用API? Cryptdll.dll advapi32.dll都行 Option Explicit Option Base 0 Public Type MD5_CTX i(1) As Long buf(3) As Long inc(63) As Byte digest(15) As Byte End Type Public Declare Sub MD5Init Lib "Cryptdll.dll" (ByVal pContex As Long) Public Declare Sub MD5Final Lib "Cryptdll.dll" (ByVal pContex As Long) Public Declare Sub MD5Update Lib "Cryptdll.dll" (ByVal pContex As Long, ByVal lPtr As Long, ByVal nSize As Long) Public Function ConvBytesToBinaryString(bytesIn() As Byte) As String Dim i As Long Dim nSize As Long Dim strRet As String nSize = UBound(bytesIn) For i = 0 To nSize strRet = strRet & Right$("0" & Hex(bytesIn(i)), 2) Next ConvBytesToBinaryString = strRet End Function Public Function GetMD5Hash(bytesIn() As Byte) As Byte() Dim ctx As MD5_CTX Dim nSize As Long nSize = UBound(bytesIn) + 1 MD5Init VarPtr(ctx) MD5Update ByVal VarPtr(ctx), ByVal VarPtr(bytesIn(0)), nSize MD5Final VarPtr(ctx) GetMD5Hash = ctx.digest End Function Public Function GetMD5Hash_Bytes(bytesIn() As Byte) As String GetMD5Hash_Bytes = ConvBytesToBinaryString(GetMD5Hash(bytesIn)) End Function Public Function GetMD5Hash_String(ByVal strIn As String) As String GetMD5Hash_String = GetMD5Hash_Bytes(StrConv(strIn, vbFromUnicode)) End Function Public Function GetMD5Hash_File(ByVal strFile As String) As String Dim lFile As Long Dim bytes() As Byte Dim lSize As Long lSize = FileLen(strFile) If (lSize) Then lFile = FreeFile ReDim bytes(lSize - 1) Open strFile For Binary As lFile Get lFile, , bytes Close lFile GetMD5Hash_File = GetMD5Hash_Bytes(bytes) End If End Function Option Explicit Public Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Long, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long Public Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Long, ByVal dwFlags As Long) As Long Public Declare Function CryptCreateHash Lib "advapi32.dll" (ByVal hProv As Long, ByVal Algid As Long, ByVal hKey As Long, ByVal dwFlags As Long, ByRef phHash As Long) As Long Public Declare Function CryptDestroyHash Lib "advapi32.dll" (ByVal hHash As Long) As Long Public Declare Function CryptHashData Lib "advapi32.dll" (ByVal hHash As Long, pbData As Any, ByVal dwDataLen As Long, ByVal dwFlags As Long) As Long Public Declare Function CryptGetHashParam Lib "advapi32.dll" (ByVal hHash As Long, ByVal dwParam As Long, pbData As Any, pdwDataLen As Long, ByVal dwFlags As Long) As Long Public Const PROV_RSA_FULL = 1 Public Const CRYPT_NEWKEYSET = &H8 Public Const ALG_CLASS_HASH = 32768 Public Const ALG_TYPE_ANY = 0 Public Const ALG_SID_MD2 = 1 Public Const ALG_SID_MD4 = 2 Public Const ALG_SID_MD5 = 3 Public Const ALG_SID_SHA1 = 4 Enum HashAlgorithm MD2 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD2 MD4 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD4 MD5 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD5 SHA1 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SHA1 End Enum Public Const HP_HASHVAL = 2 Public Const HP_HASHSIZE = 4 Public Function HashFile(ByVal FileName As String, Optional ByVal Algorithm As HashAlgorithm = MD5) As String Dim hCtx As Long Dim hHash As Long Dim lFile As Long Dim lRes As Long Dim lLen As Long Dim lIdx As Long Dim abHash() As Byte If Len(Dir$(FileName)) = 0 Then Err.Raise 53 lRes = CryptAcquireContext(hCtx, vbNullString, vbNullString, PROV_RSA_FULL, 0) If lRes = 0 And Err.LastDllError = &H80090016 Then lRes = CryptAcquireContext(hCtx, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_NEWKEYSET) End If If lRes <> 0 Then lRes = CryptCreateHash(hCtx, Algorithm, 0, 0, hHash) If lRes <> 0 Then lFile = FreeFile Open FileName For Binary As lFile If Err.Number = 0 Then Const BLOCK_SIZE As Long = 32 * 1024& ' 32K ReDim abBlock(1 To BLOCK_SIZE) As Byte Dim lCount As Long Dim lBlocks As Long Dim lLastBlock As Long lBlocks = LOF(lFile) / BLOCK_SIZE lLastBlock = LOF(lFile) - lBlocks * BLOCK_SIZE For lCount = 1 To lBlocks Get lFile, , abBlock lRes = CryptHashData(hHash, abBlock(1), BLOCK_SIZE, 0) If lRes = 0 Then Exit For Next If lLastBlock > 0 And lRes <> 0 Then ReDim abBlock(1 To lLastBlock) As Byte Get lFile, , abBlock lRes = CryptHashData(hHash, abBlock(1), lLastBlock, 0) End If Close lFile End If If lRes <> 0 Then lRes = CryptGetHashParam(hHash, HP_HASHSIZE, lLen, 4, 0) If lRes <> 0 Then ReDim abHash(0 To lLen - 1) lRes = CryptGetHashParam(hHash, HP_HASHVAL, abHash(0), lLen, 0) If lRes <> 0 Then For lIdx = 0 To UBound(abHash) HashFile = HashFile & Right$("0" & Hex$(abHash(lIdx)), 2) DoEvents Next End If End If End If CryptDestroyHash hHash End If End If CryptReleaseContext hCtx, 0 If lRes = 0 Then Err.Raise Err.LastDllError End Function
格利高里 2013-04-10
  • 打赏
  • 举报
回复
我以前也发现这个问题,但没有深入研究,惭愧
格利高里 2013-04-10
  • 打赏
  • 举报
回复
楼主不错,支持一把。
月蚀 2013-04-09
  • 打赏
  • 举报
回复
LZ好人
walkonthesky 2013-04-08
  • 打赏
  • 举报
回复
MS 提供有MD5接口,MS平台上没理由用第三方的实现吧
lhw7791086 2013-04-06
  • 打赏
  • 举报
回复
江湖影 2013-04-04
  • 打赏
  • 举报
回复
好专业,学习了
u010160858 2013-04-04
  • 打赏
  • 举报
回复
顶一下非常不错
光明与黑黯 2013-04-04
  • 打赏
  • 举报
回复
看不懂 但学学
taohuirong 2013-04-03
  • 打赏
  • 举报
回复
感谢分享
yuhaozx 2013-04-03
  • 打赏
  • 举报
回复
谢谢分享,不错
u010147864 2013-04-03
  • 打赏
  • 举报
回复
学渣ydm_bd 2013-04-02
  • 打赏
  • 举报
回复
引用 43 楼 htpower 的回复:
Visual Basic code?12345678910111213141516Public Shared Function MD5(ByVal input As String, ByVal coda As Integer) As String Dim md5Hasher As New MD5CryptoServiceProvider Dim……
对于.NET的确没有类似问题,但是其他的如ASP,VB6,VBS等不带算法支持库的语言,一般人首选就是百度。
ziddu1 2013-04-02
  • 打赏
  • 举报
回复
谢谢分享,学习了
月蚀 2013-04-02
  • 打赏
  • 举报
回复
谢LZ,看看
ccrun.com 2013-04-01
  • 打赏
  • 举报
回复
引用 13 楼 caozhy 的回复:
百度一下,你就上当。因为这些用百度的人愚不可及啊。
huang793807836 2013-04-01
  • 打赏
  • 举报
回复
百度的那两个我研究了大半天,没看懂,曾经的事
lliai 2013-04-01
  • 打赏
  • 举报
回复
谢谢分享……
htpower 2013-04-01
  • 打赏
  • 举报
回复

Public Shared Function MD5(ByVal input As String, ByVal coda As Integer) As String
        Dim md5Hasher As New MD5CryptoServiceProvider
        Dim data As Byte() = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input))
        Dim sBuilder As New StringBuilder
        Dim i As Integer
        If coda = 16 Then
            For i = 4 To 11
                sBuilder.Append(data(i).ToString("x2"))
            Next i
        Else
            For i = 0 To 15
                sBuilder.Append(data(i).ToString("x2"))
            Next i
        End If
        Return sBuilder.ToString()
    End Function
楼主,为何有标准的放着不用,非要用自已写的模块?
加载更多回复(35)

7,759

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧