112 lines
3.9 KiB
Haskell
112 lines
3.9 KiB
Haskell
module RFC6979
|
|
-- (
|
|
-- rfcTasks
|
|
-- )
|
|
where
|
|
|
|
import Crypto.Hash(SHA224(..),SHA256(..),SHA384(..),SHA512(..))
|
|
import Crypto.MAC.HMAC(HMAC,hmac)
|
|
import Crypto.Number.Generate(generateBetween)
|
|
import Crypto.Random(getRandomBytes,withDRG)
|
|
import Data.Bits(shiftL,shiftR,(.&.))
|
|
import qualified Data.ByteArray as B
|
|
import qualified Data.ByteString as S
|
|
import Data.Char(toUpper)
|
|
import qualified Data.Map.Strict as Map
|
|
import Math(showBin,showX)
|
|
import Task(Task(..))
|
|
import Utils(HashAlg(..), runHash)
|
|
|
|
|
|
runHMAC :: HashAlg -> S.ByteString -> S.ByteString -> S.ByteString
|
|
runHMAC Sha224 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA224))
|
|
runHMAC Sha256 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA256))
|
|
runHMAC Sha384 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA384))
|
|
runHMAC Sha512 key msg = S.pack (B.unpack (hmac key msg :: HMAC SHA512))
|
|
|
|
generateKStream :: HashAlg -> S.ByteString -> Integer -> Integer -> Int -> [Integer]
|
|
generateKStream alg m x q qlen = nextK bigK2 bigV2
|
|
where
|
|
h1 = runHash alg m
|
|
bigV0 = S.replicate (S.length h1) 0x01
|
|
bigK0 = S.replicate (S.length h1) 0x00
|
|
seed1 = S.concat [bigV0, S.singleton 0x00, int2octets qlen x, bits2octets qlen q h1]
|
|
bigK1 = runHMAC alg bigK0 seed1
|
|
bigV1 = runHMAC alg bigK1 bigV0
|
|
seed2 = S.concat [bigV1, S.singleton 0x01, int2octets qlen x, bits2octets qlen q h1]
|
|
bigK2 = runHMAC alg bigK1 seed2
|
|
bigV2 = runHMAC alg bigK2 bigV1
|
|
--
|
|
nextK bigK bigV =
|
|
let (bigV', bigT) = buildT bigK bigV S.empty
|
|
k = bits2int qlen bigT
|
|
bigK' = runHMAC alg bigK (bigV' `S.append` S.singleton 0)
|
|
bigV'' = runHMAC alg bigK' bigV'
|
|
in if k < q then (k : nextK bigK' bigV'') else nextK bigK' bigV''
|
|
buildT bigK bigV bigT
|
|
| S.length bigT * 8 >= qlen = (bigV, bigT)
|
|
| otherwise =
|
|
let bigV' = runHMAC alg bigK bigV
|
|
in buildT bigK bigV' (bigT `S.append` bigV')
|
|
|
|
bits2int :: Int -> S.ByteString -> Integer
|
|
bits2int qlen bstr = reduce (go bstr 0)
|
|
where
|
|
reduce x =
|
|
let vlen = S.length bstr * 8
|
|
in if vlen > qlen
|
|
then x `shiftR` (vlen - qlen)
|
|
else x
|
|
--
|
|
go x acc =
|
|
case S.uncons x of
|
|
Nothing -> acc
|
|
Just (v, rest) ->
|
|
go rest ((acc `shiftL` 8) + fromIntegral v)
|
|
|
|
int2octets :: Int -> Integer -> S.ByteString
|
|
int2octets lenBits x =
|
|
S.pack (pad (rlen `div` 8) (reverse (go x)))
|
|
where
|
|
rlen = 8 * ((lenBits + 7) `div` 8)
|
|
pad target ls
|
|
| length ls > target = drop (length ls - target) ls
|
|
| length ls < target = pad target (0 : ls)
|
|
| otherwise = ls
|
|
--
|
|
go 0 = []
|
|
go v = (fromIntegral (v .&. 0xFF)) : go (v `shiftR` 8)
|
|
|
|
bits2octets :: Int -> Integer -> S.ByteString -> S.ByteString
|
|
bits2octets qlen q bstr =
|
|
let z1 = bits2int qlen bstr
|
|
z2 = if z1 > q then z1 - q else z1
|
|
in int2octets qlen z2
|
|
|
|
rfc6979Test :: HashAlg -> Task
|
|
rfc6979Test alg = Task {
|
|
taskName = name ++ " RFC 6979 deterministic k-generation",
|
|
taskFile = "../testdata/rfc6979/" ++ name ++ ".test",
|
|
taskTest = go,
|
|
taskCount = 1000
|
|
}
|
|
where
|
|
name = map toUpper (show alg)
|
|
go (memory0, drg0) =
|
|
let (qlen, drg1) = withDRG drg0 $ generateBetween 160 521
|
|
(key, drg2) = withDRG drg1 $ generateBetween 1 ((2 ^ qlen) - 1)
|
|
(q, drg3) = withDRG drg2 $ generateBetween 1 ((2 ^ qlen) - 1)
|
|
(dataSize, drg4) = withDRG drg3 $ generateBetween 1 1024
|
|
(msg, drg5) = withDRG drg4 $ getRandomBytes (fromIntegral dataSize)
|
|
h1 = runHash alg msg
|
|
ks = generateKStream alg msg key q (fromIntegral qlen)
|
|
res = Map.fromList [("q", showX q), ("l", showX qlen),
|
|
("x", showX key), ("h", showBin h1),
|
|
("k", showX (ks !! 0)),
|
|
("y", showX (ks !! 1)),
|
|
("z", showX (ks !! 2))]
|
|
in (res, qlen, (memory0, drg5))
|
|
|
|
rfcTasks :: [Task]
|
|
rfcTasks = [rfc6979Test Sha224, rfc6979Test Sha256,
|
|
rfc6979Test Sha384, rfc6979Test Sha512] |