packages feed

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 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