Merge pull request #325 from ocheron/hash-ct
Hashing independent from input length
This commit is contained in:
commit
9eadf707c4
@ -28,14 +28,17 @@ module Crypto.Hash
|
|||||||
-- * Hash methods parametrized by algorithm
|
-- * Hash methods parametrized by algorithm
|
||||||
, hashInitWith
|
, hashInitWith
|
||||||
, hashWith
|
, hashWith
|
||||||
|
, hashPrefixWith
|
||||||
-- * Hash methods
|
-- * Hash methods
|
||||||
, hashInit
|
, hashInit
|
||||||
, hashUpdates
|
, hashUpdates
|
||||||
, hashUpdate
|
, hashUpdate
|
||||||
, hashFinalize
|
, hashFinalize
|
||||||
|
, hashFinalizePrefix
|
||||||
, hashBlockSize
|
, hashBlockSize
|
||||||
, hashDigestSize
|
, hashDigestSize
|
||||||
, hash
|
, hash
|
||||||
|
, hashPrefix
|
||||||
, hashlazy
|
, hashlazy
|
||||||
-- * Hash algorithms
|
-- * Hash algorithms
|
||||||
, module Crypto.Hash.Algorithms
|
, module Crypto.Hash.Algorithms
|
||||||
@ -57,6 +60,10 @@ import Data.Word (Word8)
|
|||||||
hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a
|
hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a
|
||||||
hash bs = hashFinalize $ hashUpdate hashInit bs
|
hash bs = hashFinalize $ hashUpdate hashInit bs
|
||||||
|
|
||||||
|
-- | Hash the first N bytes of a bytestring, with code path independent from N.
|
||||||
|
hashPrefix :: (ByteArrayAccess ba, HashAlgorithmPrefix a) => ba -> Int -> Digest a
|
||||||
|
hashPrefix = hashFinalizePrefix hashInit
|
||||||
|
|
||||||
-- | Hash a lazy bytestring into a digest.
|
-- | Hash a lazy bytestring into a digest.
|
||||||
hashlazy :: HashAlgorithm a => L.ByteString -> Digest a
|
hashlazy :: HashAlgorithm a => L.ByteString -> Digest a
|
||||||
hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs)
|
hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs)
|
||||||
@ -94,6 +101,24 @@ hashFinalize !c =
|
|||||||
((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
|
((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
-- | Update the context with the first N bytes of a bytestring and return the
|
||||||
|
-- digest. The code path is independent from N but much slower than a normal
|
||||||
|
-- 'hashUpdate'. The function can be called for the last bytes of a message, in
|
||||||
|
-- order to exclude a variable padding, without leaking the padding length. The
|
||||||
|
-- begining of the message, never impacted by the padding, should preferably go
|
||||||
|
-- through 'hashUpdate' for better performance.
|
||||||
|
hashFinalizePrefix :: forall a ba . (HashAlgorithmPrefix a, ByteArrayAccess ba)
|
||||||
|
=> Context a
|
||||||
|
-> ba
|
||||||
|
-> Int
|
||||||
|
-> Digest a
|
||||||
|
hashFinalizePrefix !c b len =
|
||||||
|
Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) -> do
|
||||||
|
((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) ->
|
||||||
|
B.withByteArray b $ \d ->
|
||||||
|
hashInternalFinalizePrefix ctx d (fromIntegral $ B.length b) (fromIntegral len) dig
|
||||||
|
return ()
|
||||||
|
|
||||||
-- | Initialize a new context for a specified hash algorithm
|
-- | Initialize a new context for a specified hash algorithm
|
||||||
hashInitWith :: HashAlgorithm alg => alg -> Context alg
|
hashInitWith :: HashAlgorithm alg => alg -> Context alg
|
||||||
hashInitWith _ = hashInit
|
hashInitWith _ = hashInit
|
||||||
@ -102,6 +127,10 @@ hashInitWith _ = hashInit
|
|||||||
hashWith :: (ByteArrayAccess ba, HashAlgorithm alg) => alg -> ba -> Digest alg
|
hashWith :: (ByteArrayAccess ba, HashAlgorithm alg) => alg -> ba -> Digest alg
|
||||||
hashWith _ = hash
|
hashWith _ = hash
|
||||||
|
|
||||||
|
-- | Run the 'hashPrefix' function but takes an explicit hash algorithm parameter
|
||||||
|
hashPrefixWith :: (ByteArrayAccess ba, HashAlgorithmPrefix alg) => alg -> ba -> Int -> Digest alg
|
||||||
|
hashPrefixWith _ = hashPrefix
|
||||||
|
|
||||||
-- | Try to transform a bytearray into a Digest of specific algorithm.
|
-- | Try to transform a bytearray into a Digest of specific algorithm.
|
||||||
--
|
--
|
||||||
-- If the digest is not the right size for the algorithm specified, then
|
-- If the digest is not the right size for the algorithm specified, then
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
--
|
--
|
||||||
module Crypto.Hash.Algorithms
|
module Crypto.Hash.Algorithms
|
||||||
( HashAlgorithm
|
( HashAlgorithm
|
||||||
|
, HashAlgorithmPrefix
|
||||||
-- * Hash algorithms
|
-- * Hash algorithms
|
||||||
, Blake2s_160(..)
|
, Blake2s_160(..)
|
||||||
, Blake2s_224(..)
|
, Blake2s_224(..)
|
||||||
@ -54,7 +55,7 @@ module Crypto.Hash.Algorithms
|
|||||||
, Whirlpool(..)
|
, Whirlpool(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Crypto.Hash.Types (HashAlgorithm)
|
import Crypto.Hash.Types (HashAlgorithm, HashAlgorithmPrefix)
|
||||||
import Crypto.Hash.Blake2s
|
import Crypto.Hash.Blake2s
|
||||||
import Crypto.Hash.Blake2sp
|
import Crypto.Hash.Blake2sp
|
||||||
import Crypto.Hash.Blake2b
|
import Crypto.Hash.Blake2b
|
||||||
|
|||||||
@ -34,6 +34,9 @@ instance HashAlgorithm MD5 where
|
|||||||
hashInternalUpdate = c_md5_update
|
hashInternalUpdate = c_md5_update
|
||||||
hashInternalFinalize = c_md5_finalize
|
hashInternalFinalize = c_md5_finalize
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix MD5 where
|
||||||
|
hashInternalFinalizePrefix = c_md5_finalize_prefix
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_md5_init"
|
foreign import ccall unsafe "cryptonite_md5_init"
|
||||||
c_md5_init :: Ptr (Context a)-> IO ()
|
c_md5_init :: Ptr (Context a)-> IO ()
|
||||||
|
|
||||||
@ -42,3 +45,6 @@ foreign import ccall "cryptonite_md5_update"
|
|||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_md5_finalize"
|
foreign import ccall unsafe "cryptonite_md5_finalize"
|
||||||
c_md5_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_md5_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_md5_finalize_prefix"
|
||||||
|
c_md5_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()
|
||||||
|
|||||||
@ -34,6 +34,9 @@ instance HashAlgorithm SHA1 where
|
|||||||
hashInternalUpdate = c_sha1_update
|
hashInternalUpdate = c_sha1_update
|
||||||
hashInternalFinalize = c_sha1_finalize
|
hashInternalFinalize = c_sha1_finalize
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix SHA1 where
|
||||||
|
hashInternalFinalizePrefix = c_sha1_finalize_prefix
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha1_init"
|
foreign import ccall unsafe "cryptonite_sha1_init"
|
||||||
c_sha1_init :: Ptr (Context a)-> IO ()
|
c_sha1_init :: Ptr (Context a)-> IO ()
|
||||||
|
|
||||||
@ -42,3 +45,6 @@ foreign import ccall "cryptonite_sha1_update"
|
|||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha1_finalize"
|
foreign import ccall unsafe "cryptonite_sha1_finalize"
|
||||||
c_sha1_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_sha1_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_sha1_finalize_prefix"
|
||||||
|
c_sha1_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()
|
||||||
|
|||||||
@ -34,6 +34,9 @@ instance HashAlgorithm SHA224 where
|
|||||||
hashInternalUpdate = c_sha224_update
|
hashInternalUpdate = c_sha224_update
|
||||||
hashInternalFinalize = c_sha224_finalize
|
hashInternalFinalize = c_sha224_finalize
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix SHA224 where
|
||||||
|
hashInternalFinalizePrefix = c_sha224_finalize_prefix
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha224_init"
|
foreign import ccall unsafe "cryptonite_sha224_init"
|
||||||
c_sha224_init :: Ptr (Context a)-> IO ()
|
c_sha224_init :: Ptr (Context a)-> IO ()
|
||||||
|
|
||||||
@ -42,3 +45,6 @@ foreign import ccall "cryptonite_sha224_update"
|
|||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha224_finalize"
|
foreign import ccall unsafe "cryptonite_sha224_finalize"
|
||||||
c_sha224_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_sha224_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_sha224_finalize_prefix"
|
||||||
|
c_sha224_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()
|
||||||
|
|||||||
@ -34,6 +34,9 @@ instance HashAlgorithm SHA256 where
|
|||||||
hashInternalUpdate = c_sha256_update
|
hashInternalUpdate = c_sha256_update
|
||||||
hashInternalFinalize = c_sha256_finalize
|
hashInternalFinalize = c_sha256_finalize
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix SHA256 where
|
||||||
|
hashInternalFinalizePrefix = c_sha256_finalize_prefix
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha256_init"
|
foreign import ccall unsafe "cryptonite_sha256_init"
|
||||||
c_sha256_init :: Ptr (Context a)-> IO ()
|
c_sha256_init :: Ptr (Context a)-> IO ()
|
||||||
|
|
||||||
@ -42,3 +45,6 @@ foreign import ccall "cryptonite_sha256_update"
|
|||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha256_finalize"
|
foreign import ccall unsafe "cryptonite_sha256_finalize"
|
||||||
c_sha256_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_sha256_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_sha256_finalize_prefix"
|
||||||
|
c_sha256_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()
|
||||||
|
|||||||
@ -34,6 +34,9 @@ instance HashAlgorithm SHA384 where
|
|||||||
hashInternalUpdate = c_sha384_update
|
hashInternalUpdate = c_sha384_update
|
||||||
hashInternalFinalize = c_sha384_finalize
|
hashInternalFinalize = c_sha384_finalize
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix SHA384 where
|
||||||
|
hashInternalFinalizePrefix = c_sha384_finalize_prefix
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha384_init"
|
foreign import ccall unsafe "cryptonite_sha384_init"
|
||||||
c_sha384_init :: Ptr (Context a)-> IO ()
|
c_sha384_init :: Ptr (Context a)-> IO ()
|
||||||
|
|
||||||
@ -42,3 +45,6 @@ foreign import ccall "cryptonite_sha384_update"
|
|||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha384_finalize"
|
foreign import ccall unsafe "cryptonite_sha384_finalize"
|
||||||
c_sha384_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_sha384_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_sha384_finalize_prefix"
|
||||||
|
c_sha384_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()
|
||||||
|
|||||||
@ -34,6 +34,9 @@ instance HashAlgorithm SHA512 where
|
|||||||
hashInternalUpdate = c_sha512_update
|
hashInternalUpdate = c_sha512_update
|
||||||
hashInternalFinalize = c_sha512_finalize
|
hashInternalFinalize = c_sha512_finalize
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix SHA512 where
|
||||||
|
hashInternalFinalizePrefix = c_sha512_finalize_prefix
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha512_init"
|
foreign import ccall unsafe "cryptonite_sha512_init"
|
||||||
c_sha512_init :: Ptr (Context a)-> IO ()
|
c_sha512_init :: Ptr (Context a)-> IO ()
|
||||||
|
|
||||||
@ -42,3 +45,6 @@ foreign import ccall "cryptonite_sha512_update"
|
|||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_sha512_finalize"
|
foreign import ccall unsafe "cryptonite_sha512_finalize"
|
||||||
c_sha512_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_sha512_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_sha512_finalize_prefix"
|
||||||
|
c_sha512_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
module Crypto.Hash.Types
|
module Crypto.Hash.Types
|
||||||
( HashAlgorithm(..)
|
( HashAlgorithm(..)
|
||||||
|
, HashAlgorithmPrefix(..)
|
||||||
, Context(..)
|
, Context(..)
|
||||||
, Digest(..)
|
, Digest(..)
|
||||||
) where
|
) where
|
||||||
@ -59,6 +60,17 @@ class HashAlgorithm a where
|
|||||||
-- | Finalize the context and set the digest raw memory to the right value
|
-- | Finalize the context and set the digest raw memory to the right value
|
||||||
hashInternalFinalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
hashInternalFinalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
||||||
|
|
||||||
|
-- | Hashing algorithms with a constant-time implementation.
|
||||||
|
class HashAlgorithm a => HashAlgorithmPrefix a where
|
||||||
|
-- | Update the context with the first N bytes of a buffer and finalize this
|
||||||
|
-- context. The code path executed is independent from N and depends only
|
||||||
|
-- on the complete buffer length.
|
||||||
|
hashInternalFinalizePrefix :: Ptr (Context a)
|
||||||
|
-> Ptr Word8 -> Word32
|
||||||
|
-> Word32
|
||||||
|
-> Ptr (Digest a)
|
||||||
|
-> IO ()
|
||||||
|
|
||||||
{-
|
{-
|
||||||
hashContextGetAlgorithm :: HashAlgorithm a => Context a -> a
|
hashContextGetAlgorithm :: HashAlgorithm a => Context a -> a
|
||||||
hashContextGetAlgorithm = undefined
|
hashContextGetAlgorithm = undefined
|
||||||
|
|||||||
@ -44,11 +44,21 @@ static inline void store_le32_aligned(uint8_t *dst, const uint32_t v)
|
|||||||
*((uint32_t *) dst) = cpu_to_le32(v);
|
*((uint32_t *) dst) = cpu_to_le32(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void xor_le32_aligned(uint8_t *dst, const uint32_t v)
|
||||||
|
{
|
||||||
|
*((uint32_t *) dst) ^= cpu_to_le32(v);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void store_be32_aligned(uint8_t *dst, const uint32_t v)
|
static inline void store_be32_aligned(uint8_t *dst, const uint32_t v)
|
||||||
{
|
{
|
||||||
*((uint32_t *) dst) = cpu_to_be32(v);
|
*((uint32_t *) dst) = cpu_to_be32(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void xor_be32_aligned(uint8_t *dst, const uint32_t v)
|
||||||
|
{
|
||||||
|
*((uint32_t *) dst) ^= cpu_to_be32(v);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void store_le64_aligned(uint8_t *dst, const uint64_t v)
|
static inline void store_le64_aligned(uint8_t *dst, const uint64_t v)
|
||||||
{
|
{
|
||||||
*((uint64_t *) dst) = cpu_to_le64(v);
|
*((uint64_t *) dst) = cpu_to_le64(v);
|
||||||
@ -59,6 +69,11 @@ static inline void store_be64_aligned(uint8_t *dst, const uint64_t v)
|
|||||||
*((uint64_t *) dst) = cpu_to_be64(v);
|
*((uint64_t *) dst) = cpu_to_be64(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void xor_be64_aligned(uint8_t *dst, const uint64_t v)
|
||||||
|
{
|
||||||
|
*((uint64_t *) dst) ^= cpu_to_be64(v);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef UNALIGNED_ACCESS_OK
|
#ifdef UNALIGNED_ACCESS_OK
|
||||||
#define load_le32(a) load_le32_aligned(a)
|
#define load_le32(a) load_le32_aligned(a)
|
||||||
#else
|
#else
|
||||||
@ -70,20 +85,30 @@ static inline uint32_t load_le32(const uint8_t *p)
|
|||||||
|
|
||||||
#ifdef UNALIGNED_ACCESS_OK
|
#ifdef UNALIGNED_ACCESS_OK
|
||||||
#define store_le32(a, b) store_le32_aligned(a, b)
|
#define store_le32(a, b) store_le32_aligned(a, b)
|
||||||
|
#define xor_le32(a, b) xor_le32_aligned(a, b)
|
||||||
#else
|
#else
|
||||||
static inline void store_le32(uint8_t *dst, const uint32_t v)
|
static inline void store_le32(uint8_t *dst, const uint32_t v)
|
||||||
{
|
{
|
||||||
dst[0] = v; dst[1] = v >> 8; dst[2] = v >> 16; dst[3] = v >> 24;
|
dst[0] = v; dst[1] = v >> 8; dst[2] = v >> 16; dst[3] = v >> 24;
|
||||||
}
|
}
|
||||||
|
static inline void xor_le32(uint8_t *dst, const uint32_t v)
|
||||||
|
{
|
||||||
|
dst[0] ^= v; dst[1] ^= v >> 8; dst[2] ^= v >> 16; dst[3] ^= v >> 24;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UNALIGNED_ACCESS_OK
|
#ifdef UNALIGNED_ACCESS_OK
|
||||||
#define store_be32(a, b) store_be32_aligned(a, b)
|
#define store_be32(a, b) store_be32_aligned(a, b)
|
||||||
|
#define xor_be32(a, b) xor_be32_aligned(a, b)
|
||||||
#else
|
#else
|
||||||
static inline void store_be32(uint8_t *dst, const uint32_t v)
|
static inline void store_be32(uint8_t *dst, const uint32_t v)
|
||||||
{
|
{
|
||||||
dst[3] = v; dst[2] = v >> 8; dst[1] = v >> 16; dst[0] = v >> 24;
|
dst[3] = v; dst[2] = v >> 8; dst[1] = v >> 16; dst[0] = v >> 24;
|
||||||
}
|
}
|
||||||
|
static inline void xor_be32(uint8_t *dst, const uint32_t v)
|
||||||
|
{
|
||||||
|
dst[3] ^= v; dst[2] ^= v >> 8; dst[1] ^= v >> 16; dst[0] ^= v >> 24;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UNALIGNED_ACCESS_OK
|
#ifdef UNALIGNED_ACCESS_OK
|
||||||
@ -98,12 +123,18 @@ static inline void store_le64(uint8_t *dst, const uint64_t v)
|
|||||||
|
|
||||||
#ifdef UNALIGNED_ACCESS_OK
|
#ifdef UNALIGNED_ACCESS_OK
|
||||||
#define store_be64(a, b) store_be64_aligned(a, b)
|
#define store_be64(a, b) store_be64_aligned(a, b)
|
||||||
|
#define xor_be64(a, b) xor_be64_aligned(a, b)
|
||||||
#else
|
#else
|
||||||
static inline void store_be64(uint8_t *dst, const uint64_t v)
|
static inline void store_be64(uint8_t *dst, const uint64_t v)
|
||||||
{
|
{
|
||||||
dst[7] = v ; dst[6] = v >> 8 ; dst[5] = v >> 16; dst[4] = v >> 24;
|
dst[7] = v ; dst[6] = v >> 8 ; dst[5] = v >> 16; dst[4] = v >> 24;
|
||||||
dst[3] = v >> 32; dst[2] = v >> 40; dst[1] = v >> 48; dst[0] = v >> 56;
|
dst[3] = v >> 32; dst[2] = v >> 40; dst[1] = v >> 48; dst[0] = v >> 56;
|
||||||
}
|
}
|
||||||
|
static inline void xor_be64(uint8_t *dst, const uint64_t v)
|
||||||
|
{
|
||||||
|
dst[7] ^= v ; dst[6] ^= v >> 8 ; dst[5] ^= v >> 16; dst[4] ^= v >> 24;
|
||||||
|
dst[3] ^= v >> 32; dst[2] ^= v >> 40; dst[1] ^= v >> 48; dst[0] ^= v >> 56;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
90
cbits/cryptonite_hash_prefix.c
Normal file
90
cbits/cryptonite_hash_prefix.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Olivier Chéron <olivier.cheron@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. 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.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cryptonite_hash_prefix.h>
|
||||||
|
|
||||||
|
void CRYPTONITE_HASHED(finalize_prefix)(struct HASHED_LOWER(ctx) *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out)
|
||||||
|
{
|
||||||
|
uint64_t bits[HASHED(BITS_ELEMS)];
|
||||||
|
uint8_t *p = (uint8_t *) &bits;
|
||||||
|
uint32_t index, padidx, padlen, pos, out_mask;
|
||||||
|
static const uint32_t cut_off = HASHED(BLOCK_SIZE) - sizeof(bits);
|
||||||
|
|
||||||
|
/* Make sure n <= len */
|
||||||
|
n += (len - n) & constant_time_lt(len, n);
|
||||||
|
|
||||||
|
/* Initial index, based on current context state */
|
||||||
|
index = CRYPTONITE_HASHED(get_index)(ctx);
|
||||||
|
|
||||||
|
/* Final size after n bytes */
|
||||||
|
CRYPTONITE_HASHED(incr_sz)(ctx, bits, n);
|
||||||
|
|
||||||
|
/* Padding index and length */
|
||||||
|
padidx = CRYPTONITE_HASHED(get_index)(ctx);
|
||||||
|
padlen = HASHED(BLOCK_SIZE) + cut_off - padidx;
|
||||||
|
padlen -= HASHED(BLOCK_SIZE) & constant_time_lt(padidx, cut_off);
|
||||||
|
|
||||||
|
/* Initialize buffers because we will XOR into them */
|
||||||
|
memset(ctx->buf + index, 0, HASHED(BLOCK_SIZE) - index);
|
||||||
|
memset(out, 0, HASHED(DIGEST_SIZE));
|
||||||
|
pos = 0;
|
||||||
|
|
||||||
|
/* Iterate based on the full buffer length, regardless of n, and include
|
||||||
|
* the maximum overhead with padding and size bytes
|
||||||
|
*/
|
||||||
|
while (pos < len + HASHED(BLOCK_SIZE) + sizeof(bits)) {
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
/* Take as many bytes from the input buffer as possible */
|
||||||
|
if (pos < len)
|
||||||
|
b = *(data++) & (uint8_t) constant_time_lt(pos, n);
|
||||||
|
else
|
||||||
|
b = 0;
|
||||||
|
|
||||||
|
/* First padding byte */
|
||||||
|
b |= 0x80 & (uint8_t) constant_time_eq(pos, n);
|
||||||
|
|
||||||
|
/* Size bytes are always at the end of a block */
|
||||||
|
if (index >= cut_off)
|
||||||
|
b |= p[index - cut_off] & (uint8_t) constant_time_ge(pos, n + padlen);
|
||||||
|
|
||||||
|
/* Store this byte into the buffer */
|
||||||
|
ctx->buf[index++] ^= b;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
/* Process a full block, at a boundary which is independent from n */
|
||||||
|
if (index >= HASHED(BLOCK_SIZE)) {
|
||||||
|
index = 0;
|
||||||
|
HASHED_LOWER(do_chunk)(ctx, (void *) ctx->buf);
|
||||||
|
memset(ctx->buf, 0, HASHED(BLOCK_SIZE));
|
||||||
|
|
||||||
|
/* Try to store the result: this is a no-op except when we reach the
|
||||||
|
* actual size based on n, more iterations may continue after that
|
||||||
|
* when len is really larger
|
||||||
|
*/
|
||||||
|
out_mask = constant_time_eq(pos, n + padlen + sizeof(bits));
|
||||||
|
CRYPTONITE_HASHED(select_digest)(ctx, out, out_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
cbits/cryptonite_hash_prefix.h
Normal file
65
cbits/cryptonite_hash_prefix.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Olivier Chéron <olivier.cheron@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. 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.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRYPTONITE_HASH_PREFIX_H
|
||||||
|
#define CRYPTONITE_HASH_PREFIX_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static inline uint32_t constant_time_msb(uint32_t a)
|
||||||
|
{
|
||||||
|
return 0 - (a >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t constant_time_lt(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t constant_time_ge(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
return ~constant_time_lt(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t constant_time_is_zero(uint32_t a)
|
||||||
|
{
|
||||||
|
return constant_time_msb(~a & (a - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t constant_time_eq(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
return constant_time_is_zero(a ^ b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t constant_time_msb_64(uint64_t a)
|
||||||
|
{
|
||||||
|
return 0 - (a >> 63);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)
|
||||||
|
{
|
||||||
|
return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -185,3 +185,30 @@ void cryptonite_md5_finalize(struct md5_ctx *ctx, uint8_t *out)
|
|||||||
store_le32(out+ 8, ctx->h[2]);
|
store_le32(out+ 8, ctx->h[2]);
|
||||||
store_le32(out+12, ctx->h[3]);
|
store_le32(out+12, ctx->h[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HASHED(m) MD5_##m
|
||||||
|
#define HASHED_LOWER(m) md5_##m
|
||||||
|
#define CRYPTONITE_HASHED(m) cryptonite_md5_##m
|
||||||
|
#define MD5_BLOCK_SIZE 64
|
||||||
|
#define MD5_BITS_ELEMS 1
|
||||||
|
|
||||||
|
static inline uint32_t cryptonite_md5_get_index(const struct md5_ctx *ctx)
|
||||||
|
{
|
||||||
|
return (uint32_t) (ctx->sz & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_md5_incr_sz(struct md5_ctx *ctx, uint64_t *bits, uint32_t n)
|
||||||
|
{
|
||||||
|
ctx->sz += n;
|
||||||
|
*bits = cpu_to_le64(ctx->sz << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_md5_select_digest(const struct md5_ctx *ctx, uint8_t *out, uint32_t out_mask)
|
||||||
|
{
|
||||||
|
xor_le32(out , ctx->h[0] & out_mask);
|
||||||
|
xor_le32(out+ 4, ctx->h[1] & out_mask);
|
||||||
|
xor_le32(out+ 8, ctx->h[2] & out_mask);
|
||||||
|
xor_le32(out+12, ctx->h[3] & out_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cryptonite_hash_prefix.c>
|
||||||
|
|||||||
@ -39,5 +39,6 @@ struct md5_ctx
|
|||||||
void cryptonite_md5_init(struct md5_ctx *ctx);
|
void cryptonite_md5_init(struct md5_ctx *ctx);
|
||||||
void cryptonite_md5_update(struct md5_ctx *ctx, const uint8_t *data, uint32_t len);
|
void cryptonite_md5_update(struct md5_ctx *ctx, const uint8_t *data, uint32_t len);
|
||||||
void cryptonite_md5_finalize(struct md5_ctx *ctx, uint8_t *out);
|
void cryptonite_md5_finalize(struct md5_ctx *ctx, uint8_t *out);
|
||||||
|
void cryptonite_md5_finalize_prefix(struct md5_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -216,3 +216,31 @@ void cryptonite_sha1_finalize(struct sha1_ctx *ctx, uint8_t *out)
|
|||||||
store_be32(out+12, ctx->h[3]);
|
store_be32(out+12, ctx->h[3]);
|
||||||
store_be32(out+16, ctx->h[4]);
|
store_be32(out+16, ctx->h[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HASHED(m) SHA1_##m
|
||||||
|
#define HASHED_LOWER(m) sha1_##m
|
||||||
|
#define CRYPTONITE_HASHED(m) cryptonite_sha1_##m
|
||||||
|
#define SHA1_BLOCK_SIZE 64
|
||||||
|
#define SHA1_BITS_ELEMS 1
|
||||||
|
|
||||||
|
static inline uint32_t cryptonite_sha1_get_index(const struct sha1_ctx *ctx)
|
||||||
|
{
|
||||||
|
return (uint32_t) (ctx->sz & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_sha1_incr_sz(struct sha1_ctx *ctx, uint64_t *bits, uint32_t n)
|
||||||
|
{
|
||||||
|
ctx->sz += n;
|
||||||
|
*bits = cpu_to_be64(ctx->sz << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_sha1_select_digest(const struct sha1_ctx *ctx, uint8_t *out, uint32_t out_mask)
|
||||||
|
{
|
||||||
|
xor_be32(out , ctx->h[0] & out_mask);
|
||||||
|
xor_be32(out+ 4, ctx->h[1] & out_mask);
|
||||||
|
xor_be32(out+ 8, ctx->h[2] & out_mask);
|
||||||
|
xor_be32(out+12, ctx->h[3] & out_mask);
|
||||||
|
xor_be32(out+16, ctx->h[4] & out_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cryptonite_hash_prefix.c>
|
||||||
|
|||||||
@ -41,5 +41,6 @@ struct sha1_ctx
|
|||||||
void cryptonite_sha1_init(struct sha1_ctx *ctx);
|
void cryptonite_sha1_init(struct sha1_ctx *ctx);
|
||||||
void cryptonite_sha1_update(struct sha1_ctx *ctx, const uint8_t *data, uint32_t len);
|
void cryptonite_sha1_update(struct sha1_ctx *ctx, const uint8_t *data, uint32_t len);
|
||||||
void cryptonite_sha1_finalize(struct sha1_ctx *ctx, uint8_t *out);
|
void cryptonite_sha1_finalize(struct sha1_ctx *ctx, uint8_t *out);
|
||||||
|
void cryptonite_sha1_finalize_prefix(struct sha1_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -161,6 +161,14 @@ void cryptonite_sha224_finalize(struct sha224_ctx *ctx, uint8_t *out)
|
|||||||
memcpy(out, intermediate, SHA224_DIGEST_SIZE);
|
memcpy(out, intermediate, SHA224_DIGEST_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cryptonite_sha224_finalize_prefix(struct sha224_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out)
|
||||||
|
{
|
||||||
|
uint8_t intermediate[SHA256_DIGEST_SIZE];
|
||||||
|
|
||||||
|
cryptonite_sha256_finalize_prefix(ctx, data, len, n, intermediate);
|
||||||
|
memcpy(out, intermediate, SHA224_DIGEST_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
void cryptonite_sha256_finalize(struct sha256_ctx *ctx, uint8_t *out)
|
void cryptonite_sha256_finalize(struct sha256_ctx *ctx, uint8_t *out)
|
||||||
{
|
{
|
||||||
static uint8_t padding[64] = { 0x80, };
|
static uint8_t padding[64] = { 0x80, };
|
||||||
@ -182,3 +190,29 @@ void cryptonite_sha256_finalize(struct sha256_ctx *ctx, uint8_t *out)
|
|||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
store_be32(out+4*i, ctx->h[i]);
|
store_be32(out+4*i, ctx->h[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HASHED(m) SHA256_##m
|
||||||
|
#define HASHED_LOWER(m) sha256_##m
|
||||||
|
#define CRYPTONITE_HASHED(m) cryptonite_sha256_##m
|
||||||
|
#define SHA256_BLOCK_SIZE 64
|
||||||
|
#define SHA256_BITS_ELEMS 1
|
||||||
|
|
||||||
|
static inline uint32_t cryptonite_sha256_get_index(const struct sha256_ctx *ctx)
|
||||||
|
{
|
||||||
|
return (uint32_t) (ctx->sz & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_sha256_incr_sz(struct sha256_ctx *ctx, uint64_t *bits, uint32_t n)
|
||||||
|
{
|
||||||
|
ctx->sz += n;
|
||||||
|
*bits = cpu_to_be64(ctx->sz << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_sha256_select_digest(const struct sha256_ctx *ctx, uint8_t *out, uint32_t out_mask)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
xor_be32(out+4*i, ctx->h[i] & out_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cryptonite_hash_prefix.c>
|
||||||
|
|||||||
@ -47,9 +47,11 @@ struct sha256_ctx
|
|||||||
void cryptonite_sha224_init(struct sha224_ctx *ctx);
|
void cryptonite_sha224_init(struct sha224_ctx *ctx);
|
||||||
void cryptonite_sha224_update(struct sha224_ctx *ctx, const uint8_t *data, uint32_t len);
|
void cryptonite_sha224_update(struct sha224_ctx *ctx, const uint8_t *data, uint32_t len);
|
||||||
void cryptonite_sha224_finalize(struct sha224_ctx *ctx, uint8_t *out);
|
void cryptonite_sha224_finalize(struct sha224_ctx *ctx, uint8_t *out);
|
||||||
|
void cryptonite_sha224_finalize_prefix(struct sha224_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
|
||||||
|
|
||||||
void cryptonite_sha256_init(struct sha256_ctx *ctx);
|
void cryptonite_sha256_init(struct sha256_ctx *ctx);
|
||||||
void cryptonite_sha256_update(struct sha256_ctx *ctx, const uint8_t *data, uint32_t len);
|
void cryptonite_sha256_update(struct sha256_ctx *ctx, const uint8_t *data, uint32_t len);
|
||||||
void cryptonite_sha256_finalize(struct sha256_ctx *ctx, uint8_t *out);
|
void cryptonite_sha256_finalize(struct sha256_ctx *ctx, uint8_t *out);
|
||||||
|
void cryptonite_sha256_finalize_prefix(struct sha256_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -180,6 +180,14 @@ void cryptonite_sha384_finalize(struct sha384_ctx *ctx, uint8_t *out)
|
|||||||
memcpy(out, intermediate, SHA384_DIGEST_SIZE);
|
memcpy(out, intermediate, SHA384_DIGEST_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cryptonite_sha384_finalize_prefix(struct sha384_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out)
|
||||||
|
{
|
||||||
|
uint8_t intermediate[SHA512_DIGEST_SIZE];
|
||||||
|
|
||||||
|
cryptonite_sha512_finalize_prefix(ctx, data, len, n, intermediate);
|
||||||
|
memcpy(out, intermediate, SHA384_DIGEST_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
void cryptonite_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out)
|
void cryptonite_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out)
|
||||||
{
|
{
|
||||||
static uint8_t padding[128] = { 0x80, };
|
static uint8_t padding[128] = { 0x80, };
|
||||||
@ -203,6 +211,38 @@ void cryptonite_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out)
|
|||||||
store_be64(out+8*i, ctx->h[i]);
|
store_be64(out+8*i, ctx->h[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HASHED(m) SHA512_##m
|
||||||
|
#define HASHED_LOWER(m) sha512_##m
|
||||||
|
#define CRYPTONITE_HASHED(m) cryptonite_sha512_##m
|
||||||
|
#define SHA512_BLOCK_SIZE 128
|
||||||
|
#define SHA512_BITS_ELEMS 2
|
||||||
|
|
||||||
|
#include <cryptonite_hash_prefix.h>
|
||||||
|
|
||||||
|
static inline uint32_t cryptonite_sha512_get_index(const struct sha512_ctx *ctx)
|
||||||
|
{
|
||||||
|
return (uint32_t) (ctx->sz[0] & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_sha512_incr_sz(struct sha512_ctx *ctx, uint64_t *bits, uint32_t n)
|
||||||
|
{
|
||||||
|
ctx->sz[0] += n;
|
||||||
|
ctx->sz[1] += 1 & constant_time_lt_64(ctx->sz[0], n);
|
||||||
|
bits[0] = cpu_to_be64((ctx->sz[1] << 3 | ctx->sz[0] >> 61));
|
||||||
|
bits[1] = cpu_to_be64((ctx->sz[0] << 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cryptonite_sha512_select_digest(const struct sha512_ctx *ctx, uint8_t *out, uint32_t out_mask)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint64_t out_mask_64 = out_mask;
|
||||||
|
out_mask_64 |= out_mask_64 << 32;
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
xor_be64(out+8*i, ctx->h[i] & out_mask_64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cryptonite_hash_prefix.c>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void cryptonite_sha512t_init(struct sha512_ctx *ctx, uint32_t hashlen)
|
void cryptonite_sha512t_init(struct sha512_ctx *ctx, uint32_t hashlen)
|
||||||
|
|||||||
@ -46,10 +46,12 @@ struct sha512_ctx
|
|||||||
void cryptonite_sha384_init(struct sha384_ctx *ctx);
|
void cryptonite_sha384_init(struct sha384_ctx *ctx);
|
||||||
void cryptonite_sha384_update(struct sha384_ctx *ctx, const uint8_t *data, uint32_t len);
|
void cryptonite_sha384_update(struct sha384_ctx *ctx, const uint8_t *data, uint32_t len);
|
||||||
void cryptonite_sha384_finalize(struct sha384_ctx *ctx, uint8_t *out);
|
void cryptonite_sha384_finalize(struct sha384_ctx *ctx, uint8_t *out);
|
||||||
|
void cryptonite_sha384_finalize_prefix(struct sha384_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
|
||||||
|
|
||||||
void cryptonite_sha512_init(struct sha512_ctx *ctx);
|
void cryptonite_sha512_init(struct sha512_ctx *ctx);
|
||||||
void cryptonite_sha512_update(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len);
|
void cryptonite_sha512_update(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len);
|
||||||
void cryptonite_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out);
|
void cryptonite_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out);
|
||||||
|
void cryptonite_sha512_finalize_prefix(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len, uint32_t n, uint8_t *out);
|
||||||
|
|
||||||
/* only multiples of 8 are supported as valid t values */
|
/* only multiples of 8 are supported as valid t values */
|
||||||
void cryptonite_sha512t_init(struct sha512_ctx *ctx, uint32_t hashlen);
|
void cryptonite_sha512t_init(struct sha512_ctx *ctx, uint32_t hashlen);
|
||||||
|
|||||||
@ -57,6 +57,7 @@ extra-source-files: cbits/*.h
|
|||||||
cbits/argon2/*.h
|
cbits/argon2/*.h
|
||||||
cbits/argon2/*.c
|
cbits/argon2/*.c
|
||||||
cbits/aes/x86ni_impl.c
|
cbits/aes/x86ni_impl.c
|
||||||
|
cbits/cryptonite_hash_prefix.c
|
||||||
tests/*.hs
|
tests/*.hs
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
|
|||||||
30
gen/Gen.hs
30
gen/Gen.hs
@ -54,6 +54,7 @@ data Prop =
|
|||||||
data HashCustom =
|
data HashCustom =
|
||||||
HashSimple Bits -- digest size in bits
|
HashSimple Bits -- digest size in bits
|
||||||
Bytes -- block length in bytes
|
Bytes -- block length in bytes
|
||||||
|
Bool -- has HashAlgorithmPrefix instance?
|
||||||
| HashMulti [Prop] [(Bits, Bytes)] -- list of (digest output size in *bits*, block size in bytes)
|
| HashMulti [Prop] [(Bits, Bytes)] -- list of (digest output size in *bits*, block size in bytes)
|
||||||
|
|
||||||
hashModules =
|
hashModules =
|
||||||
@ -62,22 +63,22 @@ hashModules =
|
|||||||
, GenHashModule "Blake2sp" "blake2.h" "blake2sp" 1752 (HashMulti [] [(224,64), (256,64)])
|
, GenHashModule "Blake2sp" "blake2.h" "blake2sp" 1752 (HashMulti [] [(224,64), (256,64)])
|
||||||
, GenHashModule "Blake2b" "blake2.h" "blake2b" 248 (HashMulti [] [(160, 128), (224, 128), (256, 128), (384, 128), (512,128)])
|
, GenHashModule "Blake2b" "blake2.h" "blake2b" 248 (HashMulti [] [(160, 128), (224, 128), (256, 128), (384, 128), (512,128)])
|
||||||
, GenHashModule "Blake2bp" "blake2.h" "blake2bp" 1768 (HashMulti [] [(512,128)])
|
, GenHashModule "Blake2bp" "blake2.h" "blake2bp" 1768 (HashMulti [] [(512,128)])
|
||||||
, GenHashModule "MD2" "md2.h" "md2" 96 (HashSimple 128 16)
|
, GenHashModule "MD2" "md2.h" "md2" 96 (HashSimple 128 16 False)
|
||||||
, GenHashModule "MD4" "md4.h" "md4" 96 (HashSimple 128 64)
|
, GenHashModule "MD4" "md4.h" "md4" 96 (HashSimple 128 64 False)
|
||||||
, GenHashModule "MD5" "md5.h" "md5" 96 (HashSimple 128 64)
|
, GenHashModule "MD5" "md5.h" "md5" 96 (HashSimple 128 64 True)
|
||||||
, GenHashModule "SHA1" "sha1.h" "sha1" 96 (HashSimple 160 64)
|
, GenHashModule "SHA1" "sha1.h" "sha1" 96 (HashSimple 160 64 True)
|
||||||
, GenHashModule "SHA224" "sha256.h" "sha224" 192 (HashSimple 224 64)
|
, GenHashModule "SHA224" "sha256.h" "sha224" 192 (HashSimple 224 64 True)
|
||||||
, GenHashModule "SHA256" "sha256.h" "sha256" 192 (HashSimple 256 64)
|
, GenHashModule "SHA256" "sha256.h" "sha256" 192 (HashSimple 256 64 True)
|
||||||
, GenHashModule "SHA384" "sha512.h" "sha384" 256 (HashSimple 384 128)
|
, GenHashModule "SHA384" "sha512.h" "sha384" 256 (HashSimple 384 128 True)
|
||||||
, GenHashModule "SHA512" "sha512.h" "sha512" 256 (HashSimple 512 128)
|
, GenHashModule "SHA512" "sha512.h" "sha512" 256 (HashSimple 512 128 True)
|
||||||
, GenHashModule "SHA512t" "sha512.h" "sha512t" 256 (HashMulti [] [(224,128),(256,128)])
|
, GenHashModule "SHA512t" "sha512.h" "sha512t" 256 (HashMulti [] [(224,128),(256,128)])
|
||||||
, GenHashModule "Keccak" "keccak.h" "keccak" 352 (HashMulti [VarCtx sha3CtxSize] [(224,144),(256,136),(384,104),(512,72)])
|
, GenHashModule "Keccak" "keccak.h" "keccak" 352 (HashMulti [VarCtx sha3CtxSize] [(224,144),(256,136),(384,104),(512,72)])
|
||||||
, GenHashModule "SHA3" "sha3.h" "sha3" 352 (HashMulti [VarCtx sha3CtxSize] [(224,144),(256,136),(384,104),(512,72)])
|
, GenHashModule "SHA3" "sha3.h" "sha3" 352 (HashMulti [VarCtx sha3CtxSize] [(224,144),(256,136),(384,104),(512,72)])
|
||||||
, GenHashModule "RIPEMD160" "ripemd.h" "ripemd160" 128 (HashSimple 160 64)
|
, GenHashModule "RIPEMD160" "ripemd.h" "ripemd160" 128 (HashSimple 160 64 False)
|
||||||
, GenHashModule "Skein256" "skein256.h" "skein256" 96 (HashMulti [] [(224,32),(256,32)])
|
, GenHashModule "Skein256" "skein256.h" "skein256" 96 (HashMulti [] [(224,32),(256,32)])
|
||||||
, GenHashModule "Skein512" "skein512.h" "skein512" 160 (HashMulti [] [(224,64),(256,64),(384,64),(512,64)])
|
, GenHashModule "Skein512" "skein512.h" "skein512" 160 (HashMulti [] [(224,64),(256,64),(384,64),(512,64)])
|
||||||
, GenHashModule "Tiger" "tiger.h" "tiger" 96 (HashSimple 192 64)
|
, GenHashModule "Tiger" "tiger.h" "tiger" 96 (HashSimple 192 64 False)
|
||||||
, GenHashModule "Whirlpool" "whirlpool.h" "whirlpool" 168 (HashSimple 512 64)
|
, GenHashModule "Whirlpool" "whirlpool.h" "whirlpool" 168 (HashSimple 512 64 False)
|
||||||
]
|
]
|
||||||
|
|
||||||
sha3CtxSize :: Bits -> Bytes
|
sha3CtxSize :: Bits -> Bytes
|
||||||
@ -105,13 +106,16 @@ renderHashModules genOpts = do
|
|||||||
|
|
||||||
let (tpl, addVars, multiVars) =
|
let (tpl, addVars, multiVars) =
|
||||||
case ghmCustomizable ghm of
|
case ghmCustomizable ghm of
|
||||||
HashSimple digestSize blockLength ->
|
HashSimple digestSize blockLength hasPrefixInstance ->
|
||||||
(hashTemplate,
|
(hashTemplate,
|
||||||
[ ("DIGEST_SIZE_BITS" , showBits digestSize)
|
[ ("DIGEST_SIZE_BITS" , showBits digestSize)
|
||||||
, ("DIGEST_SIZE_BYTES", showBytes digestSize)
|
, ("DIGEST_SIZE_BYTES", showBytes digestSize)
|
||||||
, ("BLOCK_SIZE_BYTES" , showBytes blockLength)
|
, ("BLOCK_SIZE_BYTES" , showBytes blockLength)
|
||||||
|
],
|
||||||
|
[ ("HASPREFIXINSTANCE",
|
||||||
|
[[] | hasPrefixInstance]
|
||||||
|
)
|
||||||
]
|
]
|
||||||
, []
|
|
||||||
)
|
)
|
||||||
HashMulti props customSizes ->
|
HashMulti props customSizes ->
|
||||||
let customCtxSize =
|
let customCtxSize =
|
||||||
|
|||||||
@ -45,7 +45,7 @@ renderTemplate template attrs multiAttrs =
|
|||||||
renderAtom (Tpl n t) =
|
renderAtom (Tpl n t) =
|
||||||
case lookup n multiAttrs of
|
case lookup n multiAttrs of
|
||||||
Nothing -> error ("cannot find inner template attributes for: " ++ n)
|
Nothing -> error ("cannot find inner template attributes for: " ++ n)
|
||||||
Just [] -> error ("empty multiattrs for: " ++ n)
|
Just [] -> ""
|
||||||
Just (i:is) ->
|
Just (i:is) ->
|
||||||
renderTemplate t (i ++ attrs) [] ++
|
renderTemplate t (i ++ attrs) [] ++
|
||||||
concatMap (\inAttrs -> renderTemplate t (inAttrs ++ attrs ++ [("COMMA", ",")]) []) is
|
concatMap (\inAttrs -> renderTemplate t (inAttrs ++ attrs ++ [("COMMA", ",")]) []) is
|
||||||
|
|||||||
@ -32,7 +32,10 @@ instance HashAlgorithm %%MODULENAME%% where
|
|||||||
hashInternalContextSize _ = %%CTX_SIZE_BYTES%%
|
hashInternalContextSize _ = %%CTX_SIZE_BYTES%%
|
||||||
hashInternalInit = c_%%HASHNAME%%_init
|
hashInternalInit = c_%%HASHNAME%%_init
|
||||||
hashInternalUpdate = c_%%HASHNAME%%_update
|
hashInternalUpdate = c_%%HASHNAME%%_update
|
||||||
hashInternalFinalize = c_%%HASHNAME%%_finalize
|
hashInternalFinalize = c_%%HASHNAME%%_finalize%{HASPREFIXINSTANCE%}
|
||||||
|
|
||||||
|
instance HashAlgorithmPrefix %%MODULENAME%% where
|
||||||
|
hashInternalFinalizePrefix = c_%%HASHNAME%%_finalize_prefix%{HASPREFIXINSTANCE%}
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_%%HASHNAME%%_init"
|
foreign import ccall unsafe "cryptonite_%%HASHNAME%%_init"
|
||||||
c_%%HASHNAME%%_init :: Ptr (Context a)-> IO ()
|
c_%%HASHNAME%%_init :: Ptr (Context a)-> IO ()
|
||||||
@ -41,4 +44,7 @@ foreign import ccall "cryptonite_%%HASHNAME%%_update"
|
|||||||
c_%%HASHNAME%%_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
|
c_%%HASHNAME%%_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
|
||||||
|
|
||||||
foreign import ccall unsafe "cryptonite_%%HASHNAME%%_finalize"
|
foreign import ccall unsafe "cryptonite_%%HASHNAME%%_finalize"
|
||||||
c_%%HASHNAME%%_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
|
c_%%HASHNAME%%_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()%{HASPREFIXINSTANCE%}
|
||||||
|
|
||||||
|
foreign import ccall "cryptonite_%%HASHNAME%%_finalize_prefix"
|
||||||
|
c_%%HASHNAME%%_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()%{HASPREFIXINSTANCE%}
|
||||||
|
|||||||
@ -221,6 +221,24 @@ runhashinc :: HashAlg -> [ByteString] -> ByteString
|
|||||||
runhashinc (HashAlg hashAlg) v = B.convertToBase B.Base16 $ hashinc $ v
|
runhashinc (HashAlg hashAlg) v = B.convertToBase B.Base16 $ hashinc $ v
|
||||||
where hashinc = hashFinalize . foldl hashUpdate (hashInitWith hashAlg)
|
where hashinc = hashFinalize . foldl hashUpdate (hashInitWith hashAlg)
|
||||||
|
|
||||||
|
data HashPrefixAlg = forall alg . HashAlgorithmPrefix alg => HashPrefixAlg alg
|
||||||
|
|
||||||
|
expectedPrefix :: [ (String, HashPrefixAlg) ]
|
||||||
|
expectedPrefix =
|
||||||
|
[ ("MD5", HashPrefixAlg MD5)
|
||||||
|
, ("SHA1", HashPrefixAlg SHA1)
|
||||||
|
, ("SHA224", HashPrefixAlg SHA224)
|
||||||
|
, ("SHA256", HashPrefixAlg SHA256)
|
||||||
|
, ("SHA384", HashPrefixAlg SHA384)
|
||||||
|
, ("SHA512", HashPrefixAlg SHA512)
|
||||||
|
]
|
||||||
|
|
||||||
|
runhashpfx :: HashPrefixAlg -> ByteString -> ByteString
|
||||||
|
runhashpfx (HashPrefixAlg hashAlg) v = B.convertToBase B.Base16 $ hashWith hashAlg v
|
||||||
|
|
||||||
|
runhashpfxpfx :: HashPrefixAlg -> ByteString -> Int -> ByteString
|
||||||
|
runhashpfxpfx (HashPrefixAlg hashAlg) v len = B.convertToBase B.Base16 $ hashPrefixWith hashAlg v len
|
||||||
|
|
||||||
makeTestAlg (name, hashAlg, results) =
|
makeTestAlg (name, hashAlg, results) =
|
||||||
testGroup name $ concatMap maketest (zip3 is vectors results)
|
testGroup name $ concatMap maketest (zip3 is vectors results)
|
||||||
where
|
where
|
||||||
@ -236,6 +254,19 @@ makeTestChunk (hashName, hashAlg, _) =
|
|||||||
runhash hashAlg inp `propertyEq` runhashinc hashAlg (chunkS ckLen inp)
|
runhash hashAlg inp `propertyEq` runhashinc hashAlg (chunkS ckLen inp)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
makeTestPrefix (hashName, hashAlg) =
|
||||||
|
[ testProperty hashName $ \(ArbitraryBS0_2901 inp) (Int0_2901 len) ->
|
||||||
|
runhashpfx hashAlg (B.take len inp) `propertyEq` runhashpfxpfx hashAlg inp len
|
||||||
|
]
|
||||||
|
|
||||||
|
makeTestHybrid (hashName, HashPrefixAlg alg) =
|
||||||
|
[ testProperty hashName $ \(ArbitraryBS0_2901 start) (ArbitraryBS0_2901 end) -> do
|
||||||
|
len <- choose (0, B.length end)
|
||||||
|
let ref = hashWith alg (start `B.append` B.take len end)
|
||||||
|
hyb = hashFinalizePrefix (hashUpdate (hashInitWith alg) start) end len
|
||||||
|
return (ref `propertyEq` hyb)
|
||||||
|
]
|
||||||
|
|
||||||
-- SHAKE128 truncation example with expected byte at final position
|
-- SHAKE128 truncation example with expected byte at final position
|
||||||
-- <https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ShakeTruncation.pdf>
|
-- <https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ShakeTruncation.pdf>
|
||||||
shake128TruncationBytes = [0x01, 0x03, 0x07, 0x0f, 0x0f, 0x2f, 0x6f, 0x6f]
|
shake128TruncationBytes = [0x01, 0x03, 0x07, 0x0f, 0x0f, 0x2f, 0x6f, 0x6f]
|
||||||
@ -253,6 +284,8 @@ makeTestSHAKE128Truncation i byte =
|
|||||||
tests = testGroup "hash"
|
tests = testGroup "hash"
|
||||||
[ testGroup "KATs" (map makeTestAlg expected)
|
[ testGroup "KATs" (map makeTestAlg expected)
|
||||||
, testGroup "Chunking" (concatMap makeTestChunk expected)
|
, testGroup "Chunking" (concatMap makeTestChunk expected)
|
||||||
|
, testGroup "Prefix" (concatMap makeTestPrefix expectedPrefix)
|
||||||
|
, testGroup "Hybrid" (concatMap makeTestHybrid expectedPrefix)
|
||||||
, testGroup "Truncating"
|
, testGroup "Truncating"
|
||||||
[ testGroup "SHAKE128"
|
[ testGroup "SHAKE128"
|
||||||
(zipWith makeTestSHAKE128Truncation [1..] shake128TruncationBytes)
|
(zipWith makeTestSHAKE128Truncation [1..] shake128TruncationBytes)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user