Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implement Skein-MAC.

  • Loading branch information...
commit 6728aaee4b78424f14f6ad480699c602366bef3e 1 parent fe00cb0
@meteficha authored
Showing with 166 additions and 13 deletions.
  1. +159 −13 src/Crypto/Skein.hs
  2. +7 −0 src/Crypto/Skein/Internal.hsc
View
172 src/Crypto/Skein.hs
@@ -24,6 +24,13 @@ module Crypto.Skein
, Skein_1024_1024_Ctx
, Skein_1024_1024
+ -- * Skein-MAC
+ -- $skeinmac
+ , Key
+ , skeinMAC
+ , skeinMAC'
+ , SkeinMAC (skeinMACCtx)
+
-- * Other variants
-- $variants
-- ** Skein-256-128
@@ -69,6 +76,7 @@ import Foreign.C
-- from bytestring
import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Internal as BI
import qualified Data.ByteString.Unsafe as BU
@@ -84,6 +92,7 @@ import Crypto.Classes
-- from this package
import Crypto.Skein.Internal
+----------------------------------------------------------------------
-- $variants
--
@@ -108,6 +117,92 @@ import Crypto.Skein.Internal
--
-- [SHA-512] with 'Skein_512_512' or 'Skein_1024_512'.
+----------------------------------------------------------------------
+
+-- $skeinmac
+--
+-- The standard way to use a hash function for authentication is
+-- to use the HMAC construction. While you may securely use
+-- Skein with HMAC (e.g. HMAC-Skein-512-512), Skein also supports
+-- another mode for MAC. Skein-MAC is as secure as
+-- HMAC-Skein, however faster. Skein-MAC is as fast as
+-- Skein as a hash function, with zero overhead.
+
+-- | Secret key used to calculate the Skein-MAC.
+--
+-- The 'Key' may have any length. However, it's recommended to
+-- have at least the same number of bits of the state size. For
+-- example, when using 'skeinMAC' with 'Skein_512_256', it is
+-- recommended to have a key with at least 64 bytes (512 bits),
+-- which is the state size of 'Skein_512_256' (the first of the
+-- two numbers).
+type Key = B.ByteString
+
+-- | Class of Skein contexts that may be used for Skein-MAC (all
+-- of them). Included here mostly for documentation purposes,
+-- since adding new instances is not safe (functions using
+-- 'SkeinMAC' unsurprisingly assume that they are using Skein).
+class SkeinMAC skeinCtx where
+ -- | Construct a context @skeinCtx@ given a 'Key'. This
+ -- context may be used with the usual 'Hash' interface to
+ -- obtain a message authentication code (MAC).
+ --
+ -- For a simpler interface, see 'skeinMAC' and 'skeinMAC''.
+ skeinMACCtx :: Key -> skeinCtx
+
+-- | Calculate the Skein-MAC of a lazy 'L.ByteString' given a
+-- 'Key'. You probably also want to apply 'encode' to get a
+-- 'B.ByteString' out of the @digest@.
+--
+-- This function may be partially applied for increased
+-- performance. Using a partially applied @skeinMAC@ is as fast
+-- as using Skein as a cryptographic hash function. So, instead
+-- of
+--
+-- @
+-- let mac1 = skeinMAC key message1
+-- mac2 = skeinMAC key message2
+-- mac3 = skeinMAC key message3
+-- ...
+-- @
+--
+-- write the following code:
+--
+-- @
+-- let calcMAC = skeinMAC key
+-- mac1 = calcMAC message1
+-- mac2 = calcMAC message2
+-- mac3 = calcMAC message3
+-- ...
+-- @
+--
+-- This way the key will be processed only once (with
+-- 'skeinMACCtx').
+skeinMAC :: (SkeinMAC skeinCtx, Hash skeinCtx digest) =>
+ Key -> L.ByteString -> digest
+skeinMAC k = go
+ where
+ ctx = skeinMACCtx k
+ go = go' ctx . L.toChunks
+ go' ctx' [] = finalize ctx' B.empty
+ go' ctx' [x] = finalize ctx' x
+ go' ctx' (x:xs) = go' (updateCtx ctx' x) xs
+ -- See the comment below on skeinMAC'.
+
+-- | Same as 'skeinMAC', however using a strict 'B.ByteString'.
+-- Should be faster for small 'B.ByteString'@s@.
+skeinMAC' :: (SkeinMAC skeinCtx, Hash skeinCtx digest) =>
+ Key -> B.ByteString -> digest
+skeinMAC' k = finalize ctx
+ where
+ ctx = skeinMACCtx k
+ -- We can just call 'finalize' because of the way our
+ -- implementation works. Basically, we accept ByteString
+ -- of any length on both 'updateCtx' and 'finalize'.
+ -- Calling just 'finalize' is more efficient.
+
+
+----------------------------------------------------------------------
-- | Helper function to create 'initialCtx'.
initialCtxSkein :: Storable internalCtx =>
@@ -150,6 +245,18 @@ finalizeSkein hashLenBytes update final unCtx mkHash = \ctx bs ->
check $ update ctx_ptr (castPtr bs_ptr) (fromIntegral bs_len)
fmap mkHash $ BI.create hashLenBytes $ check . final ctx_ptr . castPtr
+-- | Helper function to create 'skeinMACCtx'.
+skeinMACCtxSkein :: Storable internalCtx =>
+ CSize
+ -> (Ptr internalCtx -> CSize -> Word64 -> Ptr Word8 -> CSize -> IO CInt)
+ -> (internalCtx -> externalCtx)
+ -> (Key -> externalCtx)
+skeinMACCtxSkein bits initExt mkCtx = \key ->
+ unsafePerformIO $
+ BU.unsafeUseAsCStringLen key $ \(key_ptr, key_len) ->
+ alloca $ \ctx_ptr -> do
+ check $ initExt ctx_ptr bits sKEIN_SEQUENTIAL (castPtr key_ptr) (fromIntegral key_len)
+ fmap mkCtx $ peek ctx_ptr
@@ -161,7 +268,7 @@ finalizeSkein hashLenBytes update final unCtx mkHash = \ctx bs ->
newtype Skein_256_128_Ctx = S_256_128_Ctx {unS_256_128_Ctx :: Skein256Ctx}
-- | Skein-256-128 hash. You probably want to use 'encode' to
--- obtain a 128-bit (16-byte) 'ByteString'. May be used as a
+-- obtain a 128-bit (16-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for MD5.
newtype Skein_256_128 = S_256_128 B.ByteString deriving (Eq, Ord)
@@ -176,12 +283,15 @@ instance Hash Skein_256_128_Ctx Skein_256_128 where
updateCtx = updateCtxSkein skein256Update unS_256_128_Ctx S_256_128_Ctx
finalize = finalizeSkein 16 skein256Update skein256Final unS_256_128_Ctx S_256_128
+instance SkeinMAC Skein_256_128_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 128 skein256InitExt S_256_128_Ctx
+
-- | Context of the Skein-256-160 hash function.
newtype Skein_256_160_Ctx = S_256_160_Ctx {unS_256_160_Ctx :: Skein256Ctx}
-- | Skein-256-160 hash. You probably want to use 'encode' to
--- obtain a 160-bit (20-byte) 'ByteString'. May be used as a
+-- obtain a 160-bit (20-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for SHA-1.
newtype Skein_256_160 = S_256_160 B.ByteString deriving (Eq, Ord)
@@ -196,12 +306,15 @@ instance Hash Skein_256_160_Ctx Skein_256_160 where
updateCtx = updateCtxSkein skein256Update unS_256_160_Ctx S_256_160_Ctx
finalize = finalizeSkein 20 skein256Update skein256Final unS_256_160_Ctx S_256_160
+instance SkeinMAC Skein_256_160_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 160 skein256InitExt S_256_160_Ctx
+
-- | Context of the Skein-256-224 hash function.
newtype Skein_256_224_Ctx = S_256_224_Ctx {unS_256_224_Ctx :: Skein256Ctx}
-- | Skein-256-224 hash. You probably want to use 'encode' to
--- obtain a 224-bit (28-byte) 'ByteString'. May be used as a
+-- obtain a 224-bit (28-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for SHA-224.
newtype Skein_256_224 = S_256_224 B.ByteString deriving (Eq, Ord)
@@ -216,12 +329,15 @@ instance Hash Skein_256_224_Ctx Skein_256_224 where
updateCtx = updateCtxSkein skein256Update unS_256_224_Ctx S_256_224_Ctx
finalize = finalizeSkein 28 skein256Update skein256Final unS_256_224_Ctx S_256_224
+instance SkeinMAC Skein_256_224_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 224 skein256InitExt S_256_224_Ctx
+
-- | Context of the Skein-256-256 hash function.
newtype Skein_256_256_Ctx = S_256_256_Ctx {unS_256_256_Ctx :: Skein256Ctx}
-- | Skein-256-256 hash. You probably want to use 'encode' to
--- obtain a 256-bit (32-byte) 'ByteString'. Usually it's better
+-- obtain a 256-bit (32-byte) 'B.ByteString'. Usually it's better
-- to use 'Skein_512_256' (256 bits of output) or 'Skein_512_512'
-- (512 bits of output).
newtype Skein_256_256 = S_256_256 B.ByteString deriving (Eq, Ord)
@@ -237,6 +353,9 @@ instance Hash Skein_256_256_Ctx Skein_256_256 where
updateCtx = updateCtxSkein skein256Update unS_256_256_Ctx S_256_256_Ctx
finalize = finalizeSkein 32 skein256Update skein256Final unS_256_256_Ctx S_256_256
+instance SkeinMAC Skein_256_256_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 256 skein256InitExt S_256_256_Ctx
+
@@ -248,7 +367,7 @@ instance Hash Skein_256_256_Ctx Skein_256_256 where
newtype Skein_512_128_Ctx = S_512_128_Ctx {unS_512_128_Ctx :: Skein512Ctx}
-- | Skein-512-128 hash. You probably want to use 'encode' to
--- obtain a 128-bit (16-byte) 'ByteString'. May be used as a
+-- obtain a 128-bit (16-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for MD5.
newtype Skein_512_128 = S_512_128 B.ByteString deriving (Eq, Ord)
@@ -263,11 +382,14 @@ instance Hash Skein_512_128_Ctx Skein_512_128 where
updateCtx = updateCtxSkein skein512Update unS_512_128_Ctx S_512_128_Ctx
finalize = finalizeSkein 16 skein512Update skein512Final unS_512_128_Ctx S_512_128
+instance SkeinMAC Skein_512_128_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 128 skein512InitExt S_512_128_Ctx
+
-- | Context of the Skein-512-160 hash function.
newtype Skein_512_160_Ctx = S_512_160_Ctx {unS_512_160_Ctx :: Skein512Ctx}
-- | Skein-512-160 hash. You probably want to use 'encode' to
--- obtain a 160-bit (20-byte) 'ByteString'. May be used as a
+-- obtain a 160-bit (20-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for SHA-1.
newtype Skein_512_160 = S_512_160 B.ByteString deriving (Eq, Ord)
@@ -282,12 +404,15 @@ instance Hash Skein_512_160_Ctx Skein_512_160 where
updateCtx = updateCtxSkein skein512Update unS_512_160_Ctx S_512_160_Ctx
finalize = finalizeSkein 20 skein512Update skein512Final unS_512_160_Ctx S_512_160
+instance SkeinMAC Skein_512_160_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 160 skein512InitExt S_512_160_Ctx
+
-- | Context of the Skein-512-224 hash function.
newtype Skein_512_224_Ctx = S_512_224_Ctx {unS_512_224_Ctx :: Skein512Ctx}
-- | Skein-512-224 hash. You probably want to use 'encode' to
--- obtain a 224-bit (28-byte) 'ByteString'. May be used as a drop-in replacement for SHA-224.
+-- obtain a 224-bit (28-byte) 'B.ByteString'. May be used as a drop-in replacement for SHA-224.
newtype Skein_512_224 = S_512_224 B.ByteString deriving (Eq, Ord)
instance Serialize Skein_512_224 where
@@ -301,12 +426,15 @@ instance Hash Skein_512_224_Ctx Skein_512_224 where
updateCtx = updateCtxSkein skein512Update unS_512_224_Ctx S_512_224_Ctx
finalize = finalizeSkein 28 skein512Update skein512Final unS_512_224_Ctx S_512_224
+instance SkeinMAC Skein_512_224_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 224 skein512InitExt S_512_224_Ctx
+
-- | Context of the Skein-512-256 hash function.
newtype Skein_512_256_Ctx = S_512_256_Ctx {unS_512_256_Ctx :: Skein512Ctx}
-- | Skein-512-256 hash. You probably want to use 'encode' to
--- obtain a 256-bit (32-byte) 'ByteString'.
+-- obtain a 256-bit (32-byte) 'B.ByteString'.
newtype Skein_512_256 = S_512_256 B.ByteString deriving (Eq, Ord)
instance Serialize Skein_512_256 where
@@ -320,12 +448,15 @@ instance Hash Skein_512_256_Ctx Skein_512_256 where
updateCtx = updateCtxSkein skein512Update unS_512_256_Ctx S_512_256_Ctx
finalize = finalizeSkein 32 skein512Update skein512Final unS_512_256_Ctx S_512_256
+instance SkeinMAC Skein_512_256_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 256 skein512InitExt S_512_256_Ctx
+
-- | Context of the Skein-512-384 hash function.
newtype Skein_512_384_Ctx = S_512_384_Ctx {unS_512_384_Ctx :: Skein512Ctx}
-- | Skein-512-384 hash. You probably want to use 'encode' to
--- obtain a 384-bit (48-byte) 'ByteString'. May be used as a
+-- obtain a 384-bit (48-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for SHA-384.
newtype Skein_512_384 = S_512_384 B.ByteString deriving (Eq, Ord)
@@ -340,12 +471,15 @@ instance Hash Skein_512_384_Ctx Skein_512_384 where
updateCtx = updateCtxSkein skein512Update unS_512_384_Ctx S_512_384_Ctx
finalize = finalizeSkein 48 skein512Update skein512Final unS_512_384_Ctx S_512_384
+instance SkeinMAC Skein_512_384_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 384 skein512InitExt S_512_384_Ctx
+
-- | Context of the Skein-512-512 hash function.
newtype Skein_512_512_Ctx = S_512_512_Ctx {unS_512_512_Ctx :: Skein512Ctx}
-- | Skein-512-512 hash. You probably want to use 'encode' to
--- obtain a 512-bit (64-byte) 'ByteString'. It's the main Skein
+-- obtain a 512-bit (64-byte) 'B.ByteString'. It's the main Skein
-- hash function. May be used as a drop-in replacement for
-- SHA-512 as well.
newtype Skein_512_512 = S_512_512 B.ByteString deriving (Eq, Ord)
@@ -361,6 +495,9 @@ instance Hash Skein_512_512_Ctx Skein_512_512 where
updateCtx = updateCtxSkein skein512Update unS_512_512_Ctx S_512_512_Ctx
finalize = finalizeSkein 32 skein512Update skein512Final unS_512_512_Ctx S_512_512
+instance SkeinMAC Skein_512_512_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 512 skein512InitExt S_512_512_Ctx
+
----------------------------------------------------------------------
@@ -371,7 +508,7 @@ instance Hash Skein_512_512_Ctx Skein_512_512 where
newtype Skein_1024_384_Ctx = S_1024_384_Ctx {unS_1024_384_Ctx :: Skein1024Ctx}
-- | Skein-1024-384 hash. You probably want to use 'encode' to
--- obtain a 384-bit (48-byte) 'ByteString'. May be used as a
+-- obtain a 384-bit (48-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for SHA-384.
newtype Skein_1024_384 = S_1024_384 B.ByteString deriving (Eq, Ord)
@@ -386,12 +523,15 @@ instance Hash Skein_1024_384_Ctx Skein_1024_384 where
updateCtx = updateCtxSkein skein1024Update unS_1024_384_Ctx S_1024_384_Ctx
finalize = finalizeSkein 48 skein1024Update skein1024Final unS_1024_384_Ctx S_1024_384
+instance SkeinMAC Skein_1024_384_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 384 skein1024InitExt S_1024_384_Ctx
+
-- | Context of the Skein-1024-512 hash function.
newtype Skein_1024_512_Ctx = S_1024_512_Ctx {unS_1024_512_Ctx :: Skein1024Ctx}
-- | Skein-1024-512 hash. You probably want to use 'encode' to
--- obtain a 512-bit (64-byte) 'ByteString'. May be used as a
+-- obtain a 512-bit (64-byte) 'B.ByteString'. May be used as a
-- drop-in replacement for SHA-512.
newtype Skein_1024_512 = S_1024_512 B.ByteString deriving (Eq, Ord)
@@ -406,12 +546,15 @@ instance Hash Skein_1024_512_Ctx Skein_1024_512 where
updateCtx = updateCtxSkein skein1024Update unS_1024_512_Ctx S_1024_512_Ctx
finalize = finalizeSkein 64 skein1024Update skein1024Final unS_1024_512_Ctx S_1024_512
+instance SkeinMAC Skein_1024_512_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 512 skein1024InitExt S_1024_512_Ctx
+
-- | Context of the Skein-1024-1024 hash function.
newtype Skein_1024_1024_Ctx = S_1024_1024_Ctx {unS_1024_1024_Ctx :: Skein1024Ctx}
-- | Skein-1024-1024 hash. You probably want to use 'encode' to
--- obtain a 1024-bit (128-byte) 'ByteString'. This is the
+-- obtain a 1024-bit (128-byte) 'B.ByteString'. This is the
-- ultra-conservative variant. Even if some future attack
-- managed to break Skein-512, it's quite likely that Skein-1024
-- would remain secure.
@@ -427,3 +570,6 @@ instance Hash Skein_1024_1024_Ctx Skein_1024_1024 where
initialCtx = initialCtxSkein 1024 skein1024Init S_1024_1024_Ctx
updateCtx = updateCtxSkein skein1024Update unS_1024_1024_Ctx S_1024_1024_Ctx
finalize = finalizeSkein 128 skein1024Update skein1024Final unS_1024_1024_Ctx S_1024_1024
+
+instance SkeinMAC Skein_1024_1024_Ctx where
+ skeinMACCtx = skeinMACCtxSkein 1024 skein1024InitExt S_1024_1024_Ctx
View
7 src/Crypto/Skein/Internal.hsc
@@ -51,6 +51,9 @@ module Crypto.Skein.Internal
, skein1024InitExt
, skein1024FinalPad
, skein1024Output
+
+ -- * Misc constants
+ , sKEIN_SEQUENTIAL
) where
-- from base
@@ -144,3 +147,7 @@ foreign import ccall unsafe "skein.h Skein_256_Output" skein256Output :: Ptr Sk
foreign import ccall unsafe "skein.h Skein_512_Output" skein512Output :: Ptr Skein512Ctx -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "skein.h Skein1024_Output" skein1024Output :: Ptr Skein1024Ctx -> Ptr Word8 -> IO CInt
+
+-- | Pass to @InitExt@ to get sequential processing.
+sKEIN_SEQUENTIAL :: Word64
+sKEIN_SEQUENTIAL = 0
Please sign in to comment.
Something went wrong with that request. Please try again.