summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonEkblad <>2013-09-26 20:05:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2013-09-26 20:05:00 (GMT)
commit2ee4c06535b40fdc2db306e5ac74c037ec3e32fb (patch)
tree1f7537ef19d47ec0ab4df898fd7e5314016fab11
parenta8e43b0c79741da0450460dc6b96bb2e51c05414 (diff)
version 0.10.1
-rw-r--r--Crypto/Threefish.hs16
-rw-r--r--Crypto/Threefish/Authenticated.hs131
-rw-r--r--Crypto/Threefish/Random.hs43
-rw-r--r--Crypto/Threefish/Skein.hs98
-rw-r--r--Crypto/Threefish/Skein/Internal.hs30
-rw-r--r--Crypto/Threefish/Skein/KDF.hs34
-rw-r--r--Crypto/Threefish/Skein/StreamCipher.hs66
-rw-r--r--Crypto/Threefish/Threefish256.hs24
-rw-r--r--Crypto/Threefish/UBI.hs10
-rw-r--r--cbits/skein256.c23
-rw-r--r--cbits/threefish.h43
-rw-r--r--threefish.cabal32
12 files changed, 90 insertions, 460 deletions
diff --git a/Crypto/Threefish.hs b/Crypto/Threefish.hs
index ee7670a..41638bd 100644
--- a/Crypto/Threefish.hs
+++ b/Crypto/Threefish.hs
@@ -2,8 +2,8 @@
-- | 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,
+ Block256 (..), Threefish256, Key256,
+ Block512 (..), Threefish512, Key512,
Tweak (..), parseHex, readHex, defaultTweak,
Threefish (..)
) where
@@ -11,7 +11,6 @@ import Crypto.Threefish.Threefish256 as TF256
import Crypto.Threefish.Threefish512 as TF512
import Crypto.Threefish.Common as Common
import Data.Serialize
-import qualified Data.ByteString as BS
class Serialize a => Threefish a b | a -> b where
-- | Create a Threefish key using a custom tweak value.
@@ -20,24 +19,13 @@ class Serialize a => Threefish a b | a -> b where
threefishEncrypt :: a -> Tweak -> a -> a
-- | Decrypt a block using the given key and tweak value.
threefishDecrypt :: a -> Tweak -> a -> a
- -- | Create an appropriately sized block.
- toBlock :: BS.ByteString -> Maybe a
- -- | Extract the contents of a block.
- fromBlock :: a -> BS.ByteString
instance Threefish Block256 Threefish256 where
threefishKey = Threefish256
threefishEncrypt = encrypt256
threefishDecrypt = decrypt256
- toBlock bs = if BS.length bs /= 32 then Nothing else Just (Block256 bs)
- fromBlock (Block256 bs) = bs
instance Threefish Block512 Threefish512 where
threefishKey = Threefish512
threefishEncrypt = encrypt512
threefishDecrypt = decrypt512
- toBlock bs =
- case decode bs of
- Right block -> Just block
- _ -> Nothing
- fromBlock = encode
diff --git a/Crypto/Threefish/Authenticated.hs b/Crypto/Threefish/Authenticated.hs
deleted file mode 100644
index 97d9a31..0000000
--- a/Crypto/Threefish/Authenticated.hs
+++ /dev/null
@@ -1,131 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
--- | Authenticated encryption using Skein for PRNG, KDF, stream cipher and MAC.
-module Crypto.Threefish.Authenticated (
- DecryptFailure (..), Encrypted, Plaintext, Block256, Nonce256, Key256,
- encrypt, decrypt, encrypt', decrypt', encryptBytes, decryptBytes,
- generateNonce, toBlock, fromBlock
- ) where
-import Crypto.Threefish
-import Crypto.Threefish.Threefish256 (Block256(..))
-import Crypto.Threefish.Skein
-import Crypto.Threefish.Skein.KDF hiding (deriveKeys)
-import qualified Crypto.Threefish.Skein.StreamCipher as SC
-import Crypto.Threefish.Random
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as BSL
-import System.IO.Unsafe
-import Data.IORef
-import Data.Serialize
-import Control.Monad
-
-{-# NOINLINE prng #-}
-prng :: IORef SkeinGen
-prng = unsafePerformIO $ newSkeinGen >>= newIORef
-
--- | Strict version of 'atomicModifyIORef'. This forces both the value stored
--- in the 'IORef' as well as the value returned.
-atomicModIORef' :: IORef a -> (a -> (a,b)) -> IO b
-atomicModIORef' ref f = do
- b <- atomicModifyIORef ref
- (\x -> let (a, b) = f x
- in (a, a `seq` b))
- b `seq` return b
-
--- | Generate a 256 bit nonce using the Skein PRNG.
-generateNonce :: IO Nonce256
-generateNonce =
- Block256 `fmap` atomicModIORef' prng (pflip . randomBytes 32)
- where
- pflip (a, b) = (b, a)
-
-type MAC256 = Block256
-type Plaintext = BSL.ByteString
-
-data DecryptFailure = BadMAC | NoDecode String deriving Show
-
--- | An encrypt-then-MACed value. The binary format is as follows:
--- Bytes What
--- 0-31 256 bit nonce
--- 32-63 256 bit Skein-MAC
--- 64-71 Length of cryptotext as a 64 bit little endian word.
--- 71- Cryptotext
-data Encrypted a = Encrypted {
- encNonce :: Nonce256,
- encMAC :: MAC256,
- encData :: BSL.ByteString
- } deriving Show
-
-instance Serialize (Encrypted a) where
- put (Encrypted (Block256 nonce) (Block256 mac) cryptotext) = do
- putByteString nonce
- putByteString mac
- putWord64le (fromIntegral $ BSL.length cryptotext)
- putLazyByteString cryptotext
- get = do
- nonce <- getByteString 32
- mac <- getByteString 32
- len <- getWord64le
- cryptotext <- getLazyByteString (fromIntegral len)
- return $! Encrypted (Block256 nonce) (Block256 mac) cryptotext
-
-deriveKeys :: Key256 -> (Key256, Key256)
-deriveKeys k = (deriveKey k (Block256 $ BS.append "crypt" (BS.replicate 27 0)),
- deriveKey k (Block256 $ BS.append "mac" (BS.replicate 29 0)))
-
--- | Encrypt-then-MAC a message given a key and a nonce. Note that using the
--- same nonce more than once for a given key will completely destroy
--- security.
-encrypt' :: Key256 -> Nonce256 -> Plaintext -> Encrypted a
-encrypt' k n plaintext =
- Encrypted n mac cryptotext
- where
- (cryptKey, macKey) = deriveKeys k
- cryptotext = SC.encrypt cryptKey n plaintext
- mac = skeinMAC macKey cryptotext
-
--- | Verify and decrypt a message.
-decrypt' :: Key256 -> Encrypted a -> Either DecryptFailure Plaintext
-decrypt' k (Encrypted n mac cryptotext) = do
- when (mac' /= mac) $ Left BadMAC
- return $! SC.decrypt cryptKey n cryptotext
- where
- (cryptKey, macKey) = deriveKeys k
- mac' = skeinMAC macKey cryptotext
-
--- | Encrypt-then-MAC any serializable value.
--- The 256 bit nonce is generated using a Skein-based PRNG seeded from the
--- system's entropy pool. This means that two successive calls to encrypt
--- will not yield the exact same output; however, the identity
--- forall k, x. Right x == decrypt k (encrypt k x)
--- will always hold.
---
--- The subkeys for encryption and MAC are generated by applying Skein-KDF
--- to the master key, with the key identifiers "crypt" and "mac"
--- respectively, zero padded at the end until 32 bytes.
-encrypt :: Serialize a => Key256 -> a -> Encrypted a
-encrypt k x = unsafePerformIO $ do
- nonce <- generateNonce
- return $! encrypt' k nonce (runPutLazy (put x))
-
--- | Encrypt-then-MAC a lazy ByteString.
-encryptBytes :: Key256 -> BSL.ByteString -> BSL.ByteString
-encryptBytes k bs = unsafePerformIO $ do
- nonce <- generateNonce
- return $! runPutLazy $! put (encrypt' k nonce bs)
-
--- | Decrypt and decode a message. Will fail if there is a MAC mismatch or if
--- the message can't be decoded into the given data type.
-decrypt :: Serialize a => Key256 -> Encrypted a -> Either DecryptFailure a
-decrypt k enc = do
- plaintext <- decrypt' k enc
- case runGetLazy get plaintext of
- Right x -> return x
- Left err -> Left (NoDecode err)
-
--- | Verify and decrypt a lazy ByteString.
-decryptBytes :: Key256 -> BSL.ByteString -> Either DecryptFailure Plaintext
-decryptBytes k bs = do
- enc <- case runGetLazy get bs of
- Right x -> return x
- Left err -> Left (NoDecode err)
- decrypt' k enc
diff --git a/Crypto/Threefish/Random.hs b/Crypto/Threefish/Random.hs
index dea58cc..cd4b179 100644
--- a/Crypto/Threefish/Random.hs
+++ b/Crypto/Threefish/Random.hs
@@ -1,22 +1,17 @@
-- | Skein 256 as a PRNG.
module Crypto.Threefish.Random (
- SkeinGen, Block256, Random (..), RandomGen (..),
- newSkeinGen, mkSkeinGen, mkSkeinGenEx, randomBytes, reseedSkeinGen,
- toBlock, fromBlock
+ SkeinGen, Block256 (..), Random (..), RandomGen (..),
+ newSkeinGen, mkSkeinGen, mkSkeinGenEx, randomBytes
) where
import Crypto.Threefish.Skein
-import Crypto.Threefish.Threefish256
import System.Random
import System.Entropy
import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as BSL
import Data.ByteString.Unsafe
import System.IO.Unsafe
import Foreign.Storable (sizeOf, peek)
import Foreign.Ptr (castPtr)
import Data.Serialize
-import Crypto.Random
-import Data.Tagged
emptyKey :: Key256
emptyKey = Block256 BS.empty
@@ -55,16 +50,7 @@ mkSkeinGen = mkSkeinGenEx defaultSkeinGenPoolSize . Block256 . encode
-- across splits.
mkSkeinGenEx :: Int -> Block256 -> SkeinGen
mkSkeinGenEx poolsize (Block256 seed) = SkeinGen {
- sgState = skein $ BSL.fromStrict (BS.replicate 32 0 `BS.append` seed),
- sgPool = BS.empty,
- sgPoolSize = poolsize
- }
-
--- | Reseed a Skein PRNG.
-reseedSkeinGen :: Block256 -> SkeinGen -> SkeinGen
-reseedSkeinGen (Block256 seed) (SkeinGen (Block256 state) _ poolsize) =
- SkeinGen {
- sgState = skein $ BSL.fromStrict (state `BS.append` seed),
+ sgState = skein (BS.replicate 32 0 `BS.append` seed),
sgPool = BS.empty,
sgPoolSize = poolsize
}
@@ -79,26 +65,7 @@ randomBytes nbytes (SkeinGen (Block256 state) pool poolsize)
(BS.append pool out, SkeinGen (Block256 state') pool' poolsize)
where
-- Use all of the output to avoid making unnecessary calls
- nbytes' = fromIntegral $ 32 + max (nbytes + (32-(nbytes`rem`32))) poolsize
- bytes = hash256 nbytes' emptyKey (BSL.fromStrict state)
+ 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
-
-instance CryptoRandomGen SkeinGen where
- newGen seed =
- case BS.length seed of
- n | n >= 32 ->
- Right $ mkSkeinGenEx ps (Block256 $ BS.take 32 seed)
- | otherwise ->
- Left NotEnoughEntropy
- where ps = defaultSkeinGenPoolSize
- genSeedLength = Tagged 32
- genBytes n g = Right $ randomBytes n g
- reseedInfo = const Never
- reseedPeriod = const Never
- reseed seed g =
- case BS.length seed of
- n | n >= 32 ->
- Right $ reseedSkeinGen (Block256 $ BS.take 32 seed) g
- | otherwise ->
- Left NotEnoughEntropy
diff --git a/Crypto/Threefish/Skein.hs b/Crypto/Threefish/Skein.hs
index 96e0315..1cdadf3 100644
--- a/Crypto/Threefish/Skein.hs
+++ b/Crypto/Threefish/Skein.hs
@@ -1,89 +1,69 @@
-{-# LANGUAGE BangPatterns, OverloadedStrings, MultiParamTypeClasses #-}
+{-# LANGUAGE BangPatterns, OverloadedStrings, ForeignFunctionInterface #-}
-- | 256 and 512 bit Skein. Supports "normal" hashing and Skein-MAC.
module Crypto.Threefish.Skein (
- Skein (..), Threefish (..), Block256, Block512, Key256, Key512, Nonce256,
+ Skein (..), Block256 (..), Block512 (..), Key256, Key512, Nonce256,
hash256, hash512
) where
import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as BSL
import Crypto.Threefish.Threefish256
import Crypto.Threefish.Threefish512
import Crypto.Threefish.UBI
-import Crypto.Threefish
-import Crypto.Threefish.Skein.Internal
import Data.Bits
import Data.Serialize
import Data.Word
import Data.ByteString.Unsafe
import Foreign.Ptr
import Foreign.ForeignPtr
-import Foreign.Marshal.Alloc
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 -> BSL.ByteString -> a
+ skeinMAC :: a -> BS.ByteString -> a
-- | Calculate the Skein checksum of a message.
- skein :: BSL.ByteString -> a
+ skein :: BS.ByteString -> a
type Nonce256 = Block256
-init256 :: Key256 -> Word64 -> Skein256Ctx
-init256 (Block256 k) outlen =
- unsafePerformIO $ do
- c <- mallocForeignPtrBytes 64
- withForeignPtr c $ \ctx -> do
- withKey $ \key -> do
- skein256_init ctx (castPtr key) (outlen*8)
- return (Skein256Ctx c)
- where
- withKey f | BS.length k == 32 = unsafeUseAsCString k (f . castPtr)
- | otherwise = f nullPtr
-
-update256 :: Skein256Ctx -> Int -> BSL.ByteString -> BS.ByteString
-update256 (Skein256Ctx c) outlen bytes =
- unsafePerformIO $ withForeignPtr c $ go 1 bytes
+-- | 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
- !msgtype = type2int Message
- go !first !msg !ctx = do
- case BSL.splitAt 16384 msg of
- (chunk, rest)
- | BSL.null chunk ->
- allocaBytes (outblocks*32) $ \ptr -> do
- skein256_output ctx 0 (outblocks-1) ptr
- BS.packCStringLen (castPtr ptr, outlen)
- | otherwise -> do
- let !chunk' =
- toStrict chunk
- (!lst, !len) =
- if BSL.null rest
- then (2, fromIntegral $ BS.length chunk')
- else (0, 16384)
- unsafeUseAsCString chunk' $ \ptr -> do
- skein256_update ctx (first .|. lst) msgtype len (castPtr ptr)
- go 0 rest ctx
-
-toStrict :: BSL.ByteString -> BS.ByteString
-toStrict = BS.concat . BSL.toChunks
-
-hash256 :: Word64 -> Key256 -> BSL.ByteString -> BS.ByteString
-hash256 outlen k bs =
- case init256 k outlen of
- ctx -> update256 ctx (fromIntegral outlen) bs
+ !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 :: BSL.ByteString -> Block256
-skein256 = Block256 . hash256 32 (Block256 BS.empty)
+skein256 :: BS.ByteString -> Block256
+skein256 = Block256 . hash256 32 (Block256 "") (Block256 "")
{-# INLINE skeinMAC256 #-}
-- | Create a 256 bit Skein-MAC.
-skeinMAC256 :: Key256 -> BSL.ByteString -> Block256
-skeinMAC256 key = Block256 . hash256 32 key
+skeinMAC256 :: Key256 -> BS.ByteString -> Block256
+skeinMAC256 key = Block256 . hash256 32 key (Block256 "")
instance Skein Block256 where
skeinMAC = skeinMAC256
@@ -123,16 +103,16 @@ processBlock512 !len !key !tweak !block =
-- | Hash a message using a particular key. For normal hashing, use all zeroes;
-- for Skein-MAC, use the MAC key.
-hash512 :: Key512 -> BSL.ByteString -> Block512
+hash512 :: Key512 -> BS.ByteString -> Block512
hash512 !firstkey !bs =
- case flip runGetLazy bs' $ go len (init512 firstkey) (newTweak Message) of
+ 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 = BSL.length bs
+ !len = BS.length bs
!lastLen = case len `rem` 64 of 0 -> 64 ; n -> n
!lastLenW64 = fromIntegral lastLen
- !bs' = BSL.append bs (BSL.replicate (64-fromIntegral lastLen) 0)
+ !bs' = BS.append bs (BS.replicate (64-lastLen) 0)
go !n !key !tweak
| n > 64 = do
block <- get
@@ -148,12 +128,12 @@ hash512 !firstkey !bs =
{-# INLINE skein512 #-}
-- | Hash a message using 512 bit Skein.
-skein512 :: BSL.ByteString -> Block512
+skein512 :: BS.ByteString -> Block512
skein512 = hash512 zero512
{-# INLINE skeinMAC512 #-}
-- | Create a 512 bit Skein-MAC.
-skeinMAC512 :: Key512 -> BSL.ByteString -> Block512
+skeinMAC512 :: Key512 -> BS.ByteString -> Block512
skeinMAC512 =
hash512 . fst . processBlock512 64 zero512 (setLast True $ newTweak Key)
diff --git a/Crypto/Threefish/Skein/Internal.hs b/Crypto/Threefish/Skein/Internal.hs
deleted file mode 100644
index 07d767c..0000000
--- a/Crypto/Threefish/Skein/Internal.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-{-# LANGUAGE ForeignFunctionInterface #-}
--- | Skein FFI internals.
-module Crypto.Threefish.Skein.Internal where
-import Foreign.ForeignPtr
-import Foreign.Ptr
-import Data.Word
-
-newtype Skein256Ctx = Skein256Ctx (ForeignPtr Word64)
-
-foreign import ccall unsafe skein256_init
- :: Ptr Word64 -- ^ Skein 256 context to initialize.
- -> Ptr Word64 -- ^ Desired key or nullPtr.
- -> Word64 -- ^ Output size in bits.
- -> IO ()
-
-foreign import ccall unsafe skein256_update
- :: Ptr Word64 -- ^ Skein 256 context.
- -> Int -- ^ First/last update? First starts a new tweak.
- -- (First bit indicates first, second bit indicates last.)
- -> Int -- ^ Type of block, as given by type2int.
- -> Word64 -- ^ Length of block. Must be multiple of 32 except for last.
- -> Ptr Word64 -- ^ Pointer to update data.
- -> IO ()
-
-foreign import ccall unsafe skein256_output
- :: Ptr Word64 -- ^ Skein 256 context.
- -> Int -- ^ First output block to get.
- -> Int -- ^ Last output block to get.
- -> Ptr Word64 -- ^ Pointer to store output data in.
- -> IO ()
diff --git a/Crypto/Threefish/Skein/KDF.hs b/Crypto/Threefish/Skein/KDF.hs
deleted file mode 100644
index f07eebd..0000000
--- a/Crypto/Threefish/Skein/KDF.hs
+++ /dev/null
@@ -1,34 +0,0 @@
--- | Skein as a key derivation function.
-module Crypto.Threefish.Skein.KDF (deriveKey, deriveKeys) where
-import Crypto.Threefish.Skein.Internal
-import Crypto.Threefish.Skein
-import Crypto.Threefish.UBI
-import Crypto.Threefish.Threefish256
-import Data.Serialize
-import qualified Data.ByteString as BS
-import Data.ByteString.Unsafe
-import System.IO.Unsafe
-import Foreign.Marshal.Alloc
-import Foreign.Ptr
-
--- | Derive up to 2^64 keys from a master key.
--- The key identifiers will be 0, 1, ... 2^64-1.
-deriveKeys :: Key256 -> [Key256]
-deriveKeys mk =
- [deriveKey mk (Block256 $ runPut $ mapM_ putWord64le [kid,0,0,0]) |
- kid <- [0..]]
-
--- | Derive a key from a master key using a custom key identifier.
-deriveKey :: Key256 -> Block256 -> Key256
-deriveKey (Block256 mk) (Block256 kid) =
- unsafePerformIO $ do
- allocaBytes 64 $ \ctx -> do
- allocaBytes 32 $ \outkey -> do
- unsafeUseAsCString mk $ \masterkey -> do
- unsafeUseAsCString kid $ \keyid -> do
- skein256_init ctx (castPtr masterkey) 256
- skein256_update ctx 3 (type2int KeyIdentifier) l (castPtr keyid)
- skein256_output ctx 0 0 outkey
- Block256 `fmap` BS.packCStringLen (castPtr outkey, 32)
- where
- l = fromIntegral $ BS.length kid
diff --git a/Crypto/Threefish/Skein/StreamCipher.hs b/Crypto/Threefish/Skein/StreamCipher.hs
deleted file mode 100644
index 117fed3..0000000
--- a/Crypto/Threefish/Skein/StreamCipher.hs
+++ /dev/null
@@ -1,66 +0,0 @@
--- | 256 bit Skein as a stream cipher, as specified in the Skein 1.3 paper.
-module Crypto.Threefish.Skein.StreamCipher (
- Key256, Nonce256, Block256,
- encrypt, decrypt, toBlock, fromBlock
- ) where
-import Crypto.Threefish.Skein (Nonce256)
-import Crypto.Threefish.UBI
-import Crypto.Threefish.Threefish256
-import Crypto.Threefish
-import Crypto.Threefish.Skein.Internal
-import Data.ByteString.Unsafe
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as BSL
-import Foreign.ForeignPtr
-import Foreign.Ptr
-import Foreign.Marshal.Alloc
-import System.IO.Unsafe
-import Data.Bits (xor)
-
-init256 :: Key256 -> Nonce256 -> Skein256Ctx
-init256 (Block256 k) (Block256 n) =
- unsafePerformIO $ do
- c <- mallocForeignPtrBytes 64
- withForeignPtr c $ \ctx -> do
- unsafeUseAsCString k $ \key -> do
- unsafeUseAsCString n $ \nonce -> do
- skein256_init ctx (castPtr key) 0xffffffffffffffff
- skein256_update ctx 3 (type2int Nonce) len (castPtr nonce)
- return (Skein256Ctx c)
- where
- len = fromIntegral $ BS.length n
-
-stream256 :: Skein256Ctx -> [BS.ByteString]
-stream256 (Skein256Ctx c) =
- unsafePerformIO $ withForeignPtr c $ go 0
- where
- go n ctx = unsafeInterleaveIO $ do
- bs <- allocaBytes 1024 $ \ptr -> do
- skein256_output ctx n (n+32) ptr
- BS.packCStringLen (castPtr ptr, 1024)
- bss <- go (n+32) ctx
- return $ bs : bss
-
-keystream256 :: Key256 -> Nonce256 -> [BS.ByteString]
-keystream256 k n = stream256 (init256 k n)
-
--- | Encrypt a lazy ByteString using 256 bit Skein as a stream cipher.
-encrypt :: Key256 -> Nonce256 -> BSL.ByteString -> BSL.ByteString
-encrypt k n plaintext =
- BSL.fromChunks $ go (keystream256 k n) plaintext
- where
- go (ks:kss) msg = unsafePerformIO . unsafeInterleaveIO $ do
- case BSL.splitAt 1024 msg of
- (chunk, rest)
- | BSL.null chunk ->
- return []
- | otherwise ->
- let chunk' = BSL.toStrict chunk
- in return $ (BS.pack $ BS.zipWith xor ks chunk') : go kss rest
- go _ _ =
- error "The key stream is infinite, so this will never happen."
-
--- | Encryption and decryption are the same operation for a stream cipher, but
--- we may want to have a function called encrypt for clarity.
-decrypt :: Key256 -> Nonce256 -> BSL.ByteString -> BSL.ByteString
-decrypt = encrypt
diff --git a/Crypto/Threefish/Threefish256.hs b/Crypto/Threefish/Threefish256.hs
index fb1219b..e421e18 100644
--- a/Crypto/Threefish/Threefish256.hs
+++ b/Crypto/Threefish/Threefish256.hs
@@ -17,19 +17,19 @@ import Foreign.Ptr
import Foreign.ForeignPtr
import System.IO.Unsafe
-foreign import ccall unsafe "encrypt256" c_encrypt256 :: Ptr Word64
- -> Word64
- -> Word64
- -> Ptr Word64
- -> Ptr Word64
- -> IO ()
+foreign import ccall "encrypt256" c_encrypt256 :: Ptr Word64
+ -> Word64
+ -> Word64
+ -> Ptr Word64
+ -> Ptr Word64
+ -> IO ()
-foreign import ccall unsafe "decrypt256" c_decrypt256 :: 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
diff --git a/Crypto/Threefish/UBI.hs b/Crypto/Threefish/UBI.hs
index 7e2be56..651a5d5 100644
--- a/Crypto/Threefish/UBI.hs
+++ b/Crypto/Threefish/UBI.hs
@@ -24,16 +24,6 @@ type2w64 Nonce = 20
type2w64 Message = 48
type2w64 Output = 63
-type2int :: BlockType -> Int
-type2int Key = 0
-type2int Config = 4
-type2int Personalization = 8
-type2int PublicKey = 12
-type2int KeyIdentifier = 16
-type2int Nonce = 20
-type2int Message = 48
-type2int Output = 63
-
{-# INLINE newTweak #-}
newTweak :: BlockType -> Tweak
newTweak t = setType t $ setFirst True $ Tweak 0 0
diff --git a/cbits/skein256.c b/cbits/skein256.c
index 7a20b6c..838fbb8 100644
--- a/cbits/skein256.c
+++ b/cbits/skein256.c
@@ -1,8 +1,8 @@
#include "threefish.h"
#include <string.h>
-void skein256_init(skein_t* ctx, W64* key, W64 outlen) {
- W64 config[4] = {0x0000000133414853, outlen, 0, 0};
+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 */
@@ -84,3 +84,22 @@ void skein256_output(skein_t* ctx, int from, int to, W64* out) {
++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);
+}
diff --git a/cbits/threefish.h b/cbits/threefish.h
deleted file mode 100644
index 26b3201..0000000
--- a/cbits/threefish.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef _THREEFISH_H
-#define _THREEFISH_H
-
-typedef unsigned long long W64;
-extern W64 key_const;
-
-typedef struct {
- W64 key[4];
- W64 tweak[2];
- int outlen;
-} skein_t;
-
-#define rl(x, b) (((x) << ((b) & 63)) | ((x) >> ((64-(b)) & 63)))
-#define rr(x, b) (((x) >> ((b) & 63)) | ((x) << ((64-(b)) & 63)))
-
-typedef enum {
- T_KEY = 0,
- T_CONFIG = 4,
- T_PERSONALIZATION = 8,
- T_PUBKEY = 12,
- T_KEYIDENTIFIER = 16,
- T_NONCE = 20,
- T_MSG = 48,
- T_OUT = 63
-} UBIType;
-
-void encrypt256(W64* key, W64 t0, W64 t1, W64* in, W64* out);
-void decrypt256(W64* key, W64 t0, W64 t1, W64* in, W64* out);
-
-/* note that here outlen is in *bits* */
-void skein256_init(skein_t* ctx, W64* key, W64 outlen);
-/* firstlast & 1 if we're starting a new type, firstlast & 2 if it's the last update */
-void skein256_update(skein_t* ctx, int firstlast, UBIType type, W64 len, W64* data);
-void skein256_output(skein_t* ctx, int from, int to, W64* out);
-
-inline void init_tweak(UBIType type, W64* t);
-inline void mk_config_tweak(W64* t);
-inline void set_type(UBIType type, W64* t);
-inline void set_first(unsigned char first, W64* t);
-inline void set_last(unsigned char last, W64* t);
-inline void add_bytes(W64 bytes, W64* t);
-
-#endif
diff --git a/threefish.cabal b/threefish.cabal
index 37bc47e..31b1d29 100644
--- a/threefish.cabal
+++ b/threefish.cabal
@@ -1,7 +1,7 @@
name: threefish
-version: 0.2.6
+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, as a cryptographically secure PRNG, as a stream cipher and as a key derivation function, all implemented according to the specifications of the Skein 1.3 paper.
+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
@@ -13,19 +13,11 @@ build-type: Simple
-- extra-source-files:
cabal-version: >=1.10
-source-repository head
- type: git
- location: https://github.com/valderman/threefish.git
-
library
exposed-modules:
Crypto.Threefish,
- Crypto.Threefish.Authenticated,
Crypto.Threefish.Random,
- Crypto.Threefish.Skein,
- Crypto.Threefish.Skein.Internal,
- Crypto.Threefish.Skein.KDF,
- Crypto.Threefish.Skein.StreamCipher
+ Crypto.Threefish.Skein
other-modules:
Crypto.Threefish.Common,
Crypto.Threefish.Mix,
@@ -37,20 +29,18 @@ library
MultiParamTypeClasses,
FunctionalDependencies
build-depends:
- base >=4.5 && <5,
- bytestring >=0.10.4.0,
- cereal >=0.4.0.1,
- array >=0.4.0.0,
- crypto-api >=0.12.2.2,
- tagged >=0.7,
- data-default >=0.5.3,
+ 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
+ entropy >= 0.2.2.2
default-language: Haskell2010
ghc-options: -Wall -O2
include-dirs: cbits
- install-includes:
- threefish.h
c-sources:
cbits/threefish256.c,
cbits/skein256.c,