From c0c33c525448151f0fba4d6ff671212c3d823c92 Mon Sep 17 00:00:00 2001 From: Nicolas DI PRIMA Date: Mon, 13 Mar 2017 00:24:17 +0000 Subject: [PATCH] Use Nat for the Blake2's digest sizes --- Crypto/Hash/Algorithms.hs | 3 + Crypto/Hash/Blake2.hs | 151 ++++++++++++++++++++++++++++++++++++++ cryptonite.cabal | 1 + 3 files changed, 155 insertions(+) create mode 100644 Crypto/Hash/Blake2.hs diff --git a/Crypto/Hash/Algorithms.hs b/Crypto/Hash/Algorithms.hs index 45ee759..fdf52f4 100644 --- a/Crypto/Hash/Algorithms.hs +++ b/Crypto/Hash/Algorithms.hs @@ -45,6 +45,8 @@ module Crypto.Hash.Algorithms #if MIN_VERSION_base(4,7,0) , SHAKE128(..) , SHAKE256(..) + , Blake2b(..), Blake2bp(..) + , Blake2s(..), Blake2sp(..) #endif , Skein256_224(..) , Skein256_256(..) @@ -78,4 +80,5 @@ import Crypto.Hash.Skein512 import Crypto.Hash.Whirlpool #if MIN_VERSION_base(4,7,0) import Crypto.Hash.SHAKE +import Crypto.Hash.Blake2 #endif diff --git a/Crypto/Hash/Blake2.hs b/Crypto/Hash/Blake2.hs new file mode 100644 index 0000000..b957fa3 --- /dev/null +++ b/Crypto/Hash/Blake2.hs @@ -0,0 +1,151 @@ +-- | +-- Module : Crypto.Hash.Blake2 +-- License : BSD-style +-- Maintainer : Nicolas Di Prima +-- Stability : experimental +-- Portability : unknown +-- +-- module containing the binding functions to work with the +-- Blake2 +-- +-- Implementation based from [RFC7693](https://tools.ietf.org/html/rfc7693) +-- +-- Please consider the following when chosing a hash: +-- +-- Algorithm | Target | Collision | Digest Size | +-- Identifier | Arch | Security | in bytes | +-- ---------------+--------+-----------+-------------+ +-- id-blake2b160 | 64-bit | 2**80 | 20 | +-- id-blake2b256 | 64-bit | 2**128 | 32 | +-- id-blake2b384 | 64-bit | 2**192 | 48 | +-- id-blake2b512 | 64-bit | 2**256 | 64 | +-- ---------------+--------+-----------+-------------+ +-- id-blake2s128 | 32-bit | 2**64 | 16 | +-- id-blake2s160 | 32-bit | 2**80 | 20 | +-- id-blake2s224 | 32-bit | 2**112 | 28 | +-- id-blake2s256 | 32-bit | 2**128 | 32 | +-- ---------------+--------+-----------+-------------+ +-- +{-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TypeFamilies #-} +module Crypto.Hash.Blake2 + ( Blake2s(..) + , Blake2sp(..) + , Blake2b(..) + , Blake2bp(..) + ) where + +import Crypto.Hash.Types +import Foreign.Ptr (Ptr) +import Data.Data +import Data.Typeable +import Data.Word (Word8, Word32) +import GHC.TypeLits (Nat, KnownNat, natVal) +import Crypto.Internal.Nat + +-- | Fast and secure alternative to SHA1 and HMAC-SHA1 +-- +-- It is espacially known to target 32bits architectures. +-- +-- known supported digest sizes: +-- +-- * Blake2s 160 +-- * Blake2s 224 +-- * Blake2s 256 +-- +data Blake2s (bitlen :: Nat) = Blake2s + deriving (Show, Typeable) + +instance (IsDivisibleBy8 bitlen, KnownNat bitlen) + => HashAlgorithm (Blake2s bitlen) + where + hashBlockSize _ = 64 + hashDigestSize _ = byteLen (Proxy :: Proxy bitlen) + hashInternalContextSize _ = 185 + hashInternalInit p = c_blake2s_init p (integralNatVal (Proxy :: Proxy bitlen)) + hashInternalUpdate = c_blake2s_update + hashInternalFinalize p = c_blake2s_finalize p (integralNatVal (Proxy :: Proxy bitlen)) + +foreign import ccall unsafe "cryptonite_blake2s_init" + c_blake2s_init :: Ptr (Context a) -> Word32 -> IO () +foreign import ccall "cryptonite_blake2s_update" + c_blake2s_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO () +foreign import ccall unsafe "cryptonite_blake2s_finalize" + c_blake2s_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () + +-- | Fast cryptographic hash. +-- +-- It is especially known to target 64bits architectures. +-- +-- Known supported digest sizes: +-- +-- * Blake2b 160 +-- * Blake2b 224 +-- * Blake2b 256 +-- * Blake2b 384 +-- * Blake2b 512 +-- +data Blake2b (bitlen :: Nat) = Blake2b + deriving (Show, Typeable) + +instance (IsDivisibleBy8 bitlen, KnownNat bitlen) + => HashAlgorithm (Blake2b bitlen) + where + hashBlockSize _ = 128 + hashDigestSize _ = byteLen (Proxy :: Proxy bitlen) + hashInternalContextSize _ = 361 + hashInternalInit p = c_blake2b_init p (integralNatVal (Proxy :: Proxy bitlen)) + hashInternalUpdate = c_blake2b_update + hashInternalFinalize p = c_blake2b_finalize p (integralNatVal (Proxy :: Proxy bitlen)) + +foreign import ccall unsafe "cryptonite_blake2b_init" + c_blake2b_init :: Ptr (Context a) -> Word32 -> IO () +foreign import ccall "cryptonite_blake2b_update" + c_blake2b_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO () +foreign import ccall unsafe "cryptonite_blake2b_finalize" + c_blake2b_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () + +data Blake2sp (bitlen :: Nat) = Blake2sp + deriving (Show, Typeable) + +instance (IsDivisibleBy8 bitlen, KnownNat bitlen) + => HashAlgorithm (Blake2sp bitlen) + where + hashBlockSize _ = 64 + hashDigestSize _ = byteLen (Proxy :: Proxy bitlen) + hashInternalContextSize _ = 2185 + hashInternalInit p = c_blake2sp_init p (integralNatVal (Proxy :: Proxy bitlen)) + hashInternalUpdate = c_blake2sp_update + hashInternalFinalize p = c_blake2sp_finalize p (integralNatVal (Proxy :: Proxy bitlen)) + +foreign import ccall unsafe "cryptonite_blake2sp_init" + c_blake2sp_init :: Ptr (Context a) -> Word32 -> IO () +foreign import ccall "cryptonite_blake2sp_update" + c_blake2sp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO () +foreign import ccall unsafe "cryptonite_blake2sp_finalize" + c_blake2sp_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () + +data Blake2bp (bitlen :: Nat) = Blake2bp + deriving (Show, Typeable) + +instance (IsDivisibleBy8 bitlen, KnownNat bitlen) + => HashAlgorithm (Blake2bp bitlen) + where + hashBlockSize _ = 128 + hashDigestSize _ = byteLen (Proxy :: Proxy bitlen) + hashInternalContextSize _ = 2325 + hashInternalInit p = c_blake2bp_init p (integralNatVal (Proxy :: Proxy bitlen)) + hashInternalUpdate = c_blake2bp_update + hashInternalFinalize p = c_blake2bp_finalize p (integralNatVal (Proxy :: Proxy bitlen)) + + +foreign import ccall unsafe "cryptonite_blake2bp_init" + c_blake2bp_init :: Ptr (Context a) -> Word32 -> IO () +foreign import ccall "cryptonite_blake2bp_update" + c_blake2bp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO () +foreign import ccall unsafe "cryptonite_blake2bp_finalize" + c_blake2bp_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () diff --git a/cryptonite.cabal b/cryptonite.cabal index 9569a18..f074eb3 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -213,6 +213,7 @@ Library Crypto.Internal.WordArray if impl(ghc >= 7.8) Other-modules: Crypto.Hash.SHAKE + Crypto.Hash.Blake2 Crypto.Internal.Nat Build-depends: base >= 4.3 && < 5 , bytestring