threefish (empty) → 0.1
raw patch · 14 files changed
+948/−0 lines, 14 filesdep +arraydep +basedep +bytestringsetup-changed
Dependencies added: array, base, bytestring, cereal, crypto-api, data-default, entropy, random, tagged
Files
- Crypto/Threefish.hs +31/−0
- Crypto/Threefish/Common.hs +73/−0
- Crypto/Threefish/Mix.hs +32/−0
- Crypto/Threefish/Random.hs +71/−0
- Crypto/Threefish/Skein.hs +142/−0
- Crypto/Threefish/Threefish256.hs +91/−0
- Crypto/Threefish/Threefish512.hs +153/−0
- Crypto/Threefish/UBI.hs +52/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- cbits/skein256.c +105/−0
- cbits/threefish256.c +82/−0
- cbits/ubi.c +37/−0
- threefish.cabal +47/−0
+ Crypto/Threefish.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}+-- | 256 and 512 bit variants of the Threefish block cipher used as the+-- foundation of the Skein hash function.+module Crypto.Threefish ( + Block256 (..), Threefish256, Key256,+ Block512 (..), Threefish512, Key512,+ Tweak (..), parseHex, readHex, defaultTweak,+ Threefish (..)+) where+import Crypto.Threefish.Threefish256 as TF256+import Crypto.Threefish.Threefish512 as TF512+import Crypto.Threefish.Common as Common+import Data.Serialize++class Serialize a => Threefish a b | a -> b where+ -- | Create a Threefish key using a custom tweak value.+ threefishKey :: Tweak -> a -> b+ -- | Encrypt a block using the given key and tweak value.+ threefishEncrypt :: a -> Tweak -> a -> a+ -- | Decrypt a block using the given key and tweak value.+ threefishDecrypt :: a -> Tweak -> a -> a++instance Threefish Block256 Threefish256 where+ threefishKey = Threefish256+ threefishEncrypt = encrypt256+ threefishDecrypt = decrypt256++instance Threefish Block512 Threefish512 where+ threefishKey = Threefish512+ threefishEncrypt = encrypt512+ threefishDecrypt = decrypt512
+ Crypto/Threefish/Common.hs view
@@ -0,0 +1,73 @@+-- | Misc. shared constants and functions.+module Crypto.Threefish.Common (+ Tweak (..), showBytes, keyConst, e2m, defaultTweak, parseHex, readHex+ ) where+import Numeric (showHex)+import Data.Word+import Data.Bits+import Data.Serialize+import Control.Applicative+import qualified Data.ByteString as BS+import Data.Char+import Data.Default++hexDigit :: Char -> Maybe Word8+hexDigit c | c >= '0' && c <= '9' = Just $ fromIntegral $ ord c - ord '0'+ | c >= 'a' && c <= 'f' = Just $ fromIntegral $ ord c - ord 'a' + 10+ | c >= 'A' && c <= 'F' = Just $ fromIntegral $ ord c - ord 'A' + 10+ | otherwise = Nothing++-- | Parses a string of hexadecimal digits into a ByteString.+parseHex :: String -> Maybe BS.ByteString+parseHex = go []+ where+ go :: [Word8] -> String -> Maybe BS.ByteString+ go bytes (h:l:xs) = do+ h' <- hexDigit h+ l' <- hexDigit l+ go (((h' `shiftL` 4) .|. l') : bytes) xs+ go bytes [] =+ Just (BS.pack (reverse bytes))+ go _ _ =+ Nothing++-- | Show a little endian Word64 as a string of bytes.+showBytes :: Word64 -> String+showBytes =+ go (8 :: Int)+ where+ sr = shiftR+ go 0 _ = ""+ go n w = showHex ((w`sr`4).&.15) $ showHex (w.&.15) $ go (n-1) (w`sr`8)++-- | Key constant for Threefish.+keyConst :: Word64+keyConst = 0x1BD11BDAA9FC1A22++-- | Default tweak when Threefish is used in CBC, CTR, etc. modes.+defaultTweak :: Tweak+defaultTweak = Tweak 0 0++-- | Turn an Either computation into its Maybe counterpart.+e2m :: Either a b -> Maybe b+e2m (Right x) = Just x+e2m _ = Nothing++-- | Threefish tweak value. Please see the Skein specification for info on+-- how to use this.+data Tweak = Tweak {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64++instance Serialize Tweak where+ put (Tweak low high) = putWord64le low >> putWord64le high+ get = Tweak <$> getWord64le <*> getWord64le++instance Show Tweak where+ show (Tweak low high) = showBytes low ++ showBytes high++instance Default Tweak where+ def = defaultTweak++-- | Read any deserializable type from a hex string.+readHex :: Serialize a => String -> Maybe a+readHex s = parseHex s >>= e2m . decode
+ Crypto/Threefish/Mix.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE BangPatterns #-}+module Crypto.Threefish.Mix where+import Data.Word+import Data.Bits++{-# INLINE mix #-}+mix :: Word64 -> Word64 -> Int -> (Word64, Word64)+mix !a !b !r =+ case a + b of+ a' -> (a', rotateL b r `xor` a')++{-# INLINE mixKey #-}+mixKey :: Word64 -> Word64 -> Int -> Word64 -> Word64 -> (Word64, Word64)+mixKey !a !b !r !k0 !k1 =+ (a', rotateL b' r `xor` a')+ where+ !b' = b + k1+ !a' = a + b' + k0++{-# INLINE unmix #-}+unmix :: Word64 -> Word64 -> Int -> (Word64, Word64)+unmix !a !b !r =+ case rotateR (b `xor` a) r of+ b' -> (a - b', b')++{-# INLINE unmixKey #-}+unmixKey :: Word64 -> Word64 -> Int -> Word64 -> Word64 -> (Word64, Word64)+unmixKey !a !b !r !k0 !k1 =+ (a', b' - k1)+ where+ !b' = rotateR (b `xor` a) r+ !a' = a - (b' + k0)
+ Crypto/Threefish/Random.hs view
@@ -0,0 +1,71 @@+-- | Skein 256 as a PRNG.+module Crypto.Threefish.Random (+ SkeinGen, Block256 (..), Random (..), RandomGen (..),+ newSkeinGen, mkSkeinGen, mkSkeinGenEx, randomBytes+ ) where+import Crypto.Threefish.Skein+import System.Random+import System.Entropy+import qualified Data.ByteString as BS+import Data.ByteString.Unsafe+import System.IO.Unsafe+import Foreign.Storable (sizeOf, peek)+import Foreign.Ptr (castPtr)+import Data.Serialize++emptyKey :: Key256+emptyKey = Block256 BS.empty++-- | Default amount of random bytes to buffer.+defaultSkeinGenPoolSize :: Int+defaultSkeinGenPoolSize = 256++-- | Skein-based PRNG as defined in the Skein 1.3 paper.+data SkeinGen = SkeinGen {+ sgState :: Block256,+ sgPool :: BS.ByteString,+ sgPoolSize :: Int+ }++instance RandomGen SkeinGen where+ next g =+ case randomBytes (sizeOf (0::Int)) g of+ (bs, g') -> (unsafePerformIO $ unsafeUseAsCString bs $ peek . castPtr, g')+ split g =+ case BS.splitAt 32 (fst $ randomBytes 64 g) of+ (a, b) -> (mkSkeinGenEx (sgPoolSize g) (Block256 a),+ mkSkeinGenEx (sgPoolSize g) (Block256 b))++-- | Create a new Skein PRNG from the system's entropy pool.+newSkeinGen :: IO SkeinGen+newSkeinGen =+ (mkSkeinGenEx defaultSkeinGenPoolSize . Block256) `fmap` getEntropy 32++-- | Create a Skein PRNG from a seed.+mkSkeinGen :: Serialize a => a -> SkeinGen+mkSkeinGen = mkSkeinGenEx defaultSkeinGenPoolSize . Block256 . encode++-- | Create a Skein PRNG with a custom pool size. Larger pool sizes give faster+-- random data, but obviously take up more memory. Pool size is preserved+-- across splits.+mkSkeinGenEx :: Int -> Block256 -> SkeinGen+mkSkeinGenEx poolsize (Block256 seed) = SkeinGen {+ sgState = skein (BS.replicate 32 0 `BS.append` seed),+ sgPool = BS.empty,+ sgPoolSize = poolsize+ }++-- | Generate n random bytes using the given generator.+randomBytes :: Int -> SkeinGen -> (BS.ByteString, SkeinGen)+randomBytes nbytes (SkeinGen (Block256 state) pool poolsize)+ | BS.length pool >= nbytes =+ case BS.splitAt nbytes pool of+ (output, rest) -> (output, SkeinGen (Block256 state) rest poolsize)+ | otherwise =+ (BS.append pool out, SkeinGen (Block256 state') pool' poolsize)+ where+ -- Use all of the output to avoid making unnecessary calls+ nbytes' = 32 + max (nbytes + (32-(nbytes`rem`32))) poolsize+ bytes = hash256 nbytes' emptyKey emptyKey state+ (state', buffer) = BS.splitAt 32 bytes+ (out, pool') = BS.splitAt (nbytes - BS.length pool) buffer
+ Crypto/Threefish/Skein.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE BangPatterns, OverloadedStrings, ForeignFunctionInterface #-}+-- | 256 and 512 bit Skein. Supports "normal" hashing and Skein-MAC.+module Crypto.Threefish.Skein (+ Skein (..), Block256 (..), Block512 (..), Key256, Key512, Nonce256,+ hash256, hash512+ ) where+import qualified Data.ByteString as BS+import Crypto.Threefish.Threefish256+import Crypto.Threefish.Threefish512+import Crypto.Threefish.UBI+import Data.Bits+import Data.Serialize+import Data.Word+import Data.ByteString.Unsafe+import Foreign.Ptr+import Foreign.ForeignPtr+import System.IO.Unsafe++foreign import ccall "hash256" c_hash256 :: Ptr Word64 -- ^ Key (nullPtr for none)+ -> Ptr Word64 -- ^ Nonce (nullPtr for none)+ -> Word64 -- ^ Message length+ -> Ptr Word64 -- ^ Message+ -> Int -- ^ Size of output, in bytes+ -> Ptr Word64 -- ^ Output blocks pointer+ -> IO ()++class Skein a where+ -- | Calculate the Skein-MAC of a message.+ skeinMAC :: a -> BS.ByteString -> a+ -- | Calculate the Skein checksum of a message.+ skein :: BS.ByteString -> a++type Nonce256 = Block256++-- | Hash a message using a particular key. For normal hashing, use an empty+-- ByteString; for Skein-MAC, use the MAC key.+hash256 :: Int -> Key256 -> Nonce256 -> BS.ByteString -> BS.ByteString+hash256 outlen (Block256 key) (Block256 nonce) !msg =+ unsafePerformIO $+ withKey $ \k -> do+ withNonce $ \n -> do+ unsafeUseAsCString msg $ \b -> do+ out <- mallocForeignPtrArray (outblocks*32)+ withForeignPtr out $ \out' -> do+ c_hash256 k n len (castPtr b) outlen out'+ BS.packCStringLen (castPtr out', outlen)+ where+ outblocks =+ case outlen `quotRem` 32 of+ (blocks, 0) -> blocks+ (blocks, _) -> blocks+1+ !len = fromIntegral $ BS.length msg+ withKey f | BS.length key == 32 = unsafeUseAsCString key (f . castPtr)+ | otherwise = f nullPtr+ withNonce f | BS.length nonce == 32 = unsafeUseAsCString nonce (f . castPtr)+ | otherwise = f nullPtr++{-# INLINE skein256 #-}+-- | Hash a message using 256 bit Skein.+skein256 :: BS.ByteString -> Block256+skein256 = Block256 . hash256 32 (Block256 "") (Block256 "")++{-# INLINE skeinMAC256 #-}+-- | Create a 256 bit Skein-MAC.+skeinMAC256 :: Key256 -> BS.ByteString -> Block256+skeinMAC256 key = Block256 . hash256 32 key (Block256 "")++instance Skein Block256 where+ skeinMAC = skeinMAC256+ skein = skein256++++---------------------+-- 512 bit version --+---------------------++config512 :: Block512+config512 = Block512 0x0000000133414853 512 0 0 0 0 0 0++{-# INLINE xb512 #-}+xb512 :: Block512 -> Block512 -> Block512+xb512 (Block512 x1 x2 x3 x4 x5 x6 x7 x8)+ (Block512 y1 y2 y3 y4 y5 y6 y7 y8) =+ Block512 (x1 `xor` y1) (x2 `xor` y2) (x3 `xor` y3) (x4 `xor` y4)+ (x5 `xor` y5) (x6 `xor` y6) (x7 `xor` y7) (x8 `xor` y8)++-- | Initial state for Skein512+init512 :: Key512 -> Block512+init512 key = fst $ processBlock512 32 key configTweak config512++zero512 :: Block512+zero512 = Block512 0 0 0 0 0 0 0 0++{-# INLINE processBlock512 #-}+-- | Process a single block of Skein 512. Call on Threefish, XOR the cryptotext+-- with the plaintext and update the tweak.+processBlock512 :: Word64 -> Key512 -> Tweak -> Block512 -> (Key512, Tweak)+processBlock512 !len !key !tweak !block =+ (encrypt512 key tweak' block `xb512` block, setFirst False tweak')+ where+ !tweak' = addBytes len tweak++-- | Hash a message using a particular key. For normal hashing, use all zeroes;+-- for Skein-MAC, use the MAC key.+hash512 :: Key512 -> BS.ByteString -> Block512+hash512 !firstkey !bs =+ case flip runGet bs' $ go len (init512 firstkey) (newTweak Message) of+ Right x -> x+ Left _ -> error "hash512 failed to get output bytes - impossible!"+ where+ !len = BS.length bs+ !lastLen = case len `rem` 64 of 0 -> 64 ; n -> n+ !lastLenW64 = fromIntegral lastLen+ !bs' = BS.append bs (BS.replicate (64-lastLen) 0)+ go !n !key !tweak+ | n > 64 = do+ block <- get+ let (block', tweak') = processBlock512 64 key tweak block+ go (n-64) block' tweak'+ | otherwise = do+ block <- get+ let tweak' = setLast True tweak+ (block', _) = processBlock512 lastLenW64 key tweak' block+ finalTweak = setLast True $ newTweak Output+ (b,_) = processBlock512 8 block' finalTweak zero512+ return b++{-# INLINE skein512 #-}+-- | Hash a message using 512 bit Skein.+skein512 :: BS.ByteString -> Block512+skein512 = hash512 zero512++{-# INLINE skeinMAC512 #-}+-- | Create a 512 bit Skein-MAC.+skeinMAC512 :: Key512 -> BS.ByteString -> Block512+skeinMAC512 =+ hash512 . fst . processBlock512 64 zero512 (setLast True $ newTweak Key)++instance Skein Block512 where+ skeinMAC = skeinMAC512+ skein = skein512
+ Crypto/Threefish/Threefish256.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE BangPatterns, ForeignFunctionInterface #-}+-- | 256 bit Threefish.+module Crypto.Threefish.Threefish256 (+ Block256 (..), Key256, Threefish256 (..),+ encrypt256, decrypt256, readBlock256, Tweak (..)+ ) where+import Data.Word+import Crypto.Threefish.Common+import Data.Serialize+import Control.Applicative+import Crypto.Classes+import Data.Tagged+import qualified Data.ByteString as BS+import Data.ByteString.Unsafe+import Foreign.Storable+import Foreign.Ptr+import Foreign.ForeignPtr+import System.IO.Unsafe++foreign import ccall "encrypt256" c_encrypt256 :: Ptr Word64+ -> Word64+ -> Word64+ -> Ptr Word64+ -> Ptr Word64+ -> IO ()++foreign import ccall "decrypt256" c_decrypt256 :: Ptr Word64+ -> Word64+ -> Word64+ -> Ptr Word64+ -> Ptr Word64+ -> IO ()++newtype Block256 = Block256 BS.ByteString deriving Eq+type Key256 = Block256++instance Show Block256 where+ show (Block256 bs) =+ case readBlock256 bs 0 of+ (a, b, c, d) -> showBytes a ++ showBytes b ++ showBytes c ++ showBytes d++instance Serialize Block256 where+ put (Block256 bs) = putByteString bs+ get = Block256 <$> getBytes 32++instance Serialize Threefish256 where+ put (Threefish256 tweak key) = put tweak >> put key+ get = Threefish256 <$> get <*> get++-- | 256 bit Threefish block cipher.+data Threefish256 = Threefish256 !Tweak !Key256++{-# INLINE readBlock256 #-}+readBlock256 :: BS.ByteString -> Int -> (Word64, Word64, Word64, Word64)+readBlock256 bs off = unsafePerformIO . unsafeUseAsCString bs $ \ptr -> do+ a <- peekElemOff (castPtr ptr) off+ b <- peekElemOff (castPtr ptr) (off+1)+ c <- peekElemOff (castPtr ptr) (off+2)+ d <- peekElemOff (castPtr ptr) (off+3)+ return $! (a, b, c, d)++instance BlockCipher Threefish256 where+ blockSize = Tagged 256+ keyLength = Tagged 256+ encryptBlock (Threefish256 tweak key) block =+ case encrypt256 key tweak (Block256 block) of+ Block256 out -> out+ decryptBlock (Threefish256 tweak key) block =+ case decrypt256 key tweak (Block256 block) of+ Block256 out -> out+ buildKey bs | BS.length bs /= 32 = Nothing+ | otherwise = Just (Threefish256 defaultTweak+ (Block256 bs))++decrypt256 :: Key256 -> Tweak -> Block256 -> Block256+decrypt256 (Block256 key) (Tweak t0 t1) (Block256 block) =+ unsafePerformIO $ unsafeUseAsCString key $ \k ->+ unsafeUseAsCString block $ \b -> do+ out <- mallocForeignPtrArray 4+ withForeignPtr out $ \out' -> do+ c_decrypt256 (castPtr k) t0 t1 (castPtr b) out'+ Block256 <$> BS.packCStringLen (castPtr out', 32)++encrypt256 :: Key256 -> Tweak -> Block256 -> Block256+encrypt256 (Block256 key) (Tweak t0 t1) (Block256 block) =+ unsafePerformIO $ unsafeUseAsCString key $ \k ->+ unsafeUseAsCString block $ \b -> do+ out <- mallocForeignPtrArray 4+ withForeignPtr out $ \out' -> do+ c_encrypt256 (castPtr k) t0 t1 (castPtr b) out'+ Block256 <$> BS.packCStringLen (castPtr out', 32)
+ Crypto/Threefish/Threefish512.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE BangPatterns #-}+-- | 512 bit Threefish.+module Crypto.Threefish.Threefish512 where+import Data.Word+import Data.Bits+import Crypto.Threefish.Mix+import Crypto.Threefish.Common+import Data.Array.Unboxed+import Data.Serialize+import Control.Applicative+import Crypto.Classes+import Data.Tagged+import qualified Data.ByteString as BS+import Data.List (foldl1')++-- | 512 bit Threefish block cipher.+data Threefish512 = Threefish512 !Tweak !Key512++data Block512 = Block512 {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ {-# UNPACK #-} !Word64+ deriving Eq++type Key512 = Block512++instance Show Block512 where+ show (Block512 a b c d e f g h) =+ showBytes a ++ showBytes b ++ showBytes c ++ showBytes d +++ showBytes e ++ showBytes f ++ showBytes g ++ showBytes h++instance Serialize Block512 where+ put (Block512 a b c d e f g h) = do+ putWord64le a >> putWord64le b >> putWord64le c >> putWord64le d+ putWord64le e >> putWord64le f >> putWord64le g >> putWord64le h+ get =+ Block512 <$> getWord64le <*> getWord64le <*> getWord64le <*> getWord64le+ <*> getWord64le <*> getWord64le <*> getWord64le <*> getWord64le++instance Serialize Threefish512 where+ put (Threefish512 tweak key) = put tweak >> put key+ get = Threefish512 <$> get <*> get++-- | Rotational constants for TF512+rot :: UArray Word64 Int+rot = listArray (0,32) [46,36,19,37,33,27,14,42,17,49,36,39,44,9,54,56,+ 39,30,34,24,13,50,10,17,25,29,39,43,8,35,56,22]++-- | Encrypt a 512 bit Threefish block. Tweak may have any value without+-- compromising security.+{-# INLINE encrypt512 #-}+encrypt512 :: Key512 -> Tweak -> Block512 -> Block512+encrypt512 (Block512 k0 k1 k2 k3 k4 k5 k6 k7) (Tweak t0 t1) !blockin =+ case rounds 0 blockin of+ Block512 a b c d e f g h ->+ Block512 (a+k0) (b+k1) (c+k2) (d+k3)+ (e+k4) (f+k5+t0) (g+k6+t1) (h+k7+18)+ where+ k8 = foldl1' xor [k0,k1,k2,k3,k4,k5,k6,k7,keyConst]+ ks :: UArray Word64 Word64+ !ks = listArray (0, 8) [k0, k1, k2, k3, k4, k5, k6, k7, k8]+ ts :: UArray Word64 Word64+ !ts = listArray (0, 2) [t0, t1, t0 `xor` t1]+ + rounds 18 input = input+ rounds !n !input = rounds (n+1) (fourRounds input n (n*16))+ + {-# INLINE fourRounds #-}+ fourRounds (Block512 a0 b0 c0 d0 e0 f0 g0 h0) keyOff r =+ Block512 a4 b4 c4 d4 e4 f4 g4 h4+ where+ {-# INLINE key #-}+ key n = ks ! ((keyOff + n) `rem` 9)+ {-# INLINE t #-}+ t n = ts ! ((keyOff + n) `rem` 3)+ (a1, b1) = mixKey a0 b0 (rot ! (r .&. 31)) (key 0) (key 1)+ (c1, d1) = mixKey c0 d0 (rot ! ((r+1) .&. 31)) (key 2) (key 3)+ (e1, f1) = mixKey e0 f0 (rot ! ((r+2) .&. 31)) (key 4) (key 5 + t 0)+ (g1, h1) = mixKey g0 h0 (rot ! ((r+3) .&. 31)) (key 6 + t 1) (key 7+keyOff)+ (c2, b2) = mix c1 b1 (rot ! ((r+4) .&. 31))+ (e2, h2) = mix e1 h1 (rot ! ((r+5) .&. 31))+ (g2, f2) = mix g1 f1 (rot ! ((r+6) .&. 31))+ (a2, d2) = mix a1 d1 (rot ! ((r+7) .&. 31))+ (e3, b3) = mix e2 b2 (rot ! ((r+8) .&. 31))+ (g3, d3) = mix g2 d2 (rot ! ((r+9) .&. 31))+ (a3, f3) = mix a2 f2 (rot ! ((r+10) .&. 31))+ (c3, h3) = mix c2 h2 (rot ! ((r+11) .&. 31))+ (g4, b4) = mix g3 b3 (rot ! ((r+12) .&. 31))+ (a4, h4) = mix a3 h3 (rot ! ((r+13) .&. 31))+ (c4, f4) = mix c3 f3 (rot ! ((r+14) .&. 31))+ (e4, d4) = mix e3 d3 (rot ! ((r+15) .&. 31))++-- | Encrypt a 512 bit Threefish block.+{-# INLINE decrypt512 #-}+decrypt512 :: Key512 -> Tweak -> Block512 -> Block512+decrypt512 (Block512 k0 k1 k2 k3 k4 k5 k6 k7) (Tweak t0 t1) !blockin =+ case blockin of+ (Block512 a b c d e f g h) ->+ rounds 18 $ Block512 (a-k0) (b-k1) (c-k2) (d-k3)+ (e-k4) (f-(k5+t0)) (g-(k6+t1)) (h-(k7+18))+ where+ ks :: UArray Word64 Word64+ !ks = listArray (0, 8) [k0, k1, k2, k3, k4, k5, k6, k7, keyConst]+ ts :: UArray Word64 Word64+ !ts = listArray (0, 2) [t0, t1, t0 `xor` t1]+ + rounds 0 input = input+ rounds !n !input = rounds (n-1) (fourRounds input (n-1) ((n-1)*16))+ + {-# INLINE fourRounds #-}+ fourRounds (Block512 a0 b0 c0 d0 e0 f0 g0 h0) keyOff r =+ Block512 a4 b4 c4 d4 e4 f4 g4 h4+ where+ {-# INLINE key #-}+ key n = ks ! ((keyOff + n) `rem` 9)+ {-# INLINE t #-}+ t n = ts ! ((keyOff + n) `rem` 3)+ (g1, b1) = unmix g0 b0 (rot ! ((r+12) .&. 31))+ (a1, h1) = unmix a0 h0 (rot ! ((r+13) .&. 31))+ (c1, f1) = unmix c0 f0 (rot ! ((r+14) .&. 31))+ (e1, d1) = unmix e0 d0 (rot ! ((r+15) .&. 31))+ (e2, b2) = unmix e1 b1 (rot ! ((r+8) .&. 31))+ (g2, d2) = unmix g1 d1 (rot ! ((r+9) .&. 31))+ (a2, f2) = unmix a1 f1 (rot ! ((r+10) .&. 31))+ (c2, h2) = unmix c1 h1 (rot ! ((r+11) .&. 31))+ (c3, b3) = unmix c2 b2 (rot ! ((r+4) .&. 31))+ (e3, h3) = unmix e2 h2 (rot ! ((r+5) .&. 31))+ (g3, f3) = unmix g2 f2 (rot ! ((r+6) .&. 31))+ (a3, d3) = unmix a2 d2 (rot ! ((r+7) .&. 31))+ (a4, b4) = unmixKey a3 b3 (rot ! (r .&. 31)) (key 0) (key 1)+ (c4, d4) = unmixKey c3 d3 (rot ! ((r+1) .&. 31)) (key 2) (key 3)+ (e4, f4) = unmixKey e3 f3 (rot ! ((r+2) .&. 31)) (key 4) (key 5 + t 0)+ (g4, h4) = unmixKey g3 h3 (rot ! ((r+3) .&. 31)) (key 6 + t 1) (key 7+keyOff)++instance BlockCipher Threefish512 where+ blockSize = Tagged 512+ keyLength = Tagged 512+ encryptBlock (Threefish512 tweak key) block =+ case decode block of+ Right block' -> encode (encrypt512 key tweak block')+ Left e -> error $ "Not a valid Threefish512 block: " ++ show e+ decryptBlock (Threefish512 tweak key) block =+ case decode block of+ Right block' -> encode (decrypt512 key tweak block')+ Left e -> error $ "Not a valid Threefish512 block: " ++ show e+ buildKey bs | BS.length bs /= 64 = Nothing+ | otherwise = e2m $ do+ key <- decode bs+ return $! Threefish512 defaultTweak key
+ Crypto/Threefish/UBI.hs view
@@ -0,0 +1,52 @@+-- | Tweak manipulation for Unique Block Iteration mode.+module Crypto.Threefish.UBI where+import Data.Word+import Data.Bits+import Crypto.Threefish.Common++data BlockType+ = Key+ | Config+ | Personalization+ | PublicKey+ | KeyIdentifier+ | Nonce+ | Message+ | Output++type2w64 :: BlockType -> Word64+type2w64 Key = 0+type2w64 Config = 4+type2w64 Personalization = 8+type2w64 PublicKey = 12+type2w64 KeyIdentifier = 16+type2w64 Nonce = 20+type2w64 Message = 48+type2w64 Output = 63++{-# INLINE newTweak #-}+newTweak :: BlockType -> Tweak+newTweak t = setType t $ setFirst True $ Tweak 0 0++{-# INLINE setType #-}+setType :: BlockType -> Tweak -> Tweak+setType t (Tweak lo hi) =+ Tweak lo ((type2w64 t `shiftL` 56) .|. (hi .&. zeroType))+ where+ zeroType = complement (63 `shiftL` 56)++{-# INLINE setFirst #-}+setFirst :: Bool -> Tweak -> Tweak+setFirst set (Tweak lo hi) = Tweak lo ((if set then setBit else clearBit) hi 62)++{-# INLINE setLast #-}+setLast :: Bool -> Tweak -> Tweak+setLast set (Tweak lo hi) = Tweak lo ((if set then setBit else clearBit) hi 63)++{-# INLINE addBytes #-}+addBytes :: Word64 -> Tweak -> Tweak+addBytes bs (Tweak lo hi) = Tweak (lo + bs) hi++{-# INLINE configTweak #-}+configTweak :: Tweak+configTweak = setFirst True $ setLast True $ newTweak Config
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Anton Ekblad++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Anton Ekblad nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cbits/skein256.c view
@@ -0,0 +1,105 @@+#include "threefish.h"+#include <string.h>++void skein256_init(skein_t* ctx, W64* key, int outlen) {+ W64 config[4] = {0x0000000133414853, outlen*8, 0, 0};+ static W64 zeroes[4] = {0,0,0,0};++ /* Set up key if needed */+ if(key != NULL) {+ init_tweak(T_KEY, ctx->tweak);+ set_last(1, ctx->tweak);+ add_bytes(32, ctx->tweak);+ encrypt256(zeroes, ctx->tweak[0], ctx->tweak[1], key, ctx->key);+ ctx->key[0] ^= key[0];+ ctx->key[1] ^= key[1];+ ctx->key[2] ^= key[2];+ ctx->key[3] ^= key[3];+ } else {+ ctx->key[0] = 0; ctx->key[1] = 0; ctx->key[2] = 0; ctx->key[3] = 0;+ }++ /* Process config string */+ mk_config_tweak(ctx->tweak);+ add_bytes(32, ctx->tweak);+ encrypt256(ctx->key, ctx->tweak[0], ctx->tweak[1], config, ctx->key);+ ctx->key[0] ^= config[0];+ ctx->key[1] ^= config[1];+ ctx->key[2] ^= config[2];+ ctx->key[3] ^= config[3];+}++void skein256_update(skein_t* ctx, int firstlast, UBIType type, W64 len, W64* data) {+ W64 buf[4] = {0,0,0,0};+ W64* k = ctx->key;+ W64* tweak = ctx->tweak;+ int lastlen;++ /* Process message */+ if(firstlast & 1) {+ init_tweak(type, tweak);+ }+ /* If this is not the last update, don't do last block processing */+ if(!(firstlast & 2) && len % 32 == 0) {+ ++len;+ }+ while(len > 32) {+ add_bytes(32, tweak);+ encrypt256(k, tweak[0], tweak[1], data, k);+ set_first(0, tweak);+ k[0] ^= *data; ++data;+ k[1] ^= *data; ++data;+ k[2] ^= *data; ++data;+ k[3] ^= *data; ++data;+ len -= 32;+ }++ /* Process last block */+ if(firstlast & 2) {+ lastlen = len % 32;+ if(lastlen == 0 && len > 0) {+ lastlen = 32;+ }+ add_bytes(lastlen, tweak);+ set_last(1, tweak);+ memcpy(buf, data, lastlen);+ encrypt256(k, tweak[0], tweak[1], buf, k);+ k[0] ^= buf[0];+ k[1] ^= buf[1];+ k[2] ^= buf[2];+ k[3] ^= buf[3];+ }+}++void skein256_output(skein_t* ctx, int from, int to, W64* out) {+ W64 buf[4] = {from,0,0,0};+ W64 *k = ctx->key;+ W64 *tweak = ctx->tweak;+ for(; from <= to; ++from) {+ init_tweak(T_OUT, tweak);+ set_last(1, tweak);+ add_bytes(8, tweak);+ encrypt256(k, tweak[0], tweak[1], buf, out);+ out += 4;+ ++buf[0];+ }+}++void hash256(W64* key, W64* nonce, W64 len, W64* data, int outlen, W64* out) {+ skein_t ctx;++ skein256_init(&ctx, key, outlen);++ /* Process nonce, if available; must be 32 bytes */+ if(nonce != NULL) {+ skein256_update(&ctx, 3, T_NONCE, 32, nonce);+ }++ skein256_update(&ctx, 3, T_MSG, len, data);+ if(outlen % 32 == 0) {+ outlen = outlen / 32;+ } else {+ outlen = (outlen / 32) + 1;+ }+ skein256_output(&ctx, 0, outlen, out);+}
+ cbits/threefish256.c view
@@ -0,0 +1,82 @@+#include "threefish.h"++W64 key_const = 0x1BD11BDAA9FC1A22;++void encrypt256(W64* key, W64 t0, W64 t1, W64* in, W64* out) {+ int r;+ W64 k4 = key[0] ^ key[1] ^ key[2] ^ key[3] ^ key_const;+ W64 ks[5] = {key[0], key[1], key[2], key[3], k4};+ W64 ts[3] = {t0, t1, t0 ^ t1};+ W64 a = in[0] + ks[0];+ W64 b = in[1] + ks[1] + ts[0];+ W64 c = in[2] + ks[2] + ts[1];+ W64 d = in[3] + ks[3];++ for(r = 2; r < 20; r += 2) {+ a += b; b = rl(b, 14) ^ a;+ c += d; d = rl(d, 16) ^ c;+ a += d; d = rl(d, 52) ^ a;+ c += b; b = rl(b, 57) ^ c;+ a += b; b = rl(b, 23) ^ a;+ c += d; d = rl(d, 40) ^ c;+ a += d; d = rl(d, 5) ^ a;+ c += b; b = rl(b, 37) ^ c;+ a += ks[(r-1) % 5];+ b += ks[r % 5] + ts[(r-1) % 3];+ c += ks[(r+1) % 5] + ts[r % 3];+ d += ks[(r+2) % 5] + (r-1);+ a += b; b = rl(b, 25) ^ a;+ c += d; d = rl(d, 33) ^ c;+ a += d; d = rl(d, 46) ^ a;+ c += b; b = rl(b, 12) ^ c;+ a += b; b = rl(b, 58) ^ a;+ c += d; d = rl(d, 22) ^ c;+ a += d; d = rl(d, 32) ^ a;+ c += b; b = rl(b, 32) ^ c;+ a += ks[r % 5];+ b += ks[(r+1) % 5] + ts[r % 3];+ c += ks[(r+2) % 5] + ts[(r+1) % 3];+ d += ks[(r+3) % 5] + r;+ }+ out[0] = a; out[1] = b; out[2] = c; out[3] = d;+}++void decrypt256(W64* key, W64 t0, W64 t1, W64* in, W64* out) {+ int r;+ W64 k4 = key[0] ^ key[1] ^ key[2] ^ key[3] ^ key_const;+ W64 ks[5] = {key[0], key[1], key[2], key[3], k4};+ W64 ts[3] = {t0, t1, t0 ^ t1};+ W64 a = in[0] + ks[0];+ W64 b = in[1] + ks[1] + ts[0];+ W64 c = in[2] + ks[2] + ts[1];+ W64 d = in[3] + ks[3];++ for(r = 18; r >= 2; r -= 2) {+ a -= ks[r % 5];+ b -= ks[(r+1) % 5] + ts[r % 3];+ c -= ks[(r+2) % 5] + ts[(r+1) % 3];+ d -= ks[(r+3) % 5] + r;+ d = rr(d^a, 32); a -= d;+ b = rr(b^c, 32); c -= b;+ b = rr(b^a, 58); a -= b;+ d = rr(d^c, 22); c -= d;+ d = rr(d^a, 46); a -= d;+ b = rr(b^c, 12); c -= b;+ b = rr(b^a, 25); a -= b;+ d = rr(d^c, 33); c -= d;+ a -= ks[(r-1) % 5];+ b -= ks[r % 5] + ts[(r-1) % 3];+ c -= ks[(r+1) % 5] + ts[r % 3];+ d -= ks[(r+2) % 5] + (r-1);+ d = rr(d^a, 5); a -= d;+ b = rr(b^c, 37); c -= b;+ b = rr(b^a, 23); a -= b;+ d = rr(d^c, 40); c -= d;+ d = rr(d^a, 52); a -= d;+ b = rr(b^c, 57); c -= b;+ b = rr(b^a, 14); a -= b;+ d = rr(d^c, 16); c -= d;+ }+ out[0] = a - ks[0]; out[1] = b - (ks[1] + ts[0]);+ out[2] = c - (ks[2] + ts[1]); out[3] = d - ks[3];+}
+ cbits/ubi.c view
@@ -0,0 +1,37 @@+#include "threefish.h"++inline void init_tweak(UBIType type, W64* t) {+ t[0] = 0;+ t[1] = 0;+ set_first(1, t);+ set_type(type, t);+}++inline void mk_config_tweak(W64* t) {+ init_tweak(T_CONFIG, t);+ set_last(1, t);+}++inline void set_type(UBIType type, W64* t) {+ t[1] = (((W64)type) << 56) | (t[1] & ~(((W64)63) << 56));+}++inline void set_first(unsigned char first, W64* t) {+ if(first) {+ t[1] |= (((W64)1) << 62);+ } else {+ t[1] &= ~(((W64)1) << 62);+ }+}++inline void set_last(unsigned char last, W64* t) {+ if(last) {+ t[1] |= (((W64)1) << 63);+ } else {+ t[1] &= ~(((W64)1) << 63);+ }+}++inline void add_bytes(W64 bytes, W64* t) {+ t[0] += bytes;+}
+ threefish.cabal view
@@ -0,0 +1,47 @@+name: threefish+version: 0.1+synopsis: The Threefish block cipher and the Skein hash function for Haskell.+description: Implements 256 and 512 bit variants of Threefish and Skein. Skein is usable as a "normal" hash function as well as in Skein-MAC mode and as a cryptographically secure PRNG, as specified in the Skein 1.3 paper.+homepage: http://github.com/valderman/threefish+license: BSD3+license-file: LICENSE+author: Anton Ekblad+maintainer: anton@ekblad.cc+-- copyright: +category: Codec, Cryptography, Random+build-type: Simple+-- extra-source-files: +cabal-version: >=1.10++library+ exposed-modules:+ Crypto.Threefish,+ Crypto.Threefish.Random,+ Crypto.Threefish.Skein+ other-modules:+ Crypto.Threefish.Common,+ Crypto.Threefish.Mix,+ Crypto.Threefish.Threefish256,+ Crypto.Threefish.Threefish512,+ Crypto.Threefish.UBI+ other-extensions:+ BangPatterns,+ MultiParamTypeClasses,+ FunctionalDependencies+ build-depends:+ base >=4.6 && <5,+ bytestring >=0.10,+ cereal >=0.3,+ array >=0.4,+ crypto-api >=0.12,+ tagged >=0.4,+ data-default >=0.5,+ random,+ entropy >= 0.2.2.2+ default-language: Haskell2010+ ghc-options: -Wall -O2+ include-dirs: cbits+ c-sources:+ cbits/threefish256.c,+ cbits/skein256.c,+ cbits/ubi.c