Merge pull request #132 from NicolasDP/master
Add Fast PBKDF2 for SHA1, SHA256 and SHA512
This commit is contained in:
commit
e3ef0684f9
@ -8,17 +8,23 @@
|
|||||||
-- Password Based Key Derivation Function 2
|
-- Password Based Key Derivation Function 2
|
||||||
--
|
--
|
||||||
{-# LANGUAGE BangPatterns #-}
|
{-# LANGUAGE BangPatterns #-}
|
||||||
|
{-# LANGUAGE ForeignFunctionInterface #-}
|
||||||
|
|
||||||
module Crypto.KDF.PBKDF2
|
module Crypto.KDF.PBKDF2
|
||||||
( PRF
|
( PRF
|
||||||
, prfHMAC
|
, prfHMAC
|
||||||
, Parameters(..)
|
, Parameters(..)
|
||||||
, generate
|
, generate
|
||||||
|
, fastPBKDF2_SHA1
|
||||||
|
, fastPBKDF2_SHA256
|
||||||
|
, fastPBKDF2_SHA512
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
import Foreign.Marshal.Alloc
|
import Foreign.Marshal.Alloc
|
||||||
import Foreign.Ptr (plusPtr)
|
import Foreign.Ptr (plusPtr, Ptr)
|
||||||
|
import Foreign.C.Types (CUInt(..), CInt(..), CSize(..))
|
||||||
|
|
||||||
import Crypto.Hash (HashAlgorithm)
|
import Crypto.Hash (HashAlgorithm)
|
||||||
import qualified Crypto.MAC.HMAC as HMAC
|
import qualified Crypto.MAC.HMAC as HMAC
|
||||||
@ -100,3 +106,70 @@ generate prf params password salt =
|
|||||||
c = fromIntegral ((w `shiftR` 8) .&. 0xff)
|
c = fromIntegral ((w `shiftR` 8) .&. 0xff)
|
||||||
d = fromIntegral (w .&. 0xff)
|
d = fromIntegral (w .&. 0xff)
|
||||||
{-# NOINLINE generate #-}
|
{-# NOINLINE generate #-}
|
||||||
|
|
||||||
|
fastPBKDF2_SHA1 :: (ByteArrayAccess password, ByteArrayAccess salt, ByteArray out)
|
||||||
|
=> Parameters
|
||||||
|
-> password
|
||||||
|
-> salt
|
||||||
|
-> out
|
||||||
|
fastPBKDF2_SHA1 params password salt =
|
||||||
|
B.allocAndFreeze (outputLength params) $ \outPtr ->
|
||||||
|
B.withByteArray password $ \passPtr ->
|
||||||
|
B.withByteArray salt $ \saltPtr ->
|
||||||
|
c_cryptonite_fastpbkdf2_hmac_sha1
|
||||||
|
passPtr (fromIntegral $ B.length password)
|
||||||
|
saltPtr (fromIntegral $ B.length salt)
|
||||||
|
(fromIntegral $ iterCounts params)
|
||||||
|
outPtr (fromIntegral $ outputLength params)
|
||||||
|
|
||||||
|
fastPBKDF2_SHA256 :: (ByteArrayAccess password, ByteArrayAccess salt, ByteArray out)
|
||||||
|
=> Parameters
|
||||||
|
-> password
|
||||||
|
-> salt
|
||||||
|
-> out
|
||||||
|
fastPBKDF2_SHA256 params password salt =
|
||||||
|
B.allocAndFreeze (outputLength params) $ \outPtr ->
|
||||||
|
B.withByteArray password $ \passPtr ->
|
||||||
|
B.withByteArray salt $ \saltPtr ->
|
||||||
|
c_cryptonite_fastpbkdf2_hmac_sha256
|
||||||
|
passPtr (fromIntegral $ B.length password)
|
||||||
|
saltPtr (fromIntegral $ B.length salt)
|
||||||
|
(fromIntegral $ iterCounts params)
|
||||||
|
outPtr (fromIntegral $ outputLength params)
|
||||||
|
|
||||||
|
fastPBKDF2_SHA512 :: (ByteArrayAccess password, ByteArrayAccess salt, ByteArray out)
|
||||||
|
=> Parameters
|
||||||
|
-> password
|
||||||
|
-> salt
|
||||||
|
-> out
|
||||||
|
fastPBKDF2_SHA512 params password salt =
|
||||||
|
B.allocAndFreeze (outputLength params) $ \outPtr ->
|
||||||
|
B.withByteArray password $ \passPtr ->
|
||||||
|
B.withByteArray salt $ \saltPtr ->
|
||||||
|
c_cryptonite_fastpbkdf2_hmac_sha512
|
||||||
|
passPtr (fromIntegral $ B.length password)
|
||||||
|
saltPtr (fromIntegral $ B.length salt)
|
||||||
|
(fromIntegral $ iterCounts params)
|
||||||
|
outPtr (fromIntegral $ outputLength params)
|
||||||
|
|
||||||
|
|
||||||
|
foreign import ccall unsafe "cryptonite_pbkdf2.h cryptonite_fastpbkdf2_hmac_sha1"
|
||||||
|
c_cryptonite_fastpbkdf2_hmac_sha1 :: Ptr Word8 -> CSize
|
||||||
|
-> Ptr Word8 -> CSize
|
||||||
|
-> CUInt
|
||||||
|
-> Ptr Word8 -> CSize
|
||||||
|
-> IO ()
|
||||||
|
|
||||||
|
foreign import ccall unsafe "cryptonite_pbkdf2.h cryptonite_fastpbkdf2_hmac_sha256"
|
||||||
|
c_cryptonite_fastpbkdf2_hmac_sha256 :: Ptr Word8 -> CSize
|
||||||
|
-> Ptr Word8 -> CSize
|
||||||
|
-> CUInt
|
||||||
|
-> Ptr Word8 -> CSize
|
||||||
|
-> IO ()
|
||||||
|
|
||||||
|
foreign import ccall unsafe "cryptonite_pbkdf2.h cryptonite_fastpbkdf2_hmac_sha512"
|
||||||
|
c_cryptonite_fastpbkdf2_hmac_sha512 :: Ptr Word8 -> CSize
|
||||||
|
-> Ptr Word8 -> CSize
|
||||||
|
-> CUInt
|
||||||
|
-> Ptr Word8 -> CSize
|
||||||
|
-> IO ()
|
||||||
|
|||||||
59
benchs/PBKDF2.hs
Normal file
59
benchs/PBKDF2.hs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE PackageImports #-}
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import Criterion.Main
|
||||||
|
import Crypto.Hash.Algorithms as Crypto
|
||||||
|
import "cryptonite" Crypto.KDF.PBKDF2 as Crypto
|
||||||
|
import "fastpbkdf2" Crypto.KDF.PBKDF2 as Fast
|
||||||
|
import Data.ByteString as B
|
||||||
|
|
||||||
|
password :: ByteString
|
||||||
|
password = "password"
|
||||||
|
|
||||||
|
salt :: ByteString
|
||||||
|
salt = "salt"
|
||||||
|
|
||||||
|
runBench :: Int
|
||||||
|
-> (ByteString -> ByteString -> ByteString)
|
||||||
|
-> (ByteString -> ByteString -> ByteString)
|
||||||
|
-> (ByteString -> ByteString -> ByteString)
|
||||||
|
-> Benchmark
|
||||||
|
runBench iter cryptonite fastCryptonite fastBinding =
|
||||||
|
bgroup (show iter)
|
||||||
|
[ bench "cryptonite" $ whnf (cryptonite password) salt
|
||||||
|
, bench "cryptonite-fast" $ whnf (fastCryptonite password) salt
|
||||||
|
, bench "fastpbkdf2-hs" $ whnf (fastBinding password) salt
|
||||||
|
]
|
||||||
|
|
||||||
|
makeBench :: (Parameters -> ByteString -> ByteString -> ByteString)
|
||||||
|
-> (Parameters -> ByteString -> ByteString -> ByteString)
|
||||||
|
-> (ByteString -> ByteString -> Int -> Int -> ByteString)
|
||||||
|
-> [Benchmark]
|
||||||
|
makeBench cryptonite fastCryptonite fastBinding =
|
||||||
|
[ runBench 1
|
||||||
|
(cryptonite (Parameters 1 32))
|
||||||
|
(fastCryptonite (Parameters 1 32))
|
||||||
|
(\p s -> fastBinding p s 1 32)
|
||||||
|
, runBench 10000
|
||||||
|
(cryptonite (Parameters 10000 32))
|
||||||
|
(fastCryptonite (Parameters 10000 32))
|
||||||
|
(\p s -> fastBinding p s 10000 32)
|
||||||
|
]
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = defaultMain
|
||||||
|
[ bgroup "SHA1" $ makeBench
|
||||||
|
(Crypto.generate (Crypto.prfHMAC Crypto.SHA1))
|
||||||
|
(Crypto.fastPBKDF2_SHA1)
|
||||||
|
(Fast.fastpbkdf2_hmac_sha1)
|
||||||
|
, bgroup "SHA256" $ makeBench
|
||||||
|
(Crypto.generate (Crypto.prfHMAC Crypto.SHA256))
|
||||||
|
(Crypto.fastPBKDF2_SHA256)
|
||||||
|
(Fast.fastpbkdf2_hmac_sha256)
|
||||||
|
, bgroup "SHA512" $ makeBench
|
||||||
|
(Crypto.generate (Crypto.prfHMAC Crypto.SHA512))
|
||||||
|
(Crypto.fastPBKDF2_SHA512)
|
||||||
|
(Fast.fastpbkdf2_hmac_sha512)
|
||||||
|
]
|
||||||
419
cbits/cryptonite_pbkdf2.c
Normal file
419
cbits/cryptonite_pbkdf2.c
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* fast-pbkdf2 - Optimal PBKDF2-HMAC calculation
|
||||||
|
* Written in 2015 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||||
|
* Ported to cryptonite in 2017 by Nicolas Di Prima <nicolas@primetype.co.uk>
|
||||||
|
*
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all
|
||||||
|
* copyright and related and neighboring rights to this software to the
|
||||||
|
* public domain worldwide. This software is distributed without any
|
||||||
|
* warranty.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the CC0 Public Domain Dedication
|
||||||
|
* along with this software. If not, see
|
||||||
|
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cryptonite_pbkdf2.h"
|
||||||
|
#include "cryptonite_bitfn.h"
|
||||||
|
#include "cryptonite_sha1.h"
|
||||||
|
#include "cryptonite_sha256.h"
|
||||||
|
#include "cryptonite_sha512.h"
|
||||||
|
|
||||||
|
/* --- MSVC doesn't support C99 --- */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define restrict
|
||||||
|
#define _Pragma __pragma
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* --- Common useful things --- */
|
||||||
|
#define MIN(a, b) ((a) > (b)) ? (b) : (a)
|
||||||
|
|
||||||
|
static inline void write32_be(uint32_t n, uint8_t out[4])
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
*(uint32_t *)(out) = __builtin_bswap32(n);
|
||||||
|
#else
|
||||||
|
out[0] = (n >> 24) & 0xff;
|
||||||
|
out[1] = (n >> 16) & 0xff;
|
||||||
|
out[2] = (n >> 8) & 0xff;
|
||||||
|
out[3] = n & 0xff;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write64_be(uint64_t n, uint8_t out[8])
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
*(uint64_t *)(out) = __builtin_bswap64(n);
|
||||||
|
#else
|
||||||
|
write32_be((n >> 32) & 0xffffffff, out);
|
||||||
|
write32_be(n & 0xffffffff, out + 4);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Optional OpenMP parallelisation of consecutive blocks --- */
|
||||||
|
#ifdef WITH_OPENMP
|
||||||
|
# define OPENMP_PARALLEL_FOR _Pragma("omp parallel for")
|
||||||
|
#else
|
||||||
|
# define OPENMP_PARALLEL_FOR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Prepare block (of blocksz bytes) to contain md padding denoting a msg-size
|
||||||
|
* message (in bytes). block has a prefix of used bytes.
|
||||||
|
*
|
||||||
|
* Message length is expressed in 32 bits (so suitable for sha1, sha256, sha512). */
|
||||||
|
static inline void md_pad(uint8_t *block, size_t blocksz, size_t used, size_t msg)
|
||||||
|
{
|
||||||
|
memset(block + used, 0, blocksz - used - 4);
|
||||||
|
block[used] = 0x80;
|
||||||
|
block += blocksz - 4;
|
||||||
|
write32_be((uint32_t) (msg * 8), block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function/type names for hash-specific things. */
|
||||||
|
#define HMAC_CTX(_name) HMAC_ ## _name ## _ctx
|
||||||
|
#define HMAC_INIT(_name) HMAC_ ## _name ## _init
|
||||||
|
#define HMAC_UPDATE(_name) HMAC_ ## _name ## _update
|
||||||
|
#define HMAC_FINAL(_name) HMAC_ ## _name ## _final
|
||||||
|
|
||||||
|
#define PBKDF2_F(_name) pbkdf2_f_ ## _name
|
||||||
|
#define PBKDF2(_name) pbkdf2_ ## _name
|
||||||
|
|
||||||
|
/* This macro expands to decls for the whole implementation for a given
|
||||||
|
* hash function. Arguments are:
|
||||||
|
*
|
||||||
|
* _name like 'sha1', added to symbol names
|
||||||
|
* _blocksz block size, in bytes
|
||||||
|
* _hashsz digest output, in bytes
|
||||||
|
* _ctx hash context type
|
||||||
|
* _init hash context initialisation function
|
||||||
|
* args: (_ctx *c)
|
||||||
|
* _update hash context update function
|
||||||
|
* args: (_ctx *c, const void *data, size_t ndata)
|
||||||
|
* _final hash context finish function
|
||||||
|
* args: (void *out, _ctx *c)
|
||||||
|
* _xform hash context raw block update function
|
||||||
|
* args: (_ctx *c, const void *data)
|
||||||
|
* _xcpy hash context raw copy function (only need copy hash state)
|
||||||
|
* args: (_ctx * restrict out, const _ctx *restrict in)
|
||||||
|
* _xtract hash context state extraction
|
||||||
|
* args: args (_ctx *restrict c, uint8_t *restrict out)
|
||||||
|
* _xxor hash context xor function (only need xor hash state)
|
||||||
|
* args: (_ctx *restrict out, const _ctx *restrict in)
|
||||||
|
*
|
||||||
|
* The resulting function is named PBKDF2(_name).
|
||||||
|
*/
|
||||||
|
#define DECL_PBKDF2(_name, _blocksz, _hashsz, _ctx, \
|
||||||
|
_init, _update, _xform, _final, _xcpy, _xtract, _xxor) \
|
||||||
|
typedef struct { \
|
||||||
|
_ctx inner; \
|
||||||
|
_ctx outer; \
|
||||||
|
} HMAC_CTX(_name); \
|
||||||
|
\
|
||||||
|
static inline void HMAC_INIT(_name)(HMAC_CTX(_name) *ctx, \
|
||||||
|
const uint8_t *key, size_t nkey) \
|
||||||
|
{ \
|
||||||
|
/* Prepare key: */ \
|
||||||
|
uint8_t k[_blocksz]; \
|
||||||
|
\
|
||||||
|
/* Shorten long keys. */ \
|
||||||
|
if (nkey > _blocksz) \
|
||||||
|
{ \
|
||||||
|
_init(&ctx->inner); \
|
||||||
|
_update(&ctx->inner, key, nkey); \
|
||||||
|
_final(&ctx->inner, k); \
|
||||||
|
\
|
||||||
|
key = k; \
|
||||||
|
nkey = _hashsz; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Standard doesn't cover case where blocksz < hashsz. */ \
|
||||||
|
assert(nkey <= _blocksz); \
|
||||||
|
\
|
||||||
|
/* Right zero-pad short keys. */ \
|
||||||
|
if (k != key) \
|
||||||
|
memcpy(k, key, nkey); \
|
||||||
|
if (_blocksz > nkey) \
|
||||||
|
memset(k + nkey, 0, _blocksz - nkey); \
|
||||||
|
\
|
||||||
|
/* Start inner hash computation */ \
|
||||||
|
uint8_t blk_inner[_blocksz]; \
|
||||||
|
uint8_t blk_outer[_blocksz]; \
|
||||||
|
\
|
||||||
|
for (size_t i = 0; i < _blocksz; i++) \
|
||||||
|
{ \
|
||||||
|
blk_inner[i] = 0x36 ^ k[i]; \
|
||||||
|
blk_outer[i] = 0x5c ^ k[i]; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
_init(&ctx->inner); \
|
||||||
|
_update(&ctx->inner, blk_inner, sizeof blk_inner); \
|
||||||
|
\
|
||||||
|
/* And outer. */ \
|
||||||
|
_init(&ctx->outer); \
|
||||||
|
_update(&ctx->outer, blk_outer, sizeof blk_outer); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void HMAC_UPDATE(_name)(HMAC_CTX(_name) *ctx, \
|
||||||
|
const void *data, size_t ndata) \
|
||||||
|
{ \
|
||||||
|
_update(&ctx->inner, data, ndata); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void HMAC_FINAL(_name)(HMAC_CTX(_name) *ctx, \
|
||||||
|
uint8_t out[_hashsz]) \
|
||||||
|
{ \
|
||||||
|
_final(&ctx->inner, out); \
|
||||||
|
_update(&ctx->outer, out, _hashsz); \
|
||||||
|
_final(&ctx->outer, out); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
\
|
||||||
|
/* --- PBKDF2 --- */ \
|
||||||
|
static inline void PBKDF2_F(_name)(const HMAC_CTX(_name) *startctx, \
|
||||||
|
uint32_t counter, \
|
||||||
|
const uint8_t *salt, size_t nsalt, \
|
||||||
|
uint32_t iterations, \
|
||||||
|
uint8_t *out) \
|
||||||
|
{ \
|
||||||
|
uint8_t countbuf[4]; \
|
||||||
|
write32_be(counter, countbuf); \
|
||||||
|
\
|
||||||
|
/* Prepare loop-invariant padding block. */ \
|
||||||
|
uint8_t Ublock[_blocksz]; \
|
||||||
|
md_pad(Ublock, _blocksz, _hashsz, _blocksz + _hashsz); \
|
||||||
|
\
|
||||||
|
/* First iteration: \
|
||||||
|
* U_1 = PRF(P, S || INT_32_BE(i)) \
|
||||||
|
*/ \
|
||||||
|
HMAC_CTX(_name) ctx = *startctx; \
|
||||||
|
HMAC_UPDATE(_name)(&ctx, salt, nsalt); \
|
||||||
|
HMAC_UPDATE(_name)(&ctx, countbuf, sizeof countbuf); \
|
||||||
|
HMAC_FINAL(_name)(&ctx, Ublock); \
|
||||||
|
_ctx result = ctx.outer; \
|
||||||
|
\
|
||||||
|
/* Subsequent iterations: \
|
||||||
|
* U_c = PRF(P, U_{c-1}) \
|
||||||
|
*/ \
|
||||||
|
for (uint32_t i = 1; i < iterations; i++) \
|
||||||
|
{ \
|
||||||
|
/* Complete inner hash with previous U */ \
|
||||||
|
_xcpy(&ctx.inner, &startctx->inner); \
|
||||||
|
_xform(&ctx.inner, Ublock); \
|
||||||
|
_xtract(&ctx.inner, Ublock); \
|
||||||
|
/* Complete outer hash with inner output */ \
|
||||||
|
_xcpy(&ctx.outer, &startctx->outer); \
|
||||||
|
_xform(&ctx.outer, Ublock); \
|
||||||
|
_xtract(&ctx.outer, Ublock); \
|
||||||
|
_xxor(&result, &ctx.outer); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Reform result into output buffer. */ \
|
||||||
|
_xtract(&result, out); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void PBKDF2(_name)(const uint8_t *pw, size_t npw, \
|
||||||
|
const uint8_t *salt, size_t nsalt, \
|
||||||
|
uint32_t iterations, \
|
||||||
|
uint8_t *out, size_t nout) \
|
||||||
|
{ \
|
||||||
|
assert(iterations); \
|
||||||
|
assert(out && nout); \
|
||||||
|
\
|
||||||
|
/* Starting point for inner loop. */ \
|
||||||
|
HMAC_CTX(_name) ctx; \
|
||||||
|
HMAC_INIT(_name)(&ctx, pw, npw); \
|
||||||
|
\
|
||||||
|
/* How many blocks do we need? */ \
|
||||||
|
uint32_t blocks_needed = (uint32_t)(nout + _hashsz - 1) / _hashsz; \
|
||||||
|
\
|
||||||
|
OPENMP_PARALLEL_FOR \
|
||||||
|
for (uint32_t counter = 1; counter <= blocks_needed; counter++) \
|
||||||
|
{ \
|
||||||
|
uint8_t block[_hashsz]; \
|
||||||
|
PBKDF2_F(_name)(&ctx, counter, salt, nsalt, iterations, block); \
|
||||||
|
\
|
||||||
|
size_t offset = (counter - 1) * _hashsz; \
|
||||||
|
size_t taken = MIN(nout - offset, _hashsz); \
|
||||||
|
memcpy(out + offset, block, taken); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha1_extract(struct sha1_ctx *restrict ctx, uint8_t *restrict out)
|
||||||
|
{
|
||||||
|
write32_be(ctx->h[0], out);
|
||||||
|
write32_be(ctx->h[1], out + 4);
|
||||||
|
write32_be(ctx->h[2], out + 8);
|
||||||
|
write32_be(ctx->h[3], out + 12);
|
||||||
|
write32_be(ctx->h[4], out + 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha1_cpy(struct sha1_ctx *restrict out, const struct sha1_ctx *restrict in)
|
||||||
|
{
|
||||||
|
out->h[0] = in->h[0];
|
||||||
|
out->h[1] = in->h[1];
|
||||||
|
out->h[2] = in->h[2];
|
||||||
|
out->h[3] = in->h[3];
|
||||||
|
out->h[4] = in->h[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha1_xor(struct sha1_ctx *restrict out, const struct sha1_ctx *restrict in)
|
||||||
|
{
|
||||||
|
out->h[0] ^= in->h[0];
|
||||||
|
out->h[1] ^= in->h[1];
|
||||||
|
out->h[2] ^= in->h[2];
|
||||||
|
out->h[3] ^= in->h[3];
|
||||||
|
out->h[4] ^= in->h[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
void cryptonite_sha1_transform(struct sha1_ctx* ctx, uint8_t block[SHA1_BLOCK_SIZE])
|
||||||
|
{
|
||||||
|
cryptonite_sha1_update(ctx, block, SHA1_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_PBKDF2(sha1,
|
||||||
|
SHA1_BLOCK_SIZE,
|
||||||
|
SHA1_DIGEST_SIZE,
|
||||||
|
struct sha1_ctx,
|
||||||
|
cryptonite_sha1_init,
|
||||||
|
cryptonite_sha1_update,
|
||||||
|
cryptonite_sha1_transform,
|
||||||
|
cryptonite_sha1_finalize,
|
||||||
|
sha1_cpy,
|
||||||
|
sha1_extract,
|
||||||
|
sha1_xor);
|
||||||
|
|
||||||
|
static inline void sha256_extract(struct sha256_ctx *restrict ctx, uint8_t *restrict out)
|
||||||
|
{
|
||||||
|
write32_be(ctx->h[0], out);
|
||||||
|
write32_be(ctx->h[1], out + 4);
|
||||||
|
write32_be(ctx->h[2], out + 8);
|
||||||
|
write32_be(ctx->h[3], out + 12);
|
||||||
|
write32_be(ctx->h[4], out + 16);
|
||||||
|
write32_be(ctx->h[5], out + 20);
|
||||||
|
write32_be(ctx->h[6], out + 24);
|
||||||
|
write32_be(ctx->h[7], out + 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha256_cpy(struct sha256_ctx *restrict out, const struct sha256_ctx *restrict in)
|
||||||
|
{
|
||||||
|
out->h[0] = in->h[0];
|
||||||
|
out->h[1] = in->h[1];
|
||||||
|
out->h[2] = in->h[2];
|
||||||
|
out->h[3] = in->h[3];
|
||||||
|
out->h[4] = in->h[4];
|
||||||
|
out->h[5] = in->h[5];
|
||||||
|
out->h[6] = in->h[6];
|
||||||
|
out->h[7] = in->h[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha256_xor(struct sha256_ctx *restrict out, const struct sha256_ctx *restrict in)
|
||||||
|
{
|
||||||
|
out->h[0] ^= in->h[0];
|
||||||
|
out->h[1] ^= in->h[1];
|
||||||
|
out->h[2] ^= in->h[2];
|
||||||
|
out->h[3] ^= in->h[3];
|
||||||
|
out->h[4] ^= in->h[4];
|
||||||
|
out->h[5] ^= in->h[5];
|
||||||
|
out->h[6] ^= in->h[6];
|
||||||
|
out->h[7] ^= in->h[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
void cryptonite_sha256_transform(struct sha256_ctx* ctx, uint8_t block[SHA256_BLOCK_SIZE])
|
||||||
|
{
|
||||||
|
cryptonite_sha256_update(ctx, block, SHA256_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_PBKDF2(sha256,
|
||||||
|
SHA256_BLOCK_SIZE,
|
||||||
|
SHA256_DIGEST_SIZE,
|
||||||
|
struct sha256_ctx,
|
||||||
|
cryptonite_sha256_init,
|
||||||
|
cryptonite_sha256_update,
|
||||||
|
cryptonite_sha256_transform,
|
||||||
|
cryptonite_sha256_finalize,
|
||||||
|
sha256_cpy,
|
||||||
|
sha256_extract,
|
||||||
|
sha256_xor);
|
||||||
|
|
||||||
|
static inline void sha512_extract(struct sha512_ctx *restrict ctx, uint8_t *restrict out)
|
||||||
|
{
|
||||||
|
write64_be(ctx->h[0], out);
|
||||||
|
write64_be(ctx->h[1], out + 8);
|
||||||
|
write64_be(ctx->h[2], out + 16);
|
||||||
|
write64_be(ctx->h[3], out + 24);
|
||||||
|
write64_be(ctx->h[4], out + 32);
|
||||||
|
write64_be(ctx->h[5], out + 40);
|
||||||
|
write64_be(ctx->h[6], out + 48);
|
||||||
|
write64_be(ctx->h[7], out + 56);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha512_cpy(struct sha512_ctx *restrict out, const struct sha512_ctx *restrict in)
|
||||||
|
{
|
||||||
|
out->h[0] = in->h[0];
|
||||||
|
out->h[1] = in->h[1];
|
||||||
|
out->h[2] = in->h[2];
|
||||||
|
out->h[3] = in->h[3];
|
||||||
|
out->h[4] = in->h[4];
|
||||||
|
out->h[5] = in->h[5];
|
||||||
|
out->h[6] = in->h[6];
|
||||||
|
out->h[7] = in->h[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sha512_xor(struct sha512_ctx *restrict out, const struct sha512_ctx *restrict in)
|
||||||
|
{
|
||||||
|
out->h[0] ^= in->h[0];
|
||||||
|
out->h[1] ^= in->h[1];
|
||||||
|
out->h[2] ^= in->h[2];
|
||||||
|
out->h[3] ^= in->h[3];
|
||||||
|
out->h[4] ^= in->h[4];
|
||||||
|
out->h[5] ^= in->h[5];
|
||||||
|
out->h[6] ^= in->h[6];
|
||||||
|
out->h[7] ^= in->h[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
void cryptonite_sha512_transform(struct sha512_ctx* ctx, uint8_t block[SHA512_BLOCK_SIZE])
|
||||||
|
{
|
||||||
|
cryptonite_sha512_update(ctx, block, SHA512_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_PBKDF2(sha512,
|
||||||
|
SHA512_BLOCK_SIZE,
|
||||||
|
SHA512_DIGEST_SIZE,
|
||||||
|
struct sha512_ctx,
|
||||||
|
cryptonite_sha512_init,
|
||||||
|
cryptonite_sha512_update,
|
||||||
|
cryptonite_sha512_transform,
|
||||||
|
cryptonite_sha512_finalize,
|
||||||
|
sha512_cpy,
|
||||||
|
sha512_extract,
|
||||||
|
sha512_xor);
|
||||||
|
|
||||||
|
void cryptonite_fastpbkdf2_hmac_sha1( const uint8_t *pw, size_t npw
|
||||||
|
, const uint8_t *salt, size_t nsalt
|
||||||
|
, uint32_t iterations
|
||||||
|
, uint8_t *out, size_t nout
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PBKDF2(sha1)(pw, npw, salt, nsalt, iterations, out, nout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cryptonite_fastpbkdf2_hmac_sha256( const uint8_t *pw, size_t npw
|
||||||
|
, const uint8_t *salt, size_t nsalt
|
||||||
|
, uint32_t iterations
|
||||||
|
, uint8_t *out, size_t nout
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PBKDF2(sha256)(pw, npw, salt, nsalt, iterations, out, nout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cryptonite_fastpbkdf2_hmac_sha512( const uint8_t *pw, size_t npw
|
||||||
|
, const uint8_t *salt, size_t nsalt
|
||||||
|
, uint32_t iterations
|
||||||
|
, uint8_t *out, size_t nout
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PBKDF2(sha512)(pw, npw, salt, nsalt, iterations, out, nout);
|
||||||
|
}
|
||||||
31
cbits/cryptonite_pbkdf2.h
Normal file
31
cbits/cryptonite_pbkdf2.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef CRYPTONITE_PBKDF2_H_
|
||||||
|
#define CRYPTONITE_PBKDF2_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cryptonite_fastpbkdf2_hmac_sha1( const uint8_t *pw, size_t npw
|
||||||
|
, const uint8_t *salt, size_t nsalt
|
||||||
|
, uint32_t iterations
|
||||||
|
, uint8_t *out, size_t nout
|
||||||
|
);
|
||||||
|
void cryptonite_fastpbkdf2_hmac_sha256( const uint8_t *pw, size_t npw
|
||||||
|
, const uint8_t *salt, size_t nsalt
|
||||||
|
, uint32_t iterations
|
||||||
|
, uint8_t *out, size_t nout
|
||||||
|
);
|
||||||
|
void cryptonite_fastpbkdf2_hmac_sha512( const uint8_t *pw, size_t npw
|
||||||
|
, const uint8_t *salt, size_t nsalt
|
||||||
|
, uint32_t iterations
|
||||||
|
, uint8_t *out, size_t nout
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -26,10 +26,12 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
# define SHA1_BLOCK_SIZE 64
|
||||||
|
|
||||||
struct sha1_ctx
|
struct sha1_ctx
|
||||||
{
|
{
|
||||||
uint64_t sz;
|
uint64_t sz;
|
||||||
uint8_t buf[64];
|
uint8_t buf[SHA1_BLOCK_SIZE];
|
||||||
uint32_t h[5];
|
uint32_t h[5];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SHA256_BLOCK_SIZE 64
|
||||||
|
|
||||||
struct sha256_ctx
|
struct sha256_ctx
|
||||||
{
|
{
|
||||||
uint64_t sz;
|
uint64_t sz;
|
||||||
|
|||||||
@ -26,10 +26,12 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
# define SHA512_BLOCK_SIZE 128
|
||||||
|
|
||||||
struct sha512_ctx
|
struct sha512_ctx
|
||||||
{
|
{
|
||||||
uint64_t sz[2];
|
uint64_t sz[2];
|
||||||
uint8_t buf[128];
|
uint8_t buf[SHA512_BLOCK_SIZE];
|
||||||
uint64_t h[8];
|
uint64_t h[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -240,6 +240,7 @@ Library
|
|||||||
, cbits/cryptonite_tiger.c
|
, cbits/cryptonite_tiger.c
|
||||||
, cbits/cryptonite_whirlpool.c
|
, cbits/cryptonite_whirlpool.c
|
||||||
, cbits/cryptonite_scrypt.c
|
, cbits/cryptonite_scrypt.c
|
||||||
|
, cbits/cryptonite_pbkdf2.c
|
||||||
include-dirs: cbits cbits/ed25519
|
include-dirs: cbits cbits/ed25519
|
||||||
|
|
||||||
if arch(x86_64)
|
if arch(x86_64)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
-- from <http://www.ietf.org/rfc/rfc6070.txt>
|
-- from <http://www.ietf.org/rfc/rfc6070.txt>
|
||||||
module KAT_PBKDF2 (tests) where
|
module KAT_PBKDF2 (tests) where
|
||||||
|
|
||||||
import Crypto.Hash (SHA1(..), SHA256(..))
|
import Crypto.Hash (SHA1(..), SHA256(..), SHA512(..))
|
||||||
import qualified Crypto.KDF.PBKDF2 as PBKDF2
|
import qualified Crypto.KDF.PBKDF2 as PBKDF2
|
||||||
|
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
@ -42,14 +42,48 @@ vectors_hmac_sha256 =
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
vectors_hmac_sha512 :: [ (VectParams, ByteString) ]
|
||||||
|
vectors_hmac_sha512 =
|
||||||
|
[ ( ("password", "salt", 1, 32)
|
||||||
|
, "\x86\x7f\x70\xcf\x1a\xde\x02\xcf\xf3\x75\x25\x99\xa3\xa5\x3d\xc4\xaf\x34\xc7\xa6\x69\x81\x5a\xe5\xd5\x13\x55\x4e\x1c\x8c\xf2\x52"
|
||||||
|
)
|
||||||
|
, ( ("password", "salt", 2, 32)
|
||||||
|
, "\xe1\xd9\xc1\x6a\xa6\x81\x70\x8a\x45\xf5\xc7\xc4\xe2\x15\xce\xb6\x6e\x01\x1a\x2e\x9f\x00\x40\x71\x3f\x18\xae\xfd\xb8\x66\xd5\x3c"
|
||||||
|
)
|
||||||
|
, ( ("password", "salt", 4096, 32)
|
||||||
|
, "\xd1\x97\xb1\xb3\x3d\xb0\x14\x3e\x01\x8b\x12\xf3\xd1\xd1\x47\x9e\x6c\xde\xbd\xcc\x97\xc5\xc0\xf8\x7f\x69\x02\xe0\x72\xf4\x57\xb5"
|
||||||
|
)
|
||||||
|
, ( ("passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", 1, 72)
|
||||||
|
, "n\x23\xf2\x76\x38\x08\x4b\x0f\x7e\xa1\x73\x4e\x0d\x98\x41\xf5\x5d\xd2\x9e\xa6\x0a\x83\x44\x66\xf3\x39\x6b\xac\x80\x1f\xac\x1e\xeb\x63\x80\x2f\x03\xa0\xb4\xac\xd7\x60\x3e\x36\x99\xc8\xb7\x44\x37\xbe\x83\xff\x01\xad\x7f\x55\xda\xc1\xef\x60\xf4\xd5\x64\x80\xc3\x5e\xe6\x8f\xd5\x2c\x69\x36"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
tests = testGroup "PBKDF2"
|
tests = testGroup "PBKDF2"
|
||||||
[ testGroup "KATs-HMAC-SHA1" (katTests (PBKDF2.prfHMAC SHA1) vectors_hmac_sha1)
|
[ testGroup "KATs-HMAC-SHA1" (katTests (PBKDF2.prfHMAC SHA1) vectors_hmac_sha1)
|
||||||
|
, testGroup "KATs-HMAC-SHA1 (fast)" (katTestFastPBKDF2_SHA1 vectors_hmac_sha1)
|
||||||
, testGroup "KATs-HMAC-SHA256" (katTests (PBKDF2.prfHMAC SHA256) vectors_hmac_sha256)
|
, testGroup "KATs-HMAC-SHA256" (katTests (PBKDF2.prfHMAC SHA256) vectors_hmac_sha256)
|
||||||
|
, testGroup "KATs-HMAC-SHA256 (fast)" (katTestFastPBKDF2_SHA256 vectors_hmac_sha256)
|
||||||
|
, testGroup "KATs-HMAC-SHA512" (katTests (PBKDF2.prfHMAC SHA512) vectors_hmac_sha512)
|
||||||
|
, testGroup "KATs-HMAC-SHA512 (fast)" (katTestFastPBKDF2_SHA512 vectors_hmac_sha512)
|
||||||
]
|
]
|
||||||
where katTests prf vects = map (toKatTest prf) $ zip is vects
|
where katTests prf vects = map (toKatTest prf) $ zip is vects
|
||||||
|
|
||||||
toKatTest prf (i, ((pass, salt, iter, dkLen), output)) =
|
toKatTest prf (i, ((pass, salt, iter, dkLen), output)) =
|
||||||
testCase (show i) (output @=? PBKDF2.generate prf (PBKDF2.Parameters iter dkLen) pass salt)
|
testCase (show i) (output @=? PBKDF2.generate prf (PBKDF2.Parameters iter dkLen) pass salt)
|
||||||
|
|
||||||
|
katTestFastPBKDF2_SHA1 = map toKatTestFastPBKDF2_SHA1 . zip is
|
||||||
|
toKatTestFastPBKDF2_SHA1 (i, ((pass, salt, iter, dkLen), output)) =
|
||||||
|
testCase (show i) (output @=? PBKDF2.fastPBKDF2_SHA1 (PBKDF2.Parameters iter dkLen) pass salt)
|
||||||
|
|
||||||
|
katTestFastPBKDF2_SHA256 = map toKatTestFastPBKDF2_SHA256 . zip is
|
||||||
|
toKatTestFastPBKDF2_SHA256 (i, ((pass, salt, iter, dkLen), output)) =
|
||||||
|
testCase (show i) (output @=? PBKDF2.fastPBKDF2_SHA256 (PBKDF2.Parameters iter dkLen) pass salt)
|
||||||
|
|
||||||
|
katTestFastPBKDF2_SHA512 = map toKatTestFastPBKDF2_SHA512 . zip is
|
||||||
|
toKatTestFastPBKDF2_SHA512 (i, ((pass, salt, iter, dkLen), output)) =
|
||||||
|
testCase (show i) (output @=? PBKDF2.fastPBKDF2_SHA512 (PBKDF2.Parameters iter dkLen) pass salt)
|
||||||
|
|
||||||
|
|
||||||
is :: [Int]
|
is :: [Int]
|
||||||
is = [1..]
|
is = [1..]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user