我已经编写了以下MD5算法的实现。但是,哈希值与在线生成器的哈希值不匹配。
更正"testing"
的MD5哈希是"ae2b1fca515949e5d54fb22b8ed95575"
但我的计划提供了"786fc25092f719e0349ed15efcbe8460"
我的错误在哪里?
说明:导入必要的库并设置常量
import Data.Bits
import Data.Word
import Data.Char
import Text.Printf -- For pretty output of hexdigest
import qualified Data.Array as A
type Numbers = (Word32, Word32, Word32, Word32)
roundShift = A.listArray (0, 63) [7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21]
sines = A.listArray (0, 63) [ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ]
-- Tables found in Wiki
说明:转化
convertToW32 :: (Word8, Word8, Word8, Word8) -> Word32
convertToW32 (a,b,c,d) = (fromIntegral a) + shiftL (fromIntegral b) 8 + shiftL (fromIntegral c) 16 + shiftL (fromIntegral d) 24
convertToW8s :: Int -> Word64 -> [Word8]
convertToW8s 0 w = [fromIntegral w]
convertToW8s n w = let (p, q) = w `quotRem` (256 ^ n) in fromIntegral p : convertToW8s (n - 1) q
说明:将输入字符串准备为块
preprocess :: String -> [Word8]
preprocess message = map (fromIntegral . ord) message ++ padding ++ (convertToW8s 7 . byteSwap64 $ fromIntegral ln)
where ln = length message
padding = 0x80 : replicate ((55 - ln) `mod` 64) 0x00
-- required 512-bit input, return array (0, 15)
chunkize :: [Word8] -> [A.Array Int Word32]
chunkize [] = []
chunkize xs = if length xs < 64
then error "Cannot form chunk!"
else A.listArray (0, 15) (bulkConvert p) : chunkize q
where (p, q) = splitAt 64 xs
bulkConvert [] = []
bulkConvert (a:b:c:d:r) = convertToW32 (a,b,c,d) : bulkConvert r
说明:为每个块运行Wiki中提到的循环
findABCD :: Numbers -> A.Array Int Word32 -> Numbers
findABCD tt m = foldl loop tt [0..63]
where loop t@(a,b,c,d) x = let (f,g,i) = fgi t x in (d, b + rotateL (a + f + sines A.! i + m A.! g) (roundShift A.! i), b, c)
fgi :: Numbers -> Int -> (Word32, Int, Int)
fgi (a, b, c, d) i
| 0 <= i && i <= 15 = ((b .&. c) .|. ((complement b) .&. d), i, i)
| 16 <= i && i <= 31 = ((d .&. b) .|. ((complement d) .&. c), (1 + 5 * i) `mod` 16, i)
| 32 <= i && i <= 47 = (b `xor` c `xor` d, (5 + 3 * i) `mod` 16, i)
| 48 <= i && i <= 63 = (c `xor` ((complement d) .|. b), (7 * i) `mod` 16, i)
| otherwise = error "Index exceeds range!"
说明:字符串的md5sum; main只是一个调用函数
md5 :: String -> String
md5 message = printf "%08x%08x%08x%08x" a0 b0 c0 d0
where (a0, b0, c0, d0) = foldl addToResult (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476) (chunkize $ preprocess message)
addToResult t@(a, b, c, d) arr = let (a', b', c', d') = findABCD t arr in (a + a', b + b', c + c', d + d')
main = putStrLn . md5 =<< getLine