packages feed

cryptonite 0.10 → 0.11

raw patch · 18 files changed

+682/−66 lines, 18 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Crypto.Hash.Algorithms: Blake2s_224 :: Blake2s_224
+ Crypto.Hash.Algorithms: Blake2sp_224 :: Blake2sp_224
+ Crypto.Hash.Algorithms: data Blake2s_224
+ Crypto.Hash.Algorithms: data Blake2sp_224
+ Crypto.KDF.HKDF: data PRK a
+ Crypto.KDF.HKDF: expand :: (HashAlgorithm a, ByteArrayAccess info, ByteArray out) => PRK a -> info -> Int -> out
+ Crypto.KDF.HKDF: extract :: (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm) => salt -> ikm -> PRK a
+ Crypto.KDF.HKDF: extractSkip :: (HashAlgorithm a, ByteArrayAccess ikm) => ikm -> PRK a
+ Crypto.KDF.HKDF: instance GHC.Classes.Eq (Crypto.KDF.HKDF.PRK a)
+ Crypto.PubKey.Ed448: data DhSecret
+ Crypto.PubKey.Ed448: data PublicKey
+ Crypto.PubKey.Ed448: data SecretKey
+ Crypto.PubKey.Ed448: dh :: PublicKey -> SecretKey -> DhSecret
+ Crypto.PubKey.Ed448: dhSecret :: ByteArrayAccess b => b -> CryptoFailable DhSecret
+ Crypto.PubKey.Ed448: instance Control.DeepSeq.NFData Crypto.PubKey.Ed448.DhSecret
+ Crypto.PubKey.Ed448: instance Control.DeepSeq.NFData Crypto.PubKey.Ed448.PublicKey
+ Crypto.PubKey.Ed448: instance Control.DeepSeq.NFData Crypto.PubKey.Ed448.SecretKey
+ Crypto.PubKey.Ed448: instance Data.ByteArray.Types.ByteArrayAccess Crypto.PubKey.Ed448.DhSecret
+ Crypto.PubKey.Ed448: instance Data.ByteArray.Types.ByteArrayAccess Crypto.PubKey.Ed448.PublicKey
+ Crypto.PubKey.Ed448: instance Data.ByteArray.Types.ByteArrayAccess Crypto.PubKey.Ed448.SecretKey
+ Crypto.PubKey.Ed448: instance GHC.Classes.Eq Crypto.PubKey.Ed448.DhSecret
+ Crypto.PubKey.Ed448: instance GHC.Classes.Eq Crypto.PubKey.Ed448.PublicKey
+ Crypto.PubKey.Ed448: instance GHC.Classes.Eq Crypto.PubKey.Ed448.SecretKey
+ Crypto.PubKey.Ed448: instance GHC.Show.Show Crypto.PubKey.Ed448.DhSecret
+ Crypto.PubKey.Ed448: instance GHC.Show.Show Crypto.PubKey.Ed448.PublicKey
+ Crypto.PubKey.Ed448: instance GHC.Show.Show Crypto.PubKey.Ed448.SecretKey
+ Crypto.PubKey.Ed448: publicKey :: ByteArrayAccess bs => bs -> CryptoFailable PublicKey
+ Crypto.PubKey.Ed448: secretKey :: ByteArrayAccess bs => bs -> CryptoFailable SecretKey
+ Crypto.PubKey.Ed448: toPublic :: SecretKey -> PublicKey
- Crypto.MAC.HMAC: hmac :: (ByteArrayAccess key, ByteArray message, HashAlgorithm a) => key -> message -> HMAC a
+ Crypto.MAC.HMAC: hmac :: (ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a) => key -> message -> HMAC a

Files

