• 修改一个MD5的VB源码,使用它支持UTF8编码


    背景

    经常使用Excel的VBA,有天要把一个中文字符串进行MD5密码,上网下了一个源码,发现结果和网站加密的不一样,搜索发现,VBA使用的是GBK编码,其他系统和网站都是使用UTF8编码。只能手动修改一个,让它自动转换成UTF8再MD5。

    源码地址点击这里

    一、分析源码

    这个源码主要有两个Public函数,一个加密文件,一个加密字符串,主要看加密字符串的代码。

    1. Public Function DigestStrToHexStr(SourceString As String) As String
    2. MD5Init
    3. MD5Update Len(SourceString), StringToArray(SourceString)
    4. MD5Final
    5. DigestStrToHexStr = GetValues
    6. End Function
    7. Private Function StringToArray(InString As String) As Byte()
    8. Dim I As Integer
    9. Dim bytBuffer() As Byte
    10. ReDim bytBuffer(Len(InString))
    11. For I = 0 To Len(InString) - 1
    12. bytBuffer(I) = Asc(Mid(InString, I + 1, 1))
    13. Next I
    14. StringToArray = bytBuffer
    15. End Function
    16. Public Sub MD5Update(InputLen As Long, InputBuffer() As Byte)
    17. ......
    18. End Sub

    DigestStrToHexStr函数里主要是用StringToArray把字符串转成Byte数组,再传入MD5Update

    MD5Update的第一个参数是Byte数组的长度,第二个参数是数组指针。

    所以只在把字符串按UTF8编码转成Byte,再传给MD5Update,就完成了。

    二、找GBK转UTF8的源码

    因为VBA只能在WIN平台使用,所以使用WIN32API的WideCharToMultiByte

    1. Private Const BITS_TO_A_BYTE = 8
    2. Private Const BYTES_TO_A_WORD = 4
    3. Private Const BITS_TO_A_WORD = 32
    4. Private m_lOnBits(30)
    5. Private m_l2Power(30)
    6. Public Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, _
    7. ByVal dwFlags As Long, ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long, _
    8. ByVal lpMultiByteStr As LongPtr, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, _
    9. ByVal lpUsedDefaultChar As Long) As Long
    10. Public Declare PtrSafe Function MultiByteToWideChar Lib "kernel32.dll" (ByVal CodePage As Long, _
    11. ByVal dwFlags As Long, ByVal lpMultiByteStr As LongPtr, ByVal cchMultiByte As Long, _
    12. ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long) As Long
    13. Public Const CP_UTF8 = 65001
    14. Public Const CP_ACP = 0

    三、改造

    1. Public Function DigestStrToHexStr(SourceString As String) As String
    2. MD5Init
    3. bByte = WideCharToMultiByte(CP_UTF8, 0, StrPtr(SourceString), Len(SourceString), 0, 0, 0, 0)
    4. Debug.Print bByte
    5. Dim arr() As Byte
    6. ReDim arr(bByte - 1)
    7. WideCharToMultiByte CP_UTF8, 0, StrPtr(SourceString), Len(SourceString), VarPtr(arr(0)), bByte, 0, 0
    8. MD5Update UBound(arr) + 1, arr
    9. MD5Final
    10. DigestStrToHexStr = GetValues
    11. End Function

    四、修改后的全部源码

    1. Private Const BITS_TO_A_BYTE = 8
    2. Private Const BYTES_TO_A_WORD = 4
    3. Private Const BITS_TO_A_WORD = 32
    4. Private m_lOnBits(30)
    5. Private m_l2Power(30)
    6. Public Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, _
    7. ByVal dwFlags As Long, ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long, _
    8. ByVal lpMultiByteStr As LongPtr, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, _
    9. ByVal lpUsedDefaultChar As Long) As Long
    10. Public Declare PtrSafe Function MultiByteToWideChar Lib "kernel32.dll" (ByVal CodePage As Long, _
    11. ByVal dwFlags As Long, ByVal lpMultiByteStr As LongPtr, ByVal cchMultiByte As Long, _
    12. ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long) As Long
    13. Public Const CP_UTF8 = 65001
    14. Public Const CP_ACP = 0
    15. '=
    16. '= Class Constants
    17. '=
    18. Private Const OFFSET_4 = 4294967296#
    19. Private Const MAXINT_4 = 2147483647
    20. Private Const S11 = 7
    21. Private Const S12 = 12
    22. Private Const S13 = 17
    23. Private Const S14 = 22
    24. Private Const S21 = 5
    25. Private Const S22 = 9
    26. Private Const S23 = 14
    27. Private Const S24 = 20
    28. Private Const S31 = 4
    29. Private Const S32 = 11
    30. Private Const S33 = 16
    31. Private Const S34 = 23
    32. Private Const S41 = 6
    33. Private Const S42 = 10
    34. Private Const S43 = 15
    35. Private Const S44 = 21
    36. '=
    37. '= Class Variables
    38. '=
    39. Private State(4) As Long
    40. Private ByteCounter As Long
    41. Private ByteBuffer(63) As Byte
    42. '=
    43. '= Class Properties
    44. '=
    45. Property Get RegisterA() As String
    46. RegisterA = State(1)
    47. End Property
    48. Property Get RegisterB() As String
    49. RegisterB = State(2)
    50. End Property
    51. Property Get RegisterC() As String
    52. RegisterC = State(3)
    53. End Property
    54. Property Get RegisterD() As String
    55. RegisterD = State(4)
    56. End Property
    57. '=
    58. '= Class Functions
    59. '=
    60. '
    61. ' Function to quickly digest a file into a hex string
    62. 'MD5一个文件
    63. Public Function DigestFileToHexStr(FileName As String) As String
    64. Open FileName For Binary Access Read As #1
    65. MD5Init
    66. Do While Not EOF(1)
    67. Get #1, , ByteBuffer
    68. If Loc(1) < LOF(1) Then
    69. ByteCounter = ByteCounter + 64
    70. MD5Transform ByteBuffer
    71. End If
    72. Loop
    73. ByteCounter = ByteCounter + (LOF(1) Mod 64)
    74. Close #1
    75. MD5Final
    76. DigestFileToHexStr = GetValues
    77. End Function
    78. '
    79. ' Function to digest a text string and output the result as a string
    80. ' of hexadecimal characters.
    81. 'MD5一个字符串(转换成UTF8编码)
    82. Public Function DigestStrToHexStr(SourceString As String) As String
    83. MD5Init
    84. bByte = WideCharToMultiByte(CP_UTF8, 0, StrPtr(SourceString), Len(SourceString), 0, 0, 0, 0)
    85. Debug.Print bByte
    86. Dim arr() As Byte
    87. ReDim arr(bByte - 1)
    88. WideCharToMultiByte CP_UTF8, 0, StrPtr(SourceString), Len(SourceString), VarPtr(arr(0)), bByte, 0, 0
    89. MD5Update UBound(arr) + 1, arr
    90. MD5Final
    91. DigestStrToHexStr = GetValues
    92. End Function
    93. '
    94. ' Function to digest a text string and output the result as a string
    95. ' of hexadecimal characters.
    96. 'MD5一个字节数组
    97. Public Function Md5FromByte(SourceByte() As Byte) As String
    98. MD5Init
    99. MD5Update UBound(SourceByte) + 1, SourceByte
    100. MD5Final
    101. DigestStrToHexStr = GetValues
    102. End Function
    103. '
    104. ' A utility function which converts a string into an array of
    105. ' bytes.
    106. '
    107. Private Function StringToArray(InString As String) As Byte()
    108. Dim I As Integer
    109. Dim bytBuffer() As Byte
    110. bByte = WideCharToMultiByte(CP_UTF8, 0, StrPtr(InString), Len(InString), 0, 0, 0, 0)
    111. 'ReDim bytBuffer(LenB(InString))
    112. ReDim bytBuffer(bByte)
    113. For I = 0 To bByte - 1
    114. bytBuffer(I) = Asc(Mid(InString, I + 1, 1))
    115. Next I
    116. StringToArray = bytBuffer
    117. End Function
    118. Private Function ByteToArray(InString As String) As Byte()
    119. Dim I As Integer
    120. Dim bytBuffer() As Byte
    121. bByte = WideCharToMultiByte(CP_UTF8, 0, StrPtr(InString), Len(InString), 0, 0, 0, 0)
    122. 'ReDim bytBuffer(LenB(InString))
    123. ReDim bytBuffer(bByte)
    124. For I = 0 To bByte - 1
    125. bytBuffer(I) = Asc(Mid(InString, I + 1, 1))
    126. Next I
    127. StringToArray = bytBuffer
    128. End Function
    129. '
    130. ' Concatenate the four state vaules into one string
    131. '
    132. Public Function GetValues() As String
    133. GetValues = LongToString(State(1)) & LongToString(State(2)) & LongToString(State(3)) & LongToString(State(4))
    134. End Function
    135. '
    136. ' Convert a Long to a Hex string
    137. '
    138. Private Function LongToString(Num As Long) As String
    139. Dim a As Byte
    140. Dim b As Byte
    141. Dim c As Byte
    142. Dim d As Byte
    143. a = Num And &HFF&
    144. If a < 16 Then
    145. LongToString = "0" & Hex(a)
    146. Else
    147. LongToString = Hex(a)
    148. End If
    149. b = (Num And &HFF00&) \ 256
    150. If b < 16 Then
    151. LongToString = LongToString & "0" & Hex(b)
    152. Else
    153. LongToString = LongToString & Hex(b)
    154. End If
    155. c = (Num And &HFF0000) \ 65536
    156. If c < 16 Then
    157. LongToString = LongToString & "0" & Hex(c)
    158. Else
    159. LongToString = LongToString & Hex(c)
    160. End If
    161. If Num < 0 Then
    162. d = ((Num And &H7F000000) \ 16777216) Or &H80&
    163. Else
    164. d = (Num And &HFF000000) \ 16777216
    165. End If
    166. If d < 16 Then
    167. LongToString = LongToString & "0" & Hex(d)
    168. Else
    169. LongToString = LongToString & Hex(d)
    170. End If
    171. End Function
    172. '
    173. ' Initialize the class
    174. ' This must be called before a digest calculation is started
    175. '
    176. Public Sub MD5Init()
    177. ByteCounter = 0
    178. State(1) = UnsignedToLong(1732584193#)
    179. State(2) = UnsignedToLong(4023233417#)
    180. State(3) = UnsignedToLong(2562383102#)
    181. State(4) = UnsignedToLong(271733878#)
    182. End Sub
    183. '
    184. ' MD5 Final
    185. '
    186. Public Sub MD5Final()
    187. Dim dblBits As Double
    188. Dim padding(72) As Byte
    189. Dim lngBytesBuffered As Long
    190. padding(0) = &H80
    191. dblBits = ByteCounter * 8
    192. ' Pad out
    193. lngBytesBuffered = ByteCounter Mod 64
    194. If lngBytesBuffered <= 56 Then
    195. MD5Update 56 - lngBytesBuffered, padding
    196. Else
    197. MD5Update 120 - ByteCounter, padding
    198. End If
    199. padding(0) = UnsignedToLong(dblBits) And &HFF&
    200. padding(1) = UnsignedToLong(dblBits) \ 256 And &HFF&
    201. padding(2) = UnsignedToLong(dblBits) \ 65536 And &HFF&
    202. padding(3) = UnsignedToLong(dblBits) \ 16777216 And &HFF&
    203. padding(4) = 0
    204. padding(5) = 0
    205. padding(6) = 0
    206. padding(7) = 0
    207. MD5Update 8, padding
    208. End Sub
    209. '
    210. ' Break up input stream into 64 byte chunks
    211. '
    212. Public Sub MD5Update(InputLen As Long, InputBuffer() As Byte)
    213. Dim II As Integer
    214. Dim I As Integer
    215. Dim J As Integer
    216. Dim K As Integer
    217. Dim lngBufferedBytes As Long
    218. Dim lngBufferRemaining As Long
    219. Dim lngRem As Long
    220. lngBufferedBytes = ByteCounter Mod 64
    221. lngBufferRemaining = 64 - lngBufferedBytes
    222. ByteCounter = ByteCounter + InputLen
    223. ' Use up old buffer results first
    224. If InputLen >= lngBufferRemaining Then
    225. For II = 0 To lngBufferRemaining - 1
    226. ByteBuffer(lngBufferedBytes + II) = InputBuffer(II)
    227. Next II
    228. MD5Transform ByteBuffer
    229. lngRem = (InputLen) Mod 64
    230. ' The transfer is a multiple of 64 lets do some transformations
    231. For I = lngBufferRemaining To InputLen - II - lngRem Step 64
    232. For J = 0 To 63
    233. ByteBuffer(J) = InputBuffer(I + J)
    234. Next J
    235. MD5Transform ByteBuffer
    236. Next I
    237. lngBufferedBytes = 0
    238. Else
    239. I = 0
    240. End If
    241. ' Buffer any remaining input
    242. For K = 0 To InputLen - I - 1
    243. ByteBuffer(lngBufferedBytes + K) = InputBuffer(I + K)
    244. Next K
    245. End Sub
    246. '
    247. ' MD5 Transform
    248. '
    249. Private Sub MD5Transform(Buffer() As Byte)
    250. Dim x(16) As Long
    251. Dim a As Long
    252. Dim b As Long
    253. Dim c As Long
    254. Dim d As Long
    255. a = State(1)
    256. b = State(2)
    257. c = State(3)
    258. d = State(4)
    259. Decode 64, x, Buffer
    260. ' Round 1
    261. FF a, b, c, d, x(0), S11, -680876936
    262. FF d, a, b, c, x(1), S12, -389564586
    263. FF c, d, a, b, x(2), S13, 606105819
    264. FF b, c, d, a, x(3), S14, -1044525330
    265. FF a, b, c, d, x(4), S11, -176418897
    266. FF d, a, b, c, x(5), S12, 1200080426
    267. FF c, d, a, b, x(6), S13, -1473231341
    268. FF b, c, d, a, x(7), S14, -45705983
    269. FF a, b, c, d, x(8), S11, 1770035416
    270. FF d, a, b, c, x(9), S12, -1958414417
    271. FF c, d, a, b, x(10), S13, -42063
    272. FF b, c, d, a, x(11), S14, -1990404162
    273. FF a, b, c, d, x(12), S11, 1804603682
    274. FF d, a, b, c, x(13), S12, -40341101
    275. FF c, d, a, b, x(14), S13, -1502002290
    276. FF b, c, d, a, x(15), S14, 1236535329
    277. ' Round 2
    278. GG a, b, c, d, x(1), S21, -165796510
    279. GG d, a, b, c, x(6), S22, -1069501632
    280. GG c, d, a, b, x(11), S23, 643717713
    281. GG b, c, d, a, x(0), S24, -373897302
    282. GG a, b, c, d, x(5), S21, -701558691
    283. GG d, a, b, c, x(10), S22, 38016083
    284. GG c, d, a, b, x(15), S23, -660478335
    285. GG b, c, d, a, x(4), S24, -405537848
    286. GG a, b, c, d, x(9), S21, 568446438
    287. GG d, a, b, c, x(14), S22, -1019803690
    288. GG c, d, a, b, x(3), S23, -187363961
    289. GG b, c, d, a, x(8), S24, 1163531501
    290. GG a, b, c, d, x(13), S21, -1444681467
    291. GG d, a, b, c, x(2), S22, -51403784
    292. GG c, d, a, b, x(7), S23, 1735328473
    293. GG b, c, d, a, x(12), S24, -1926607734
    294. ' Round 3
    295. HH a, b, c, d, x(5), S31, -378558
    296. HH d, a, b, c, x(8), S32, -2022574463
    297. HH c, d, a, b, x(11), S33, 1839030562
    298. HH b, c, d, a, x(14), S34, -35309556
    299. HH a, b, c, d, x(1), S31, -1530992060
    300. HH d, a, b, c, x(4), S32, 1272893353
    301. HH c, d, a, b, x(7), S33, -155497632
    302. HH b, c, d, a, x(10), S34, -1094730640
    303. HH a, b, c, d, x(13), S31, 681279174
    304. HH d, a, b, c, x(0), S32, -358537222
    305. HH c, d, a, b, x(3), S33, -722521979
    306. HH b, c, d, a, x(6), S34, 76029189
    307. HH a, b, c, d, x(9), S31, -640364487
    308. HH d, a, b, c, x(12), S32, -421815835
    309. HH c, d, a, b, x(15), S33, 530742520
    310. HH b, c, d, a, x(2), S34, -995338651
    311. ' Round 4
    312. II a, b, c, d, x(0), S41, -198630844
    313. II d, a, b, c, x(7), S42, 1126891415
    314. II c, d, a, b, x(14), S43, -1416354905
    315. II b, c, d, a, x(5), S44, -57434055
    316. II a, b, c, d, x(12), S41, 1700485571
    317. II d, a, b, c, x(3), S42, -1894986606
    318. II c, d, a, b, x(10), S43, -1051523
    319. II b, c, d, a, x(1), S44, -2054922799
    320. II a, b, c, d, x(8), S41, 1873313359
    321. II d, a, b, c, x(15), S42, -30611744
    322. II c, d, a, b, x(6), S43, -1560198380
    323. II b, c, d, a, x(13), S44, 1309151649
    324. II a, b, c, d, x(4), S41, -145523070
    325. II d, a, b, c, x(11), S42, -1120210379
    326. II c, d, a, b, x(2), S43, 718787259
    327. II b, c, d, a, x(9), S44, -343485551
    328. State(1) = LongOverflowAdd(State(1), a)
    329. State(2) = LongOverflowAdd(State(2), b)
    330. State(3) = LongOverflowAdd(State(3), c)
    331. State(4) = LongOverflowAdd(State(4), d)
    332. ' /* Zeroize sensitive information.
    333. '*/
    334. ' MD5_memset ((POINTER)x, 0, sizeof (x));
    335. End Sub
    336. Private Sub Decode(Length As Integer, OutputBuffer() As Long, InputBuffer() As Byte)
    337. Dim intDblIndex As Integer
    338. Dim intByteIndex As Integer
    339. Dim dblSum As Double
    340. intDblIndex = 0
    341. For intByteIndex = 0 To Length - 1 Step 4
    342. dblSum = InputBuffer(intByteIndex) + _
    343. InputBuffer(intByteIndex + 1) * 256# + _
    344. InputBuffer(intByteIndex + 2) * 65536# + _
    345. InputBuffer(intByteIndex + 3) * 16777216#
    346. OutputBuffer(intDblIndex) = UnsignedToLong(dblSum)
    347. intDblIndex = intDblIndex + 1
    348. Next intByteIndex
    349. End Sub
    350. '
    351. ' FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
    352. ' Rotation is separate from addition to prevent recomputation.
    353. '
    354. Private Function FF(a As Long, _
    355. b As Long, _
    356. c As Long, _
    357. d As Long, _
    358. x As Long, _
    359. s As Long, _
    360. ac As Long) As Long
    361. a = LongOverflowAdd4(a, (b And c) Or (Not (b) And d), x, ac)
    362. a = LongLeftRotate(a, s)
    363. a = LongOverflowAdd(a, b)
    364. End Function
    365. Private Function GG(a As Long, _
    366. b As Long, _
    367. c As Long, _
    368. d As Long, _
    369. x As Long, _
    370. s As Long, _
    371. ac As Long) As Long
    372. a = LongOverflowAdd4(a, (b And d) Or (c And Not (d)), x, ac)
    373. a = LongLeftRotate(a, s)
    374. a = LongOverflowAdd(a, b)
    375. End Function
    376. Private Function HH(a As Long, _
    377. b As Long, _
    378. c As Long, _
    379. d As Long, _
    380. x As Long, _
    381. s As Long, _
    382. ac As Long) As Long
    383. a = LongOverflowAdd4(a, b Xor c Xor d, x, ac)
    384. a = LongLeftRotate(a, s)
    385. a = LongOverflowAdd(a, b)
    386. End Function
    387. Private Function II(a As Long, _
    388. b As Long, _
    389. c As Long, _
    390. d As Long, _
    391. x As Long, _
    392. s As Long, _
    393. ac As Long) As Long
    394. a = LongOverflowAdd4(a, c Xor (b Or Not (d)), x, ac)
    395. a = LongLeftRotate(a, s)
    396. a = LongOverflowAdd(a, b)
    397. End Function
    398. '
    399. ' Rotate a long to the right
    400. '
    401. Function LongLeftRotate(value As Long, bits As Long) As Long
    402. Dim lngSign As Long
    403. Dim lngI As Long
    404. bits = bits Mod 32
    405. If bits = 0 Then LongLeftRotate = value: Exit Function
    406. For lngI = 1 To bits
    407. lngSign = value And &HC0000000
    408. value = (value And &H3FFFFFFF) * 2
    409. value = value Or ((lngSign < 0) And 1) Or (CBool(lngSign And _
    410. &H40000000) And &H80000000)
    411. Next
    412. LongLeftRotate = value
    413. End Function
    414. '
    415. ' Function to add two unsigned numbers together as in C.
    416. ' Overflows are ignored!
    417. '
    418. Private Function LongOverflowAdd(Val1 As Long, Val2 As Long) As Long
    419. Dim lngHighWord As Long
    420. Dim lngLowWord As Long
    421. Dim lngOverflow As Long
    422. lngLowWord = (Val1 And &HFFFF&) + (Val2 And &HFFFF&)
    423. lngOverflow = lngLowWord \ 65536
    424. lngHighWord = (((Val1 And &HFFFF0000) \ 65536) + ((Val2 And &HFFFF0000) \ 65536) + lngOverflow) And &HFFFF&
    425. LongOverflowAdd = UnsignedToLong((lngHighWord * 65536#) + (lngLowWord And &HFFFF&))
    426. End Function
    427. '
    428. ' Function to add two unsigned numbers together as in C.
    429. ' Overflows are ignored!
    430. '
    431. Private Function LongOverflowAdd4(Val1 As Long, Val2 As Long, val3 As Long, val4 As Long) As Long
    432. Dim lngHighWord As Long
    433. Dim lngLowWord As Long
    434. Dim lngOverflow As Long
    435. lngLowWord = (Val1 And &HFFFF&) + (Val2 And &HFFFF&) + (val3 And &HFFFF&) + (val4 And &HFFFF&)
    436. lngOverflow = lngLowWord \ 65536
    437. lngHighWord = (((Val1 And &HFFFF0000) \ 65536) + _
    438. ((Val2 And &HFFFF0000) \ 65536) + _
    439. ((val3 And &HFFFF0000) \ 65536) + _
    440. ((val4 And &HFFFF0000) \ 65536) + _
    441. lngOverflow) And &HFFFF&
    442. LongOverflowAdd4 = UnsignedToLong((lngHighWord * 65536#) + (lngLowWord And &HFFFF&))
    443. End Function
    444. '
    445. ' Convert an unsigned double into a long
    446. '
    447. Private Function UnsignedToLong(value As Double) As Long
    448. If value < 0 Or value >= OFFSET_4 Then Error 6 ' Overflow
    449. If value <= MAXINT_4 Then
    450. UnsignedToLong = value
    451. Else
    452. UnsignedToLong = value - OFFSET_4
    453. End If
    454. End Function
    455. '
    456. ' Convert a long to an unsigned Double
    457. '
    458. Private Function LongToUnsigned(value As Long) As Double
    459. If value < 0 Then
    460. LongToUnsigned = value + OFFSET_4
    461. Else
    462. LongToUnsigned = value
    463. End If
    464. End Function

  • 相关阅读:
    EMAS Serverless系列~4步教你快速搭建小程序
    【QT】窗口的大小标题图标设置
    聊一聊异构系统间数据一致性
    Linux安装RabbitMQ详细教程(图文)erlang24.1+RabbitMQ3.9.7
    企业日常公关如何抵御负面信息的入侵?
    基于云计算与深度学习的常见作物害虫识别系统的设计与实现
    CSP-J 2022年8月第一轮模拟赛 1
    KITTI 数据集简介
    leetcode算法题--数值的整数次方
    反射(类加载、加载流程、加载的五个阶段、获取类结构信息、反射暴破创建实例、操作属性、操作方法)
  • 原文地址:https://blog.csdn.net/LILI00000/article/details/133414832