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 +11/−0
- Crypto/Cipher/ChaChaPoly1305.hs +20/−7
- Crypto/Hash/Algorithms.hs +2/−0
- Crypto/Hash/Blake2s.hs +13/−1
- Crypto/Hash/Blake2sp.hs +13/−1
- Crypto/KDF/HKDF.hs +77/−0
- Crypto/MAC/HMAC.hs +1/−1
- Crypto/Number/Compat.hs +1/−1
- Crypto/PubKey/DSA.hs +7/−2
- Crypto/PubKey/Ed448.hs +102/−0
- cbits/cryptonite_bitfn.h +2/−0
- cbits/cryptonite_sysrand.c +0/−46
- cbits/ed448/x448.c +306/−0
- cbits/ed448/x448.h +25/−0
- cryptonite.cabal +21/−7
- tests/KAT_Ed448.hs +23/−0
- tests/KAT_HKDF.hs +54/−0
- tests/Tests.hs +4/−0
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