CHANGELOG.md view
@@ -1,3 +1,14 @@+## 0.11++* Truncate hashing correctly for DSA+* Add support for HKDF (RFC 5869)+* Add support for Ed448+* Extends support for Blake2s to 224 bits version.+* Compilation workaround for old distribution (RHEL 4.1)+* Compilation fix for AIX+* Compilation fix with AESNI and ghci compiling C source in a weird order.+* Fix example compilation, typo, and warning+ ## 0.10  * Add reference implementation of blake2 for non-SSE2 platform
Crypto/Cipher/ChaChaPoly1305.hs view
@@ -5,7 +5,8 @@ -- Stability   : stable -- Portability : good ----- A simple AEAD scheme using ChaCha20 and Poly1305. See RFC7539.+-- A simple AEAD scheme using ChaCha20 and Poly1305. See+-- <https://tools.ietf.org/html/rfc7539 RFC 7539>. -- -- The State is not modified in place, so each function changing the State, -- returns a new State.@@ -15,12 +16,24 @@ -- -- Once 'finalizeAAD' has been called, no further 'appendAAD' call should be make. ----- > encrypt nonce key hdr inp =--- >    let st1        = ChaChaPoly1305.initialize key nonce--- >        st2        = ChaChaPoly1305.finalizeAAD $ ChaChaPoly1305.appendAAD hdr st1--- >        (out, st3) = ChaChaPoly1305.encrypt inp st2--- >        auth       = ChaChaPoly1305.finalize st3--- >     in out `B.append` Data.ByteArray.convert auth+-- >import Data.ByteString.Char8 as B+-- >import Data.ByteArray+-- >import Crypto.Error+-- >import Crypto.Cipher.ChaChaPoly1305 as C+-- >+-- >encrypt+-- >    :: ByteString -- nonce (12 random bytes)+-- >    -> ByteString -- symmetric key+-- >    -> ByteString -- optional associated data (won't be encrypted)+-- >    -> ByteString -- input plaintext to be encrypted+-- >    -> CryptoFailable ByteString -- ciphertext with a 128-bit tag attached+-- >encrypt nonce key header plaintext = do+-- >    st1 <- C.nonce12 nonce >>= C.initialize key+-- >    let+-- >        st2 = C.finalizeAAD $ C.appendAAD header st1+-- >        (out, st3) = C.encrypt plaintext st2+-- >        auth = C.finalize st3+-- >    return $ out `B.append` Data.ByteArray.convert auth -- module Crypto.Cipher.ChaChaPoly1305     ( State
Crypto/Hash/Algorithms.hs view
@@ -11,6 +11,8 @@ module Crypto.Hash.Algorithms     ( HashAlgorithm     -- * hash algorithms+    , Blake2s_224(..)+    , Blake2sp_224(..)     , Blake2s_256(..)     , Blake2sp_256(..)     , Blake2b_512(..)
Crypto/Hash/Blake2s.hs view
@@ -10,13 +10,25 @@ -- {-# LANGUAGE ForeignFunctionInterface #-} module Crypto.Hash.Blake2s-    (  Blake2s_256 (..)+    (  Blake2s_224 (..), Blake2s_256 (..)     ) where  import           Crypto.Hash.Types import           Foreign.Ptr (Ptr) import           Data.Word (Word8, Word32) ++-- | Blake2s (224 bits) cryptographic hash algorithm+data Blake2s_224 = Blake2s_224+    deriving (Show)++instance HashAlgorithm Blake2s_224 where+    hashBlockSize  _          = 64+    hashDigestSize _          = 28+    hashInternalContextSize _ = 185+    hashInternalInit p        = c_blake2s_init p 224+    hashInternalUpdate        = c_blake2s_update+    hashInternalFinalize p    = c_blake2s_finalize p 224  -- | Blake2s (256 bits) cryptographic hash algorithm data Blake2s_256 = Blake2s_256
Crypto/Hash/Blake2sp.hs view
@@ -10,13 +10,25 @@ -- {-# LANGUAGE ForeignFunctionInterface #-} module Crypto.Hash.Blake2sp-    (  Blake2sp_256 (..)+    (  Blake2sp_224 (..), Blake2sp_256 (..)     ) where  import           Crypto.Hash.Types import           Foreign.Ptr (Ptr) import           Data.Word (Word8, Word32) ++-- | Blake2sp (224 bits) cryptographic hash algorithm+data Blake2sp_224 = Blake2sp_224+    deriving (Show)++instance HashAlgorithm Blake2sp_224 where+    hashBlockSize  _          = 64+    hashDigestSize _          = 28+    hashInternalContextSize _ = 2185+    hashInternalInit p        = c_blake2sp_init p 224+    hashInternalUpdate        = c_blake2sp_update+    hashInternalFinalize p    = c_blake2sp_finalize p 224  -- | Blake2sp (256 bits) cryptographic hash algorithm data Blake2sp_256 = Blake2sp_256
+ Crypto/KDF/HKDF.hs view
@@ -0,0 +1,77 @@+-- |+-- Module      : Crypto.KDF.HKDF+-- License     : BSD-style+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>+-- Stability   : experimental+-- Portability : unknown+--+-- Key Derivation Function based on HMAC+--+-- See rfc5869+--+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Crypto.KDF.HKDF+    ( PRK+    , extract+    , extractSkip+    , expand+    ) where++import           Data.Word+import           Crypto.Hash +import           Crypto.MAC.HMAC+import           Crypto.Internal.ByteArray (ScrubbedBytes, Bytes, ByteArray, ByteArrayAccess)+import qualified Crypto.Internal.ByteArray as B++-- | Pseudo Random Key+data PRK a = PRK (HMAC a) | PRK_NoExpand ScrubbedBytes+    deriving (Eq)++-- | Extract a Pseudo Random Key using the parameter and the underlaying hash mechanism+extract :: (HashAlgorithm a, ByteArrayAccess salt, ByteArrayAccess ikm)+        => salt  -- ^ Salt+        -> ikm   -- ^ Input Keying Material+        -> PRK a -- ^ Pseudo random key+extract salt ikm = PRK $ hmac salt ikm++-- | Create a PRK directly from the input key material, skipping any hmacing+extractSkip :: (HashAlgorithm a, ByteArrayAccess ikm)+            => ikm+            -> PRK a+extractSkip ikm = PRK_NoExpand $ B.convert ikm++-- | Expand key material of specific length out of the parameters+expand :: (HashAlgorithm a, ByteArrayAccess info, ByteArray out)+       => PRK a      -- ^ Pseudo Random Key+       -> info       -- ^ Optional context and application specific information+       -> Int        -- ^ Output length in bytes+       -> out        -- ^ Output data+expand prkAt infoAt outputLength =+    let hF = hFGet prkAt+     in B.concat $ loop hF B.empty outputLength 1+  where+    hFGet :: (HashAlgorithm a, ByteArrayAccess b) => PRK a -> (b -> HMAC a)+    hFGet prk = case prk of+             PRK hmacKey      -> hmac hmacKey+             PRK_NoExpand ikm -> hmac ikm++    info :: ScrubbedBytes+    info = B.convert infoAt++    loop :: HashAlgorithm a+         => (ScrubbedBytes -> HMAC a)+         -> ScrubbedBytes+         -> Int+         -> Word8+         -> [ScrubbedBytes]+    loop hF tim1 n i+        | n <= 0    = []+        | otherwise =+            let input   = B.concat [tim1,info,B.singleton i] :: ScrubbedBytes+                ti      = B.convert $ hF input+                hashLen = B.length ti+                r       = n - hashLen+             in (if n >= hashLen then ti else B.take n ti)+              : loop hF ti r (i+1)+
Crypto/MAC/HMAC.hs view
@@ -40,7 +40,7 @@     (HMAC b1) == (HMAC b2) = B.constEq b1 b2  -- | compute a MAC using the supplied hashing function-hmac :: (ByteArrayAccess key, ByteArray message, HashAlgorithm a)+hmac :: (ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a)      => key     -- ^ Secret key      -> message -- ^ Message to MAC      -> HMAC a
Crypto/Number/Compat.hs view
@@ -71,7 +71,7 @@ -- time wise through GMP gmpPowModSecInteger :: Integer -> Integer -> Integer -> GmpSupported Integer #if MIN_VERSION_integer_gmp(1,0,0)-gmpPowModSecInteger b e m = GmpUnsupported+gmpPowModSecInteger _ _ _ = GmpUnsupported #elif MIN_VERSION_integer_gmp(0,5,1) gmpPowModSecInteger b e m = GmpSupported (powModSecInteger b e m) #else
Crypto/PubKey/DSA.hs view
@@ -29,14 +29,17 @@     ) where  import           Crypto.Random.Types+import           Data.Bits (testBit) import           Data.Data import           Data.Maybe+import           Crypto.Number.Basic (numBits) import           Crypto.Number.ModArithmetic (expFast, expSafe, inverse) import           Crypto.Number.Serialize import           Crypto.Number.Generate-import           Crypto.Internal.ByteArray (ByteArrayAccess)+import           Crypto.Internal.ByteArray (ByteArrayAccess(length), convert, index, dropView, takeView) import           Crypto.Internal.Imports import           Crypto.Hash+import           Prelude hiding (length)  -- | DSA Public Number, usually embedded in DSA Public Key type PublicNumber = Integer@@ -145,9 +148,11 @@     | otherwise                            = v == r     where (Params p g q) = public_params pk           y       = public_y pk-          hm      = os2ip $ hashWith hashAlg m+          hm      = os2ip . truncateHash $ hashWith hashAlg m            w       = fromJust $ inverse s q           u1      = (hm*w) `mod` q           u2      = (r*w) `mod` q           v       = ((expFast g u1 p) * (expFast y u2 p)) `mod` p `mod` q+          -- if the hash is larger than the size of q, truncate it; FIXME: deal with the case of a q not evenly divisible by 8+          truncateHash h = if numBits (os2ip h) > numBits q then takeView h (numBits q `div` 8) else dropView h 0
+ Crypto/PubKey/Ed448.hs view
@@ -0,0 +1,102 @@+-- |+-- Module      : Crypto.PubKey.Ed448+-- License     : BSD-style+-- Maintainer  : John Galt <jgalt@centromere.net>+-- Stability   : experimental+-- Portability : unknown+--+-- Ed448 support+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash #-}+module Crypto.PubKey.Ed448+    ( SecretKey+    , PublicKey+    , DhSecret+    -- * Smart constructors+    , dhSecret+    , publicKey+    , secretKey+    -- * methods+    , dh+    , toPublic+    ) where++import           Data.Word+import           Foreign.Ptr+import           GHC.Ptr++import           Crypto.Error+import           Crypto.Internal.Compat+import           Crypto.Internal.Imports+import           Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)+import qualified Crypto.Internal.ByteArray as B++-- | A Ed448 Secret key+newtype SecretKey = SecretKey ScrubbedBytes+    deriving (Show,Eq,ByteArrayAccess,NFData)++-- | A Ed448 public key+newtype PublicKey = PublicKey Bytes+    deriving (Show,Eq,ByteArrayAccess,NFData)++-- | A Ed448 Diffie Hellman secret related to a+-- public key and a secret key.+newtype DhSecret = DhSecret ScrubbedBytes+    deriving (Show,Eq,ByteArrayAccess,NFData)++-- | Try to build a public key from a bytearray+publicKey :: ByteArrayAccess bs => bs -> CryptoFailable PublicKey+publicKey bs+    | B.length bs == x448_bytes = CryptoPassed $ PublicKey $ B.copyAndFreeze bs (\_ -> return ())+    | otherwise                 = CryptoFailed CryptoError_PublicKeySizeInvalid++-- | Try to build a secret key from a bytearray+secretKey :: ByteArrayAccess bs => bs -> CryptoFailable SecretKey+secretKey bs+    | B.length bs == x448_bytes = unsafeDoIO $+        withByteArray bs $ \inp -> do+            valid <- isValidPtr inp+            if valid+                then (CryptoPassed . SecretKey) <$> B.copy bs (\_ -> return ())+                else return $ CryptoFailed CryptoError_SecretKeyStructureInvalid+    | otherwise = CryptoFailed CryptoError_SecretKeySizeInvalid+  where+        isValidPtr :: Ptr Word8 -> IO Bool+        isValidPtr _ =+            return True+{-# NOINLINE secretKey #-}++-- | Create a DhSecret from a bytearray object+dhSecret :: ByteArrayAccess b => b -> CryptoFailable DhSecret+dhSecret bs+    | B.length bs == x448_bytes = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ())+    | otherwise                 = CryptoFailed CryptoError_SharedSecretSizeInvalid++-- | Compute the Diffie Hellman secret from a public key and a secret key+dh :: PublicKey -> SecretKey -> DhSecret+dh (PublicKey pub) (SecretKey sec) = DhSecret <$>+    B.allocAndFreeze x448_bytes $ \result ->+    withByteArray sec           $ \psec   ->+    withByteArray pub           $ \ppub   ->+        ccryptonite_ed448 result psec ppub+{-# NOINLINE dh #-}++-- | Create a public key from a secret key+toPublic :: SecretKey -> PublicKey+toPublic (SecretKey sec) = PublicKey <$>+    B.allocAndFreeze x448_bytes     $ \result ->+    withByteArray sec               $ \psec   ->+        ccryptonite_ed448 result psec basePoint+  where+        basePoint = Ptr "\x05\x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00\x00x00\x00\x00\x00\x00\x00\x00"#+{-# NOINLINE toPublic #-}++x448_bytes :: Int+x448_bytes = 448 `quot` 8++foreign import ccall "cryptonite_x448"+    ccryptonite_ed448 :: Ptr Word8 -- ^ public+                      -> Ptr Word8 -- ^ secret+                      -> Ptr Word8 -- ^ basepoint+                      -> IO ()
cbits/cryptonite_bitfn.h view
@@ -188,6 +188,8 @@ #elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ )   # define BIG_ENDIAN 1234   # define BYTE_ORDER    BIG_ENDIAN+#elif defined( _AIX )+  # include <sys/machine.h> #else   # include <endian.h> #endif
− cbits/cryptonite_sysrand.c
@@ -1,46 +0,0 @@-/*- * Copyright (C) 2015 Vincent Hanquez <tab@snarc.org>- *- * All rights reserved.- * - * 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.- * 3. Neither the name of the author nor the names of his contributors- *    may be used to endorse or promote products derived from this software- *    without specific prior written permission.- * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF- * SUCH DAMAGE.- */--#include <stdlib.h>-#include <stdint.h>-#include <sys/time.h>-#include "cryptonite_sha512.h"--void cryptonite_sysrand_init(uint8_t *buf, uint32_t sz)-{-	struct timeval tv;-	struct sha512_ctx ctx;-	uint8_t out[64];-	-	gettimeofday(&tv, NULL);-	cryptonite_sha512_init(&ctx);-	cryptonite_sha512_update(&ctx, (uint8_t *) &tv, sizeof(tv));-	cryptonite_sha512_finalize(&ctx, out);-}
+ cbits/ed448/x448.c view
@@ -0,0 +1,306 @@+/* Copyright (c) 2015 Cryptography Research, Inc.+ * Released under the MIT License.  See LICENSE.txt for license information.+ */++/**+ * @file decaf.c+ * @author Mike Hamburg+ * @brief Decaf high-level functions.+ */++#include <stdint.h>+#include "x448.h"++#define WBITS 64 /* TODO */+#define LBITS (WBITS * 7 / 8)+#define X448_LIMBS (448/LBITS)++#if WBITS == 64+typedef uint64_t decaf_word_t;+typedef int64_t decaf_sword_t;+typedef __uint128_t decaf_dword_t;+typedef __int128_t decaf_sdword_t;+#elif WBITS == 32+typedef uint32_t decaf_word_t;+typedef int32_t decaf_sword_t;+typedef uint64_t decaf_dword_t;+typedef int64_t decaf_sdword_t;+#else+#error "WBITS must be 32 or 64"+#endif++typedef struct { decaf_word_t limb[X448_LIMBS]; } gf_s, gf[1];++const unsigned char X448_BASE_POINT[X448_BYTES] = {5};++static const gf ZERO = {{{0}}}, ONE = {{{1}}};++#define LMASK ((((decaf_word_t)1)<<LBITS)-1)+#if WBITS == 64+static const gf P = {{{ LMASK, LMASK, LMASK, LMASK, LMASK-1, LMASK, LMASK, LMASK }}};+#else+static const gf P = {{{ LMASK,   LMASK, LMASK, LMASK, LMASK, LMASK, LMASK, LMASK,+		      LMASK-1, LMASK, LMASK, LMASK, LMASK, LMASK, LMASK, LMASK }}};+#endif+static const int EDWARDS_D = -39081;++#if (defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__)) || defined(DECAF_FORCE_UNROLL)+    #if X448_LIMBS==8+    #define FOR_LIMB_U(i,op) { unsigned int i=0; \+       op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; \+    }+    #elif X448_LIMBS==16+    #define FOR_LIMB_U(i,op) { unsigned int i=0; \+       op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; \+       op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; op;i++; \+    }+    #else+    #define FOR_LIMB_U(i,op) { unsigned int i=0; for (i=0; i<X448_LIMBS; i++)  { op; }}+    #endif+#else+#define FOR_LIMB_U(i,op) { unsigned int i=0; for (i=0; i<X448_LIMBS; i++)  { op; }}+#endif++#define FOR_LIMB(i,op) { unsigned int i=0; for (i=0; i<X448_LIMBS; i++)  { op; }}++/** Copy x = y */+static void gf_cpy(gf x, const gf y) {+    FOR_LIMB_U(i, x->limb[i] = y->limb[i]);+}++/** Mostly-unoptimized multiply (PERF), but at least it's unrolled. */+static void+gf_mul (gf c, const gf a, const gf b) {+    gf aa;+    gf_cpy(aa,a);++    decaf_dword_t accum[X448_LIMBS] = {0};+    FOR_LIMB_U(i, {+        FOR_LIMB_U(j,{ accum[(i+j)%X448_LIMBS] += (decaf_dword_t)b->limb[i] * aa->limb[j]; });+        aa->limb[(X448_LIMBS-1-i)^(X448_LIMBS/2)] += aa->limb[X448_LIMBS-1-i];+    });++    accum[X448_LIMBS-1] += accum[X448_LIMBS-2] >> LBITS;+    accum[X448_LIMBS-2] &= LMASK;+    accum[X448_LIMBS/2] += accum[X448_LIMBS-1] >> LBITS;+    FOR_LIMB_U(j,{+        accum[j] += accum[(j-1)%X448_LIMBS] >> LBITS;+        accum[(j-1)%X448_LIMBS] &= LMASK;+    });+    FOR_LIMB_U(j, c->limb[j] = accum[j] );+}++/** No dedicated square (PERF) */+#define gf_sqr(c,a) gf_mul(c,a,a)++/** Inverse square root using addition chain. */+static void+gf_isqrt(gf y, const gf x) {+    int i;+#define STEP(s,m,n) gf_mul(s,m,c); gf_cpy(c,s); for (i=0;i<n;i++) gf_sqr(c,c);+    gf a, b, c;+    gf_sqr ( c,   x );+    STEP(b,x,1);+    STEP(b,x,3);+    STEP(a,b,3);+    STEP(a,b,9);+    STEP(b,a,1);+    STEP(a,x,18);+    STEP(a,b,37);+    STEP(b,a,37);+    STEP(b,a,111);+    STEP(a,b,1);+    STEP(b,x,223);+    gf_mul(y,a,c);+}++static void+gf_inv(gf y, const gf x) {+    gf z,w;+    gf_sqr(z,x); /* x^2 */+    gf_isqrt(w,z); /* +- 1/sqrt(x^2) = +- 1/x */+    gf_sqr(z,w); /* 1/x^2 */+    gf_mul(w,x,z); /* 1/x */+    gf_cpy(y,w);+}++/** Weak reduce mod p. */+static void+gf_reduce(gf x) {+    x->limb[X448_LIMBS/2] += x->limb[X448_LIMBS-1] >> LBITS;+    FOR_LIMB_U(j,{+        x->limb[j] += x->limb[(j-1)%X448_LIMBS] >> LBITS;+        x->limb[(j-1)%X448_LIMBS] &= LMASK;+    });+}++/** Add mod p.  Conservatively always weak-reduce. (PERF) */+static void+gf_add ( gf x, const gf y, const gf z ) {+    FOR_LIMB_U(i, x->limb[i] = y->limb[i] + z->limb[i] );+    gf_reduce(x);+}++/** Subtract mod p.  Conservatively always weak-reduce. (PERF) */+static void+gf_sub ( gf x, const gf y, const gf z ) {+    FOR_LIMB_U(i, x->limb[i] = y->limb[i] - z->limb[i] + 2*P->limb[i] );+    gf_reduce(x);+}++/** Constant time, if (swap) (x,y) = (y,x); */+static void+cond_swap(gf x, gf_s *__restrict__ y, decaf_word_t swap) {+    FOR_LIMB_U(i, {+        decaf_word_t s = (x->limb[i] ^ y->limb[i]) & swap;+        x->limb[i] ^= s;+        y->limb[i] ^= s;+    });+}++/**+ * Mul by signed int.  Not constant-time WRT the sign of that int.+ * Just uses a full mul (PERF)+ */+static inline void+gf_mlw(gf a, const gf b, int w) {+    if (w>0) {+        gf ww = {{{w}}};+        gf_mul(a,b,ww);+    } else {+        gf ww = {{{-w}}};+        gf_mul(a,b,ww);+        gf_sub(a,ZERO,a);+    }+}++/** Canonicalize */+static void gf_canon ( gf a ) {+    gf_reduce(a);++    /* subtract p with borrow */+    decaf_sdword_t carry = 0;+    FOR_LIMB(i, {+        carry = carry + a->limb[i] - P->limb[i];+        a->limb[i] = carry & LMASK;+        carry >>= LBITS;+    });++    decaf_word_t addback = carry;+    carry = 0;++    /* add it back */+    FOR_LIMB(i, {+        carry = carry + a->limb[i] + (P->limb[i] & addback);+        a->limb[i] = carry & LMASK;+        carry >>= LBITS;+    });+}++/* Deserialize */+static decaf_word_t+gf_deser(gf s, const unsigned char ser[X448_BYTES]) {+    unsigned int i, k=0, bits=0;+    decaf_dword_t buf=0;+    for (i=0; i<X448_BYTES; i++) {+        buf |= (decaf_dword_t)ser[i]<<bits;+        for (bits += 8; (bits>=LBITS || i==X448_BYTES-1) && k<X448_LIMBS; bits-=LBITS, buf>>=LBITS) {+            s->limb[k++] = buf & LMASK;+        }+    }++    decaf_sdword_t accum = 0;+    FOR_LIMB(i, accum = (accum + s->limb[i] - P->limb[i]) >> WBITS );+    return accum;+}++/* Serialize */+static void+gf_ser(uint8_t ser[X448_BYTES], gf a) {+    gf_canon(a);+    int k=0, bits=0;+    decaf_dword_t buf=0;+    FOR_LIMB(i, {+        buf |= (decaf_dword_t)a->limb[i]<<bits;+        for (bits += LBITS; (bits>=8 || i==X448_LIMBS-1) && k<X448_BYTES; bits-=8, buf>>=8) {+            ser[k++]=buf;+        }+    });+}++int __attribute__((visibility("default"))) cryptonite_x448 (+    unsigned char out[X448_BYTES],+    const unsigned char scalar[X448_BYTES],+    const unsigned char base[X448_BYTES]+) {+    gf x1, x2, z2, x3, z3, t1, t2;+    gf_deser(x1,base);+    gf_cpy(x2,ONE);+    gf_cpy(z2,ZERO);+    gf_cpy(x3,x1);+    gf_cpy(z3,ONE);++    int t;+    decaf_word_t swap = 0;++    for (t = 448-1; t>=0; t--) {+        uint8_t sb = scalar[t/8];++        /* Scalar conditioning */+        if (t/8==0) sb &= 0xFC;+        else if (t/8 == X448_BYTES-1) sb |= 0x80;++        decaf_word_t k_t = (sb>>(t%8)) & 1;+        k_t = -k_t; /* set to all 0s or all 1s */++        swap ^= k_t;+        cond_swap(x2,x3,swap);+        cond_swap(z2,z3,swap);+        swap = k_t;++        gf_add(t1,x2,z2); /* A = x2 + z2 */+        gf_sub(t2,x2,z2); /* B = x2 - z2 */+        gf_sub(z2,x3,z3); /* D = x3 - z3 */+        gf_mul(x2,t1,z2); /* DA */+        gf_add(z2,z3,x3); /* C = x3 + z3 */+        gf_mul(x3,t2,z2); /* CB */+        gf_sub(z3,x2,x3); /* DA-CB */+        gf_sqr(z2,z3);    /* (DA-CB)^2 */+        gf_mul(z3,x1,z2); /* z3 = x1(DA-CB)^2 */+        gf_add(z2,x2,x3); /* (DA+CB) */+        gf_sqr(x3,z2);    /* x3 = (DA+CB)^2 */++        gf_sqr(z2,t1);    /* AA = A^2 */+        gf_sqr(t1,t2);    /* BB = B^2 */+        gf_mul(x2,z2,t1); /* x2 = AA*BB */+        gf_sub(t2,z2,t1); /* E = AA-BB */++        gf_mlw(t1,t2,-EDWARDS_D); /* E*-d = a24*E */+        gf_add(t1,t1,z2); /* AA + a24*E */+        gf_mul(z2,t2,t1); /* z2 = E(AA+a24*E) */+    }++    /* Finish */+    cond_swap(x2,x3,swap);+    cond_swap(z2,z3,swap);+    gf_inv(z2,z2);+    gf_mul(x1,x2,z2);+    gf_ser(out,x1);++    decaf_sword_t nz = 0;+    for (t=0; t<X448_BYTES; t++) {+        nz |= out[t];+    }+    nz = (nz-1)>>8; /* 0 = succ, -1 = fail */++    /* return value: 0 = succ, -1 = fail */+    return nz;+}++int __attribute__((visibility("default")))+cryptonite_x448_base (+    unsigned char out[X448_BYTES],+    const unsigned char scalar[X448_BYTES]+) {+    return cryptonite_x448(out,scalar,X448_BASE_POINT);+}
+ cbits/ed448/x448.h view
@@ -0,0 +1,25 @@++#define X448_BYTES (448/8)++/* The base point (5) */+extern const unsigned char X448_BASE_POINT[X448_BYTES];++/* Returns 0 on success, -1 on failure */+int __attribute__((visibility("default")))+cryptonite_x448 (+    unsigned char out[X448_BYTES],+    const unsigned char scalar[X448_BYTES],+    const unsigned char base[X448_BYTES]+);++/* Returns 0 on success, -1 on failure+ *+ * Same as x448(out,scalar,X448_BASE_POINT), except that+ * an implementation may optimize it.+ */+int __attribute__((visibility("default")))+cryptonite_x448_base (+    unsigned char out[X448_BYTES],+    const unsigned char scalar[X448_BYTES]+);+
cryptonite.cabal view
@@ -1,5 +1,5 @@ Name:                cryptonite-Version:             0.10+Version:             0.11 Synopsis:            Cryptography Primitives sink Description:     A repository of cryptographic primitives.@@ -12,7 +12,7 @@     .     * Assymmetric crypto: DSA, RSA, DH, ECDH, ECDSA, ECC, Curve25519, Ed25519     .-    * Key Derivation Function: PBKDF2, Scrypt+    * Key Derivation Function: PBKDF2, Scrypt, HKDF     .     * Cryptographic Random generation: System Entropy, Deterministic Random Generator     .@@ -38,6 +38,7 @@ extra-source-files:  cbits/*.h                      cbits/aes/*.h                      cbits/ed25519/*.h+                     cbits/ed448/*.h                      cbits/p256/*.h                      cbits/blake2/ref/*.h                      cbits/blake2/ref/*.c@@ -80,6 +81,11 @@   Default:           True   Manual:            True +Flag old_toolchain_inliner+  Description:       use -fgnu89-inline to workaround an old compiler / linker / glibc issue.+  Default:           False+  Manual:            True+ Library   Exposed-modules:   Crypto.Cipher.AES                      Crypto.Cipher.Blowfish@@ -106,6 +112,7 @@                      Crypto.KDF.PBKDF2                      Crypto.KDF.Scrypt                      Crypto.KDF.BCrypt+                     Crypto.KDF.HKDF                      Crypto.Hash                      Crypto.Hash.IO                      Crypto.Hash.Algorithms@@ -120,6 +127,7 @@                      Crypto.PubKey.ECC.P256                      Crypto.PubKey.ECC.Types                      Crypto.PubKey.Ed25519+                     Crypto.PubKey.Ed448                      Crypto.PubKey.RSA                      Crypto.PubKey.RSA.PKCS15                      Crypto.PubKey.RSA.Prim@@ -186,15 +194,15 @@   ghc-options:       -Wall -fwarn-tabs -optc-O3 -fno-warn-unused-imports   default-language:  Haskell2010   cc-options:        -std=gnu99+  if flag(old_toolchain_inliner)+    cc-options:      -fgnu89-inline   C-sources:         cbits/cryptonite_chacha.c                    , cbits/cryptonite_salsa.c                    , cbits/cryptonite_rc4.c                    , cbits/cryptonite_cpu.c-                   , cbits/aes/generic.c-                   , cbits/aes/gf.c-                   , cbits/cryptonite_aes.c                    , cbits/curve25519/curve25519-donna.c                    , cbits/ed25519/ed25519.c+                   , cbits/ed448/x448.c                    , cbits/p256/p256.c                    , cbits/p256/p256_ec.c                    , cbits/cryptonite_blake2s.c@@ -216,7 +224,6 @@                    , cbits/cryptonite_tiger.c                    , cbits/cryptonite_whirlpool.c                    , cbits/cryptonite_scrypt.c-                   , cbits/cryptonite_sysrand.c   include-dirs:  cbits cbits/ed25519    -- FIXME armel or mispel is also little endian.@@ -238,7 +245,14 @@     CC-options:     -mssse3 -maes -DWITH_AESNI     if flag(support_pclmuldq)        CC-options:  -msse4.1 -mpclmul -DWITH_PCLMUL-    C-sources:      cbits/aes/x86ni.c+    C-sources:       cbits/aes/x86ni.c+                   , cbits/aes/generic.c+                   , cbits/aes/gf.c+                   , cbits/cryptonite_aes.c+  else+    C-sources:       cbits/aes/generic.c+                   , cbits/aes/gf.c+                   , cbits/cryptonite_aes.c    if arch(x86_64) || flag(support_blake2_sse)     C-sources:      cbits/blake2/sse/blake2s.c
+ tests/KAT_Ed448.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE OverloadedStrings #-}+module KAT_Ed448 ( tests ) where++import           Crypto.Error+import qualified Crypto.PubKey.Ed448 as Ed448+import           Data.ByteArray as B+import           Imports++alicePrivate = throwCryptoError $ Ed448.secretKey ("\x9a\x8f\x49\x25\xd1\x51\x9f\x57\x75\xcf\x46\xb0\x4b\x58\x00\xd4\xee\x9e\xe8\xba\xe8\xbc\x55\x65\xd4\x98\xc2\x8d\xd9\xc9\xba\xf5\x74\xa9\x41\x97\x44\x89\x73\x91\x00\x63\x82\xa6\xf1\x27\xab\x1d\x9a\xc2\xd8\xc0\xa5\x98\x72\x6b" :: ByteString)+alicePublic  = throwCryptoError $ Ed448.publicKey ("\x9b\x08\xf7\xcc\x31\xb7\xe3\xe6\x7d\x22\xd5\xae\xa1\x21\x07\x4a\x27\x3b\xd2\xb8\x3d\xe0\x9c\x63\xfa\xa7\x3d\x2c\x22\xc5\xd9\xbb\xc8\x36\x64\x72\x41\xd9\x53\xd4\x0c\x5b\x12\xda\x88\x12\x0d\x53\x17\x7f\x80\xe5\x32\xc4\x1f\xa0" :: ByteString)+bobPrivate   = throwCryptoError $ Ed448.secretKey ("\x1c\x30\x6a\x7a\xc2\xa0\xe2\xe0\x99\x0b\x29\x44\x70\xcb\xa3\x39\xe6\x45\x37\x72\xb0\x75\x81\x1d\x8f\xad\x0d\x1d\x69\x27\xc1\x20\xbb\x5e\xe8\x97\x2b\x0d\x3e\x21\x37\x4c\x9c\x92\x1b\x09\xd1\xb0\x36\x6f\x10\xb6\x51\x73\x99\x2d" :: ByteString)+bobPublic    = throwCryptoError $ Ed448.publicKey ("\x3e\xb7\xa8\x29\xb0\xcd\x20\xf5\xbc\xfc\x0b\x59\x9b\x6f\xec\xcf\x6d\xa4\x62\x71\x07\xbd\xb0\xd4\xf3\x45\xb4\x30\x27\xd8\xb9\x72\xfc\x3e\x34\xfb\x42\x32\xa1\x3c\xa7\x06\xdc\xb5\x7a\xec\x3d\xae\x07\xbd\xc1\xc6\x7b\xf3\x36\x09" :: ByteString)+aliceMultBob = "\x07\xff\xf4\x18\x1a\xc6\xcc\x95\xec\x1c\x16\xa9\x4a\x0f\x74\xd1\x2d\xa2\x32\xce\x40\xa7\x75\x52\x28\x1d\x28\x2b\xb6\x0c\x0b\x56\xfd\x24\x64\xc3\x35\x54\x39\x36\x52\x1c\x24\x40\x30\x85\xd5\x9a\x44\x9a\x50\x37\x51\x4a\x87\x9d" :: ByteString++katTests :: [TestTree]+katTests =+    [ testCase "0" (aliceMultBob @=? B.convert (Ed448.dh alicePublic bobPrivate))+    , testCase "1" (aliceMultBob @=? B.convert (Ed448.dh bobPublic alicePrivate))+    ]++tests = testGroup "Ed448"+    [ testGroup "KATs" katTests+    ]
+ tests/KAT_HKDF.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE OverloadedStrings #-}+module KAT_HKDF (tests) where++import qualified Crypto.KDF.HKDF as HKDF+import Crypto.Hash (MD5(..), SHA1(..), SHA256(..)+                   , Keccak_224(..), Keccak_256(..), Keccak_384(..), Keccak_512(..)+                   , SHA3_224(..), SHA3_256(..), SHA3_384(..), SHA3_512(..)+                   , HashAlgorithm, digestFromByteString)+import qualified Data.ByteString as B++import Imports+++data KDFVector hash = KDFVector+    { kdfIKM    :: ByteString+    , kdfSalt   :: ByteString+    , kdfInfo   :: ByteString+    , kdfResult :: ByteString+    }++sha256KDFVectors :: [KDFVector SHA256]+sha256KDFVectors =+    [ KDFVector+        "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"+        (B.pack [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c])+        "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"+        "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36\x2f\x2a\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65"+    , KDFVector+        (B.pack [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f])+        (B.pack [0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf])+        (B.pack [0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff])+        (B.pack [0xb1,0x1e,0x39,0x8d,0xc8,0x03,0x27,0xa1,0xc8,0xe7,0xf7,0x8c,0x59,0x6a,0x49,0x34,0x4f,0x01,0x2e,0xda,0x2d,0x4e,0xfa,0xd8,0xa0,0x50,0xcc,0x4c,0x19,0xaf,0xa9,0x7c,0x59,0x04,0x5a,0x99,0xca,0xc7,0x82,0x72,0x71,0xcb,0x41,0xc6,0x5e,0x59,0x0e,0x09,0xda,0x32,0x75,0x60,0x0c,0x2f,0x09,0xb8,0x36,0x77,0x93,0xa9,0xac,0xa3,0xdb,0x71,0xcc,0x30,0xc5,0x81,0x79,0xec,0x3e,0x87,0xc1,0x4c,0x01,0xd5,0xc1,0xf3,0x43,0x4f,0x1d,0x87])+    ]++kdfTests :: [TestTree]+kdfTests =+    [ testGroup "sha256" $ concatMap toKDFTest $ zip is sha256KDFVectors+    ]+  where toKDFTest (i, kdfVector) =+            [ testCase (show i) (t HKDF.extract kdfVector)+            ]++        t :: HashAlgorithm a => (ByteString -> ByteString -> HKDF.PRK a) -> KDFVector a -> Assertion+        t ext v =+            let prk = ext (kdfSalt v) (kdfIKM v)+             in kdfResult v @=? HKDF.expand prk (kdfInfo v) (B.length $ kdfResult v)++        is :: [Int]+        is = [1..]+++tests = testGroup "HKDF"+    [ testGroup "KATs" kdfTests+    ]
tests/Tests.hs view
@@ -11,8 +11,10 @@ import qualified ChaCha import qualified ChaChaPoly1305 import qualified KAT_HMAC+import qualified KAT_HKDF import qualified KAT_PBKDF2 import qualified KAT_Curve25519+import qualified KAT_Ed448 import qualified KAT_Ed25519 import qualified KAT_PubKey import qualified KAT_Scrypt@@ -36,12 +38,14 @@         , KAT_HMAC.tests         ]     , KAT_Curve25519.tests+    , KAT_Ed448.tests     , KAT_Ed25519.tests     , KAT_PubKey.tests     , testGroup "KDF"         [ KAT_PBKDF2.tests         , KAT_Scrypt.tests         , BCrypt.tests+        , KAT_HKDF.tests         ]     , testGroup "block-cipher"         [ KAT_AES.tests