Hi, After a few weeks of hard work I have managed to add the CTR, CMAC and SIV modes of operation. The implemententation passes all the KATS I could find and is made as efficiently as possible without forgetting the risk of timing attacks over them. The patch is attached here and you can free it along with your library with a BSD-3 license as long as you recognize the authorship.
Francisco Blas Izquierdo Riera (klondike) PS: Attached is also a set of commands I used with ghci to check quickly the implementation and which contain parts of the KATS I used, feel free to use them.
diff -ur crypto-api-0.5.2/Crypto/Modes.hs crypto-api-0.5.2.new/Crypto/Modes.hs
--- crypto-api-0.5.2/Crypto/Modes.hs 2011-02-16 17:46:11.000000000 +0100
+++ crypto-api-0.5.2.new/Crypto/Modes.hs 2011-04-09 01:44:06.743745436
+0200
@@ -12,7 +12,7 @@
(
-- * Initialization Vector Type (for all ciphers for all modes that use
IVs)
IV
- , getIV, getIVIO
+ , getIV, getIVIO, zeroIV
-- * Blockcipher modes of operation. Note name' (with a prime) means
strict, without a prime means lazy bytestrings.
, ecb, unEcb
, cbc, unCbc
@@ -28,7 +28,9 @@
-- , gmc
-- , xts
-- , ccm
- -- , ctr, unCtr, ctr', unCtr'
+ , cMac', cMac
+ , ctr, unCtr, ctr', unCtr', incIV, dblIV
+ , siv, unSiv, siv', unSiv'
) where
import qualified Data.ByteString as B
@@ -36,12 +38,15 @@
import Data.Serialize
import qualified Data.Serialize.Put as SP
import qualified Data.Serialize.Get as SG
-import Data.Bits (xor)
+import Data.Bits
(xor,shift,(.&.),(.|.),testBit,setBit,clearBit,Bits,complementBit)
import Data.Tagged
import Crypto.Classes
import Crypto.Random
+import Crypto.CPoly
import System.Crypto.Random (getEntropy)
import Control.Monad (liftM)
+import Data.Word (Word8)
+import Data.List (genericDrop,genericReplicate,genericLength)
#if MIN_VERSION_tagged(0,2,0)
import Data.Proxy
#endif
@@ -120,10 +125,10 @@
in (c:cs, ivFinal)
cbcMac' :: BlockCipher k => k -> B.ByteString -> B.ByteString
-cbcMac' k pt = encode $ snd $ cbc' k (IV (B.replicate (blockSize `for` k) 0))
pt
+cbcMac' k pt = encode $ snd $ cbc' k zeroIV pt
cbcMac :: BlockCipher k => k -> L.ByteString -> L.ByteString
-cbcMac k pt = L.fromChunks [encode $ snd $ cbc k (IV (B.replicate (blockSize
`for` k) 0)) pt]
+cbcMac k pt = L.fromChunks [encode $ snd $ cbc k zeroIV pt]
-- |Cipher block chaining decryption for strict bytestrings
unCbc' :: BlockCipher k => k -> IV k -> B.ByteString -> (B.ByteString, IV k)
@@ -261,6 +266,253 @@
newIV = IV . B.concat . L.toChunks . L.take (fromIntegral ivLen) .
L.drop mLen . L.fromChunks $ ivStr
in (zwp' (B.concat ivStr) msg, newIV)
+-- |Counter mode for lazy bytestrings
+ctr :: BlockCipher k => (IV k -> IV k) -> k -> IV k -> L.ByteString ->
(L.ByteString, IV k)
+ctr = unCtr
+
+-- |Counter mode for lazy bytestrings
+unCtr :: BlockCipher k => (IV k -> IV k) -> k -> IV k -> L.ByteString ->
(L.ByteString, IV k)
+unCtr f k (IV iv) msg =
+ let ivStr = iterate f $ IV iv
+ ivLen = fromIntegral $ B.length iv
+ newIV = head $ genericDrop ((ivLen - 1 + L.length msg) `div` ivLen)
ivStr
+ in (zwp (L.fromChunks $ map (encryptBlock k) $ map initializationVector
ivStr) msg, newIV)
+
+-- |Counter mode for strict bytestrings
+ctr' :: BlockCipher k => (IV k -> IV k) -> k -> IV k -> B.ByteString ->
(B.ByteString, IV k)
+ctr' = unCtr'
+
+-- |Counter mode for strict bytestrings
+unCtr' :: BlockCipher k => (IV k -> IV k) -> k -> IV k -> B.ByteString ->
(B.ByteString, IV k)
+unCtr' f k (IV iv) msg =
+ let ivStr = iterate f $ IV iv
+ ivLen = fromIntegral $ B.length iv
+ newIV = head $ genericDrop ((ivLen - 1 + B.length msg) `div` ivLen)
ivStr
+ in (zwp' (B.concat $ collect (B.length msg) (map (encryptBlock k .
initializationVector) ivStr)) msg, newIV)
+
+-- |Generate cmac subkeys
+-- |The usage of seq tries to force evaluation of both keys avoiding posible
timing attacks
+cMacSubk :: BlockCipher k => k -> (IV k, IV k)
+cMacSubk k = (k1, k2) `seq` (k1, k2)
+ where
+ bSize = blockSizeBytes `for` k
+ k1 = dblIV $ IV $ encryptBlock k $ B.replicate bSize 0
+ k2 = dblIV $ k1
+
+-- |Pad the string as required by the cmac algorithm. In theory this should
work
+-- | at bit level but since the API works at byte level we do the same
+cMacPad :: ([Word8], Bool, Int) -> Maybe (Word8,([Word8], Bool, Int))
+cMacPad (_, _, 0) = Nothing
+cMacPad ([], False, n) = Just (0,([], False, n-1))
+cMacPad ([], True, n) = Just (128,([], False, n-1))
+cMacPad (x:xs, b, n) = Just (x,(xs, b, n-1))
+
+-- |Obtain the cmac with the specified subkey for lazy bytestrings
+cMacWithSubK :: BlockCipher k => k -> (IV k, IV k) -> L.ByteString ->
L.ByteString
+cMacWithSubK k (IV k1, IV k2) l = L.fromChunks $ [go (chunkFor k t) $
B.replicate bSize1 0]
+ where
+ bSize1 = fromIntegral $ blockSizeBytes `for` k
+ bSize2 = fromIntegral $ blockSizeBytes `for` k
+ (t,e) = L.splitAt (((L.length l-1)`div` bSize2)*bSize2) l
+ pe = fst $ B.unfoldrN (bSize1) cMacPad (L.unpack e,True,bSize1)
+ fe | bSize2 == L.length e = zwp' k1 pe
+ | otherwise = zwp' k2 pe
+ go [] c = encryptBlock k (zwp' c fe)
+ go (x:xs) c = go xs $ encryptBlock k $ zwp' c x
+
+-- |Obtain the cmac for lazy bytestrings
+cMac :: BlockCipher k => k -> L.ByteString -> L.ByteString
+cMac k = cMacWithSubK k (cMacSubk k)
+
+-- |Obtain the cmac with the specified subkey for strict bytestrings
+cMacWithSubK' :: BlockCipher k => k -> (IV k, IV k) -> B.ByteString ->
B.ByteString
+cMacWithSubK' k (IV k1, IV k2) b = go (chunkFor' k t) $ B.replicate bSize1 0
+ where
+ bSize1 = fromIntegral $ blockSizeBytes `for` k
+ bSize2 = fromIntegral $ blockSizeBytes `for` k
+ (t,e) = B.splitAt (((B.length b-1)`div` bSize2)*bSize2) b
+ pe = fst $ B.unfoldrN (bSize1) cMacPad (B.unpack e,True,bSize1)
+ fe | bSize2 == B.length e = zwp' k1 pe
+ | otherwise = zwp' k2 pe
+ go [] c = encryptBlock k (zwp' c fe)
+ go (x:xs) c = go xs $ encryptBlock k $ zwp' c x
+
+-- |Obtain the cmac for strict bytestrings
+cMac' :: BlockCipher k => k -> B.ByteString -> B.ByteString
+cMac' k = cMacWithSubK' k (cMacSubk k)
+
+-- |Generate the xor stream for the last step of the CMAC* algorithm
+xorend :: Int -> (Int,[Word8]) -> Maybe (Word8,(Int,[Word8]))
+xorend bsize (0, []) = Nothing
+xorend bsize (n, x:xs) | n <= bsize = Just (x,((n-1),xs))
+ | otherwise = Just (0,((n-1),(x:xs)))
+
+-- |Obtain the CMAC* on lazy bytestrings
+cMacStar :: BlockCipher k => k -> [L.ByteString] -> L.ByteString
+cMacStar k l = go (lcmac (L.replicate bSize 0)) l
+ where
+ bSize = fromIntegral $ blockSizeBytes `for` k
+ bSizeb = fromIntegral $ blockSize `for` k
+ lcmac = cMacWithSubK k (cMacSubk k)
+ go s [] = s
+ go s [x] | (L.length x) >= bSize = lcmac $ zwp x $ L.unfoldr (xorend $
fromIntegral bSize) (fromIntegral $ L.length x,L.unpack s)
+ | otherwise = lcmac $ zwp (dblL s) (L.unfoldr cMacPad
(L.unpack x,True,fromIntegral bSize))
+ go s (x:xs) = go (zwp (dblL s) (lcmac x)) xs
+
+-- |Obtain the CMAC* on strict bytestrings
+cMacStar' :: BlockCipher k => k -> [B.ByteString] -> B.ByteString
+cMacStar' k s = go (lcmac (B.replicate bSize 0)) s
+ where
+ bSize = fromIntegral $ blockSizeBytes `for` k
+ bSizeb = fromIntegral $ blockSize `for` k
+ lcmac = cMacWithSubK' k (cMacSubk k)
+ go s [] = s
+ go s [x] | (B.length x) >= bSize = lcmac $ zwp' x $ fst $ B.unfoldrN
(B.length x) (xorend bSize) (fromIntegral $ B.length x,B.unpack s)
+ | otherwise = lcmac $ zwp' (dblB s) (fst $ B.unfoldrN bSize
cMacPad (B.unpack x,True,bSize))
+ go s (x:xs) = go (zwp' (dblB s) (lcmac x)) xs
+
+-- |Create the mask for SIV based ciphers
+sivMask :: B.ByteString -> B.ByteString
+sivMask b = snd $ B.mapAccumR (go) 0 b
+ where go :: Int -> Word8 -> (Int,Word8)
+ go 24 w = (32,clearBit w 7)
+ go 56 w = (64,clearBit w 7)
+ go n w = (n+8,w)
+
+-- |SIV (Synthetic IV) mode for lazy bytestrings
+-- |First argument is the optional list of bytestrings to be authenticated
+-- | but not encrypted
+-- |As required by the specification this algorithm may return nothing when
+-- | certain constraints aren't met.
+siv :: BlockCipher k => k -> k -> [L.ByteString] -> L.ByteString -> Maybe
L.ByteString
+siv k1 k2 xs m | length xs > bSizeb - 1 = Nothing
+ | otherwise = Just $ L.append iv $ fst $ ctr incIV k2 (IV $
sivMask $ B.concat $ L.toChunks iv) m
+ where
+ bSize = fromIntegral $ blockSizeBytes `for` k1
+ bSizeb = fromIntegral $ blockSize `for` k1
+ iv = cMacStar k1 $ xs ++ [m]
+
+
+-- |SIV (Synthetic IV) for lazy bytestrings
+-- |First argument is the optional list of bytestrings to be authenticated
+-- | but not encrypted
+-- |As required by the specification this algorithm may return nothing when
+-- | authentication fails
+unSiv :: BlockCipher k => k -> k -> [L.ByteString] -> L.ByteString -> Maybe
L.ByteString
+unSiv k1 k2 xs c | length xs > bSizeb - 1 = Nothing
+ | L.length c < fromIntegral bSize = Nothing
+ | iv /= (cMacStar k1 $ xs ++ [dm]) = Nothing
+ | otherwise = Just dm
+ where
+ bSize = fromIntegral $ blockSizeBytes `for` k1
+ bSizeb = fromIntegral $ blockSize `for` k1
+ (iv,m) = L.splitAt (fromIntegral bSize) c
+ dm = fst $ unCtr incIV k2 (IV $ sivMask $ B.concat $ L.toChunks iv) m
+
+-- |SIV (Synthetic IV) mode for strict bytestrings
+-- |First argument is the optional list of bytestrings to be authenticated
+-- | but not encrypted
+-- |As required by the specification this algorithm may return nothing when
+-- | certain constraints aren't met.
+siv' :: BlockCipher k => k -> k -> [B.ByteString] -> B.ByteString -> Maybe
B.ByteString
+siv' k1 k2 xs m | length xs > bSizeb - 1 = Nothing
+ | otherwise = Just $ B.append iv $ fst $ ctr' incIV k2 (IV $
sivMask iv) m
+ where
+ bSize = fromIntegral $ blockSizeBytes `for` k1
+ bSizeb = fromIntegral $ blockSize `for` k1
+ iv = cMacStar' k1 $ xs ++ [m]
+
+
+-- |SIV (Synthetic IV) for strict bytestrings
+-- |First argument is the optional list of bytestrings to be authenticated
+-- | but not encrypted
+-- |As required by the specification this algorithm may return nothing when
+-- | authentication fails
+unSiv' :: BlockCipher k => k -> k -> [B.ByteString] -> B.ByteString -> Maybe
B.ByteString
+unSiv' k1 k2 xs c | length xs > bSizeb - 1 = Nothing
+ | B.length c < bSize = Nothing
+ | iv /= (cMacStar' k1 $ xs ++ [dm]) = Nothing
+ | otherwise = Just dm
+ where
+ bSize = fromIntegral $ blockSizeBytes `for` k1
+ bSizeb = fromIntegral $ blockSize `for` k1
+ (iv,m) = B.splitAt bSize c
+ dm = fst $ unCtr' incIV k2 (IV $ sivMask iv) m
+
+-- |Increase an `IV` by one
+-- |This is way faster than decoding, increasing, encoding
+incIV :: BlockCipher k => IV k -> IV k
+incIV (IV b) = IV $ snd $ B.mapAccumR (incw) True b
+ where incw :: Bool -> Word8 -> (Bool, Word8)
+ incw True w = (w == maxBound, w + 1)
+ incw False w = (False, w)
+
+-- |Accumulator based double operation
+dblw :: Bool -> (Int,[Int],Bool) -> Word8 -> ((Int,[Int],Bool), Word8)
+dblw hb (i,xs,b) w = dblw' hb
+ where slw True w = (setBit (shift w 1) 0)
+ slw False w = (clearBit (shift w 1) 0)
+ cpolyw i [] w = ((i+8,[]),w)
+ cpolyw i (x:xs) w
+ | x < i +8 = (\(a,b) -> (a,complementBit b (x-i))) $ cpolyw i xs w
+ |otherwise = ((i+8,(x:xs)),w)
+ b' = testBit w 7
+ w' = slw b w
+ ((i',xs'),w'') = cpolyw i xs w'
+ dblw' False = i'`seq`xs'`seq`w''`seq`((i,xs,b'),w')
+ dblw' True = ((i',xs',b'),w'')
+
+
+-- |Perform doubling as defined by the CMAC and SIV papers
+dblIV :: BlockCipher k => IV k -> IV k
+dblIV (IV b) = IV $ dblB b
+
+-- |Perform doubling as defined by the CMAC and SIV papers
+dblB :: B.ByteString -> B.ByteString
+dblB b | B.null b = b
+ | otherwise = snd $ B.mapAccumR (dblw (testBit (B.head b) 7))
(0,cpoly2revlist (B.length b * 8),False) b
+
+-- |Perform doubling as defined by the CMAC and SIV papers
+dblL :: L.ByteString -> L.ByteString
+dblL b | L.null b = b
+ | otherwise = snd $ L.mapAccumR (dblw (testBit (L.head b) 7))
(0,cpoly2revlist (L.length b * 8),False) b
+
+-- |Cast a bigEndian ByteString into an Integer
+decodeB :: B.ByteString -> Integer
+decodeB = B.foldl' (\acc w -> (shift acc 8) + toInteger(w)) 0
+
+-- |Cast an Integer into a bigEndian ByteString of size k
+-- |It will drop the MSBs in case the number is bigger than k and add 00s if it
+-- |is smaller
+encodeB :: (Ord a,Num a) => a -> Integer -> B.ByteString
+encodeB k n = B.pack $ if lr > k then takel (lr - k) r else pad (k - lr) r
+ where go 0 xs = xs
+ go n xs = go (shift n (-8)) (fromInteger (n .&. 255) : xs)
+ pad 0 xs = xs
+ pad n xs = 0 : pad (n-1) xs
+ takel 0 xs = xs
+ takel n (_:xs) = takel (n-1) xs
+ r = go n []
+ lr = genericLength r
+
+-- |Cast a bigEndian ByteString into an Integer
+decodeL :: L.ByteString -> Integer
+decodeL = L.foldl' (\acc w -> (shift acc 8) + toInteger(w)) 0
+
+-- |Cast an Integer into a bigEndian ByteString of size k
+-- |It will drop the MSBs in case the number is bigger than k and add 00s if it
+-- |is smaller
+encodeL :: (Ord a,Num a) => a -> Integer -> L.ByteString
+encodeL k n = L.pack $ if lr > k then takel (lr - k) r else pad (k - lr) r
+ where go 0 xs = xs
+ go n xs = go (shift n (-8)) (fromInteger (n .&. 255) : xs)
+ pad 0 xs = xs
+ pad n xs = 0 : pad (n-1) xs
+ takel 0 xs = xs
+ takel n (_:xs) = takel (n-1) xs
+ r = go n []
+ lr = genericLength r
+
unfoldK :: (b -> Maybe (a,b)) -> b -> ([a],b)
unfoldK f i =
case (f i) of
@@ -269,6 +521,13 @@
let (as, iF) = unfoldK f i'
in (a:as, iF)
+
+-- |Obtain an `IV` made only of zeroes
+zeroIV :: (BlockCipher k) => IV k
+zeroIV = iv
+ where bytes = ivBlockSizeBytes iv
+ iv = IV $ B.replicate bytes 0
+
-- |Obtain an `IV` using the provided CryptoRandomGenerator.
getIV :: (BlockCipher k, CryptoRandomGen g) => g -> Either GenError (IV k, g)
getIV g =
Sólo en crypto-api-0.5.2.new/Crypto: Poly.hs
import Crypto.Cipher.AES import Codec.Binary.Base16 import Data.Maybe import Data.Char let (k) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "2b7e151628aed2a6abf7158809cf4f3c" let (iv) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" let (Just ptext) = Codec.Binary.Base16.decode $ map toUpper $ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" let (Just ctext) = Codec.Binary.Base16.decode $ map toUpper $ "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee" let lastIV = IV $ B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "f0f1f2f3f4f5f6f7f8f9fafbfcfdff03" let (Just c) = buildKey k::Maybe AES128 (ctr incIV c (IV iv) $ L.pack ptext) == (L.pack ctext,lastIV) (ctr' incIV c (IV iv) $ B.pack ptext) == (B.pack ctext,lastIV) let (Just ptext) = Codec.Binary.Base16.decode $ map toUpper $ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c37" let (Just ctext) = Codec.Binary.Base16.decode $ map toUpper $ "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009c" (ctr incIV c (IV iv) $ L.pack ptext) == (L.pack ctext,lastIV) (ctr' incIV c (IV iv) $ B.pack ptext) == (B.pack ctext,lastIV) let (k1) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "fbeed618357133667c85e08f7236a8de" let (k2) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "f7ddac306ae266ccf90bc11ee46d513b" ( cMacSubk c) == (IV k1, IV k2) let (ehash) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "bb1d6929e95937287fa37d129b756746" let m1 = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "6bc1bee22e409f96e93d7e117393172a" let m1hash = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "070a16b46b4d4144f79bdd9dd04a287c" let m2 = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411" let m2hash = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "dfa66747de9ae63030ca32611497c827" let m3 = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710" let m3hash = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "51f0bebf7e3b9d92fc49741779363cfe" (cMac' c B.empty) == ehash (cMac' c m1) == m1hash (cMac' c m2) == m2hash (cMac' c m3) == m3hash let (ka) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0" let (kb) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" let (Just c1) = buildKey ka::Maybe AES128 let (Just c2) = buildKey kb::Maybe AES128 let ad = map (\x->B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper x) ["101112131415161718191a1b1c1d1e1f2021222324252627"] let pt = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "112233445566778899aabbccddee" let res = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "85632d07c6e8f37f950acd320a2ecc9340c02b9690c4dc04daef7f6afe5c" siv' c1 c2 ad pt == Just res unSiv' c1 c2 ad (fromJust $ siv' c1 c2 ad pt) == Just pt let (ka) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "7f7e7d7c7b7a79787776757473727170" let (kb) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "404142434445464748494a4b4c4d4e4f" let (Just c1) = buildKey ka::Maybe AES128 let (Just c2) = buildKey kb::Maybe AES128 let ad = map (\x->B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper x) ["00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa99887766554433221100","102030405060708090a0","09f911029d74e35bd84156c5635688c0"] let pt = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "7468697320697320736f6d6520706c61696e7465787420746f20656e6372797074207573696e67205349562d414553" let res = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "7bdb6e3b432667eb06f4d14bff2fbd0fcb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829ea64ad544a272e9c485b62a3fd5c0d" siv' c1 c2 ad pt == Just res unSiv' c1 c2 ad (fromJust $ siv' c1 c2 ad pt) == Just pt let (ka) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0" let (kb) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" let (Just c1) = buildKey ka::Maybe AES128 let (Just c2) = buildKey kb::Maybe AES128 let ad = map (\x->L.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper x) ["101112131415161718191a1b1c1d1e1f2021222324252627"] let pt = L.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "112233445566778899aabbccddee" let res = L.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "85632d07c6e8f37f950acd320a2ecc9340c02b9690c4dc04daef7f6afe5c" siv c1 c2 ad pt == Just res unSiv c1 c2 ad (fromJust $ siv c1 c2 ad pt) == Just pt let (ka) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "7f7e7d7c7b7a79787776757473727170" let (kb) = B.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper $ "404142434445464748494a4b4c4d4e4f" let (Just c1) = buildKey ka::Maybe AES128 let (Just c2) = buildKey kb::Maybe AES128 let ad = map (\x->L.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper x) ["00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa99887766554433221100","102030405060708090a0","09f911029d74e35bd84156c5635688c0"] let pt = L.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "7468697320697320736f6d6520706c61696e7465787420746f20656e6372797074207573696e67205349562d414553" let res = L.pack $ fromJust $ Codec.Binary.Base16.decode $ map toUpper "7bdb6e3b432667eb06f4d14bff2fbd0fcb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829ea64ad544a272e9c485b62a3fd5c0d" siv c1 c2 ad pt == Just res unSiv c1 c2 ad (fromJust $ siv c1 c2 ad pt) == Just pt
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
