haskell 中的 SHA-1 生成错误的哈希值

SHA-1 in haskell producing wrong hashes

我编写了一个程序来执行 haskell 中的 SHA-1,虽然它确实产生了哈希值,但它们与其他 SHA-1 程序产生的哈希值不匹配

示例:cat 散列为:b5be86bc8bccfc24b01b093228ebb96fc92fa804 但应该散列为 9d989e8d27dc9e0ec3389fc855f142c3d40f0c50

我的代码是:

(old code omitted)

我不知道出了什么问题。谁能告诉我哪里出错了?

编辑: 我修复了指出的问题,但它仍然无法正常工作。它可以正常工作,直到内部循环。 我清理了代码,因此内部循环的函数可用作 f1f2f3 cat 现在有趣地散列为 ebe6c9fa1afa0ef5a0ca80bab251fd41cc29127e

代码:

import Data.Word
import Data.Bits
import Data.Char (ord, intToDigit)
import Data.Binary (encode, decode)
import Numeric (showHex, showIntAtBase)
import System.IO (stdin)
import Data.Sequence ((<|), (|>))
import qualified Data.Sequence as S
import qualified Data.ByteString.Lazy as B
type Quintuple32 = (Word32, Word32, Word32, Word32, Word32)

addQuintuple (a, b, c, d, e) (f, g, h, i, j) =
    (a + f, b + g, c + h, d + i, e + j)

shower :: Quintuple32 -> String
shower (a, b, c, d, e) = concatMap (`showHex` "") [a, b, c, d, e]

hash :: Int -> S.Seq Word32 -> Quintuple32 -> Quintuple32
hash i w h@(a, b, c, d, e)
    | i < 20 = hash (i + 1) w (newhash (f1 h + k1))
    | i < 40 = hash (i + 1) w (newhash (f2 h + k2))
    | i < 60 = hash (i + 1) w (newhash (f3 h + k3))
    | i < 80 = hash (i + 1) w (newhash (f2 h + k4))
    | otherwise = h
  where (k1, k2, k3, k4) = (0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6)
        newhash a' = (rotate a 5 + a' + e + (w `S.index` i), a, rotate b 30, c, d)

f1 :: Quintuple32 -> Word32
f1 (_, b, c, _, _) = (b .&. c) .|. (complement b .&. c)

f2 :: Quintuple32 -> Word32
f2 (_, b, c, d, _) = b `xor` c `xor` d

f3 :: Quintuple32 -> Word32
f3 (_, b, c, d, _) = (b .&. c) .|. (b .&. d) .|. (c .&. d)

starting :: Quintuple32
starting = (0x67452301
           , 0xEFCDAB89
           , 0x98BADCFE
           , 0x10325476
           , 0xC3D2E1F0)

hasher :: Quintuple32 -> S.Seq Word32 -> Quintuple32
hasher acc x = addQuintuple acc (hash 0 (extend x) acc)

process :: B.ByteString -> Quintuple32
process = foldl hasher starting . chunks . pad

extend :: S.Seq Word32 -> S.Seq Word32
extend = extend' 16

extend' :: Int -> S.Seq Word32 -> S.Seq Word32
extend' 80 a = a
extend' i a = extend' (i + 1) (a |> xored)
  where xored = rotate ((a `S.index` (i - 3)) `xor`
                        (a `S.index` (i - 8)) `xor`
                        (a `S.index` (i - 14)) `xor`
                        (a `S.index` (i - 16))) 1

toBytes :: String -> B.ByteString
toBytes = B.pack . map (fromIntegral . ord)

splitEvery n xs
    | B.null xs = S.empty
    | otherwise = B.take n xs <| splitEvery n (B.drop n xs)

chunks :: B.ByteString -> [S.Seq Word32]
chunks xs
    | B.null xs = []
    | otherwise = x : chunks (B.drop 64 xs)
  where x = fmap decode (splitEvery 4 (B.take 64 xs))

pad :: B.ByteString -> B.ByteString
pad xs = B.append (add0 $ add1 xs) length64
  where length64 = encode (fromIntegral (8 * B.length xs) :: Word64)

add1 :: B.ByteString -> B.ByteString
add1 = flip B.append (B.singleton 128)

add0 :: B.ByteString -> B.ByteString
add0 xs
    | modulo /= 448 = add0 $ B.append xs (B.singleton 0)
    | otherwise = xs
  where modulo = (B.length xs * 8) `rem` 512

此外,还有一个小问题:像 (a, b) = (8, 9) 这样设置多个变量是否可以接受?

哦,还有一个!

我立刻跳出两个错误:

pad :: B.ByteString -> B.ByteString
pad xs = B.append (add0 $ add1 xs) length64
  where length64 = encode (fromIntegral (B.length xs) :: Word64)

请注意,您附加的长度应该是位长度,而不是字节长度。

add1 :: B.ByteString -> B.ByteString
add1 = flip B.append (B.singleton 255)

注意255 /= 0b10000000,pad应该是后者。

通常,您通过 1) 反复检查规范来调试这些。 2) 与其他实现(例如 Adam Wick 的 SHA 包)进行比较,并在尽可能细粒度的级别上比较是否相等。

编辑:还有两个错误,基本上是转录错误。环顾四周,如果仍然卡住,请大声喊叫。