packages feed

argon2 (empty) → 1.0.0

raw patch · 11 files changed

+2296/−0 lines, 11 filesdep +basedep +bytestringdep +textsetup-changed

Dependencies added: base, bytestring, text, transformers

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016, Ollie Charles++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Ollie Charles nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT+OWNER 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ argon2.cabal view
@@ -0,0 +1,31 @@+-- Initial argon2.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                argon2+version:             1.0.0+synopsis:            Haskell bindings to libargon2 - the reference implementation of the Argon2 password-hashing function+-- description:         +homepage:            https://github.com/ocharles/argon2.git+license:             BSD3+license-file:        LICENSE+author:              Ollie Charles+maintainer:          ollie@ocharles.org.uk+-- copyright:           +-- category:            +build-type:          Simple+-- extra-source-files:  +cabal-version:       >=1.10++library+  exposed-modules:     Crypto.Argon2.FFI+                       Crypto.Argon2+  build-depends:       base >=4.8 && <4.9, bytestring, text, transformers+  hs-source-dirs:      src+  default-language:    Haskell2010+  c-sources: phc-winner-argon2/src/argon2.c+             phc-winner-argon2/src/core.c+             phc-winner-argon2/src/blake2/blake2b.c+             phc-winner-argon2/src/thread.c+             phc-winner-argon2/src/ref.c+             phc-winner-argon2/src/encoding.c+  include-dirs: phc-winner-argon2/src
+ phc-winner-argon2/src/argon2.c view
@@ -0,0 +1,398 @@+/*+ * Argon2 source code package+ *+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ *+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ *+ * 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 <stdint.h>+#include <string.h>+#include <stdlib.h>+#include <stdio.h>+#include <limits.h>++#include "argon2.h"+#include "encoding.h"+#include "core.h"++/* Error messages */+static const char *Argon2_ErrorMessage[] = {+    /*{ARGON2_OK, */ "OK",+    /*},++    {ARGON2_OUTPUT_PTR_NULL, */ "Output pointer is NULL",+    /*},++{ARGON2_OUTPUT_TOO_SHORT, */ "Output is too short",+    /*},+{ARGON2_OUTPUT_TOO_LONG, */ "Output is too long",+    /*},++{ARGON2_PWD_TOO_SHORT, */ "Password is too short",+    /*},+{ARGON2_PWD_TOO_LONG, */ "Password is too long",+    /*},++{ARGON2_SALT_TOO_SHORT, */ "Salt is too short",+    /*},+{ARGON2_SALT_TOO_LONG, */ "Salt is too long",+    /*},++{ARGON2_AD_TOO_SHORT, */ "Associated data is too short",+    /*},+{ARGON2_AD_TOO_LONG, */ "Associated date is too long",+    /*},++{ARGON2_SECRET_TOO_SHORT, */ "Secret is too short",+    /*},+{ARGON2_SECRET_TOO_LONG, */ "Secret is too long",+    /*},++{ARGON2_TIME_TOO_SMALL, */ "Time cost is too small",+    /*},+{ARGON2_TIME_TOO_LARGE, */ "Time cost is too large",+    /*},++{ARGON2_MEMORY_TOO_LITTLE, */ "Memory cost is too small",+    /*},+{ARGON2_MEMORY_TOO_MUCH, */ "Memory cost is too large",+    /*},++{ARGON2_LANES_TOO_FEW, */ "Too few lanes",+    /*},+{ARGON2_LANES_TOO_MANY, */ "Too many lanes",+    /*},++{ARGON2_PWD_PTR_MISMATCH, */ "Password pointer is NULL, but password length is not 0",+    /*},+{ARGON2_SALT_PTR_MISMATCH, */ "Salt pointer is NULL, but salt length is not 0",+    /*},+{ARGON2_SECRET_PTR_MISMATCH, */ "Secret pointer is NULL, but secret length is not 0",+    /*},+{ARGON2_AD_PTR_MISMATCH, */ "Associated data pointer is NULL, but ad length is not 0",+    /*},++{ARGON2_MEMORY_ALLOCATION_ERROR, */ "Memory allocation error",+    /*},++{ARGON2_FREE_MEMORY_CBK_NULL, */ "The free memory callback is NULL",+    /*},+{ARGON2_ALLOCATE_MEMORY_CBK_NULL, */ "The allocate memory callback is NULL",+    /*},++{ARGON2_INCORRECT_PARAMETER, */ "Argon2_Context context is NULL",+    /*},+{ARGON2_INCORRECT_TYPE, */ "There is no such version of Argon2",+    /*},++{ARGON2_OUT_PTR_MISMATCH, */ "Output pointer mismatch",+    /*},++{ARGON2_THREADS_TOO_FEW, */ "Not enough threads",+    /*},+{ARGON2_THREADS_TOO_MANY, */ "Too many threads",+    /*},+{ARGON2_MISSING_ARGS, */ "Missing arguments",+    /*},+{ARGON2_ENCODING_FAIL, */ "Encoding failed",+    /*},+{ARGON2_DECODING_FAIL, */ "Decoding failed", /*},*/+};+++int argon2_core(argon2_context *context, argon2_type type) {+    /* 1. Validate all inputs */+    int result = validate_inputs(context);+    uint32_t memory_blocks, segment_length;+    argon2_instance_t instance;++    if (ARGON2_OK != result) {+        return result;+    }++    if (Argon2_d != type && Argon2_i != type) {+        return ARGON2_INCORRECT_TYPE;+    }++    /* 2. Align memory size */+    /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */+    memory_blocks = context->m_cost;++    if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) {+        memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;+    }++    segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);+    /* Ensure that all segments have equal length */+    memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);++    instance.memory = NULL;+    instance.passes = context->t_cost;+    instance.memory_blocks = memory_blocks;+    instance.segment_length = segment_length;+    instance.lane_length = segment_length * ARGON2_SYNC_POINTS;+    instance.lanes = context->lanes;+    instance.threads = context->threads;+    instance.type = type;++    /* 3. Initialization: Hashing inputs, allocating memory, filling first+     * blocks+     */+    result = initialize(&instance, context);++    if (ARGON2_OK != result) {+        return result;+    }++    /* 4. Filling memory */+    fill_memory_blocks(&instance);++    /* 5. Finalization */+    finalize(context, &instance);++    return ARGON2_OK;+}+++int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,+                const uint32_t parallelism, const void *pwd,+                const size_t pwdlen, const void *salt, const size_t saltlen,+                void *hash, const size_t hashlen, char *encoded,+                const size_t encodedlen, argon2_type type) {++    argon2_context context;+    int result;+    uint8_t *out;++    /* Detect and reject overflowing sizes */+    /* TODO: This should probably be fixed in the function signature */+    if (pwdlen > UINT32_MAX) {+        return ARGON2_PWD_TOO_LONG;+    }++    if (hashlen > UINT32_MAX) {+        return ARGON2_OUTPUT_TOO_LONG;+    }++    if (saltlen > UINT32_MAX) {+        return ARGON2_SALT_TOO_LONG;+    }++    out = malloc(hashlen);+    if (!out) {+        return ARGON2_MEMORY_ALLOCATION_ERROR;+    }++    context.out = (uint8_t *)out;+    context.outlen = (uint32_t)hashlen;+    context.pwd = (uint8_t *)pwd;+    context.pwdlen = (uint32_t)pwdlen;+    context.salt = (uint8_t *)salt;+    context.saltlen = (uint32_t)saltlen;+    context.secret = NULL;+    context.secretlen = 0;+    context.ad = NULL;+    context.adlen = 0;+    context.t_cost = t_cost;+    context.m_cost = m_cost;+    context.lanes = parallelism;+    context.threads = parallelism;+    context.allocate_cbk = NULL;+    context.free_cbk = NULL;+    context.flags = ARGON2_DEFAULT_FLAGS;++    result = argon2_core(&context, type);++    if (result != ARGON2_OK) {+        memset(out, 0x00, hashlen);+        free(out);+        return result;+    }++    /* if raw hash requested, write it */+    if (hash) {+        memcpy(hash, out, hashlen);+    }++    /* if encoding requested, write it */+    if (encoded && encodedlen) {+        if (!encode_string(encoded, encodedlen, &context, type)) {+            memset(out, 0x00, hashlen);+            memset(encoded, 0x00, encodedlen);+            free(out);+            return ARGON2_ENCODING_FAIL;+        }+    }++    free(out);++    return ARGON2_OK;+}++int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,+                         const uint32_t parallelism, const void *pwd,+                         const size_t pwdlen, const void *salt,+                         const size_t saltlen, const size_t hashlen,+                         char *encoded, const size_t encodedlen) {++    return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,+                       NULL, hashlen, encoded, encodedlen, Argon2_i);+}++int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost,+                     const uint32_t parallelism, const void *pwd,+                     const size_t pwdlen, const void *salt,+                     const size_t saltlen, void *hash, const size_t hashlen) {++    return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,+                       hash, hashlen, NULL, 0, Argon2_i);+}++int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,+                         const uint32_t parallelism, const void *pwd,+                         const size_t pwdlen, const void *salt,+                         const size_t saltlen, const size_t hashlen,+                         char *encoded, const size_t encodedlen) {++    return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,+                       NULL, hashlen, encoded, encodedlen, Argon2_d);+}++int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,+                     const uint32_t parallelism, const void *pwd,+                     const size_t pwdlen, const void *salt,+                     const size_t saltlen, void *hash, const size_t hashlen) {++    return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,+                       hash, hashlen, NULL, 0, Argon2_d);+}++int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) {+    size_t i;+    uint8_t d = 0U;++    for (i = 0U; i < len; i++) {+        d |= b1[i] ^ b2[i];+    }+    return (int)((1 & ((d - 1) >> 8)) - 1);+}++int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,+                  argon2_type type) {++    argon2_context ctx;+    uint8_t *out;+    int ret;++    /* max values, to be updated in decode_string */+    ctx.adlen = 512;+    ctx.saltlen = 512;+    ctx.outlen = 512;++    ctx.ad = malloc(ctx.adlen);+    ctx.salt = malloc(ctx.saltlen);+    ctx.out = malloc(ctx.outlen);+    if (!ctx.out || !ctx.salt || !ctx.ad) {+        free(ctx.ad);+        free(ctx.salt);+        free(ctx.out);+        return ARGON2_MEMORY_ALLOCATION_ERROR;+    }+    out = malloc(ctx.outlen);+    if (!out) {+        free(ctx.ad);+        free(ctx.salt);+        free(ctx.out);+        return ARGON2_MEMORY_ALLOCATION_ERROR;+    }++    if(decode_string(&ctx, encoded, type) != 1) {+        free(ctx.ad);+        free(ctx.salt);+        free(ctx.out);+        free(out);+        return ARGON2_DECODING_FAIL;+    }++    ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, ctx.salt,+                ctx.saltlen, out, ctx.outlen, NULL, 0, type);++    free(ctx.ad);+    free(ctx.salt);++    if (ret != ARGON2_OK || argon2_compare(out, ctx.out, ctx.outlen)) {+        free(out);+        free(ctx.out);+        return ARGON2_DECODING_FAIL;+    }+    free(out);+    free(ctx.out);++    return ARGON2_OK;+}++int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) {++    return argon2_verify(encoded, pwd, pwdlen, Argon2_i);+}++int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) {++    return argon2_verify(encoded, pwd, pwdlen, Argon2_d);+}++int argon2d(argon2_context *context) { return argon2_core(context, Argon2_d); }++int argon2i(argon2_context *context) { return argon2_core(context, Argon2_i); }++int verify_d(argon2_context *context, const char *hash) {+    int result;+    if (0 == context->outlen || NULL == hash) {+        return ARGON2_OUT_PTR_MISMATCH;+    }++    result = argon2_core(context, Argon2_d);++    if (ARGON2_OK != result) {+        return result;+    }++    return 0 == memcmp(hash, context->out, context->outlen);+}++int verify_i(argon2_context *context, const char *hash) {+    int result;+    if (0 == context->outlen || NULL == hash) {+        return ARGON2_OUT_PTR_MISMATCH;+    }++    result = argon2_core(context, Argon2_i);++    if (ARGON2_OK != result) {+        return result;+    }++    return 0 == memcmp(hash, context->out, context->outlen);+}+++const char *error_message(int error_code) {+    enum {+        /* Make sure---at compile time---that the enum size matches the array+           size */+        ERROR_STRING_CHECK =+            1 /+            !!((sizeof(Argon2_ErrorMessage) / sizeof(Argon2_ErrorMessage[0])) ==+               ARGON2_ERROR_CODES_LENGTH)+    };+    if (error_code < ARGON2_ERROR_CODES_LENGTH) {+        return Argon2_ErrorMessage[(argon2_error_codes)error_code];+    }+    return "Unknown error code.";+}
+ phc-winner-argon2/src/blake2/blake2b.c view
@@ -0,0 +1,372 @@+#include <stdint.h>+#include <string.h>+#include <stdio.h>++#include "blake2.h"+#include "blake2-impl.h"++static const uint64_t blake2b_IV[8] = {+    UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b),+    UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1),+    UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f),+    UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)};++static const unsigned int blake2b_sigma[12][16] = {+    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},+    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},+    {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},+    {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},+    {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},+    {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},+    {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},+    {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},+    {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},+    {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},+    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},+    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},+};++static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) {+    S->f[1] = (uint64_t)-1;+}++static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) {+    if (S->last_node) {+        blake2b_set_lastnode(S);+    }+    S->f[0] = (uint64_t)-1;+}++static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,+                                                    uint64_t inc) {+    S->t[0] += inc;+    S->t[1] += (S->t[0] < inc);+}++static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {+    burn(S, sizeof(*S));      /* wipe */+    blake2b_set_lastblock(S); /* invalidate for further use */+}++static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) {+    memset(S, 0, sizeof(*S));+    memcpy(S->h, blake2b_IV, sizeof(S->h));+}++int blake2b_init_param(blake2b_state *S, const blake2b_param *P) {+    const unsigned char *p = (const unsigned char *)P;+    unsigned int i;++    if (NULL == P || NULL == S) {+        return -1;+    }++    blake2b_init0(S);+    /* IV XOR Parameter Block */+    for (i = 0; i < 8; ++i) {+        S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);+    }+    S->outlen = P->digest_length;+    return 0;+}++/* Sequential blake2b initialization */+int blake2b_init(blake2b_state *S, size_t outlen) {+    blake2b_param P;++    if (S == NULL) {+        return -1;+    }++    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {+        blake2b_invalidate_state(S);+        return -1;+    }++    /* Setup Parameter Block for unkeyed BLAKE2 */+    P.digest_length = (uint8_t)outlen;+    P.key_length = 0;+    P.fanout = 1;+    P.depth = 1;+    P.leaf_length = 0;+    P.node_offset = 0;+    P.node_depth = 0;+    P.inner_length = 0;+    memset(P.reserved, 0, sizeof(P.reserved));+    memset(P.salt, 0, sizeof(P.salt));+    memset(P.personal, 0, sizeof(P.personal));++    return blake2b_init_param(S, &P);+}++int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,+                     size_t keylen) {+    blake2b_param P;++    if (S == NULL) {+        return -1;+    }++    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {+        blake2b_invalidate_state(S);+        return -1;+    }++    if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) {+        blake2b_invalidate_state(S);+        return -1;+    }++    /* Setup Parameter Block for keyed BLAKE2 */+    P.digest_length = (uint8_t)outlen;+    P.key_length = (uint8_t)keylen;+    P.fanout = 1;+    P.depth = 1;+    P.leaf_length = 0;+    P.node_offset = 0;+    P.node_depth = 0;+    P.inner_length = 0;+    memset(P.reserved, 0, sizeof(P.reserved));+    memset(P.salt, 0, sizeof(P.salt));+    memset(P.personal, 0, sizeof(P.personal));++    if (blake2b_init_param(S, &P) < 0) {+        blake2b_invalidate_state(S);+        return -1;+    }++    {+        uint8_t block[BLAKE2B_BLOCKBYTES];+        memset(block, 0, BLAKE2B_BLOCKBYTES);+        memcpy(block, key, keylen);+        blake2b_update(S, block, BLAKE2B_BLOCKBYTES);+        burn(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */+    }+    return 0;+}++static void blake2b_compress(blake2b_state *S, const uint8_t *block) {+    uint64_t m[16];+    uint64_t v[16];+    unsigned int i, r;++    for (i = 0; i < 16; ++i) {+        m[i] = load64(block + i * sizeof(m[i]));+    }++    for (i = 0; i < 8; ++i) {+        v[i] = S->h[i];+    }++    v[8] = blake2b_IV[0];+    v[9] = blake2b_IV[1];+    v[10] = blake2b_IV[2];+    v[11] = blake2b_IV[3];+    v[12] = blake2b_IV[4] ^ S->t[0];+    v[13] = blake2b_IV[5] ^ S->t[1];+    v[14] = blake2b_IV[6] ^ S->f[0];+    v[15] = blake2b_IV[7] ^ S->f[1];++#define G(r, i, a, b, c, d)                                                    \+    do {                                                                       \+        a = a + b + m[blake2b_sigma[r][2 * i + 0]];                            \+        d = rotr64(d ^ a, 32);                                                 \+        c = c + d;                                                             \+        b = rotr64(b ^ c, 24);                                                 \+        a = a + b + m[blake2b_sigma[r][2 * i + 1]];                            \+        d = rotr64(d ^ a, 16);                                                 \+        c = c + d;                                                             \+        b = rotr64(b ^ c, 63);                                                 \+    } while ((void)0, 0)++#define ROUND(r)                                                               \+    do {                                                                       \+        G(r, 0, v[0], v[4], v[8], v[12]);                                      \+        G(r, 1, v[1], v[5], v[9], v[13]);                                      \+        G(r, 2, v[2], v[6], v[10], v[14]);                                     \+        G(r, 3, v[3], v[7], v[11], v[15]);                                     \+        G(r, 4, v[0], v[5], v[10], v[15]);                                     \+        G(r, 5, v[1], v[6], v[11], v[12]);                                     \+        G(r, 6, v[2], v[7], v[8], v[13]);                                      \+        G(r, 7, v[3], v[4], v[9], v[14]);                                      \+    } while ((void)0, 0)++    for (r = 0; r < 12; ++r) {+        ROUND(r);+    }++    for (i = 0; i < 8; ++i) {+        S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];+    }++#undef G+#undef ROUND+}++int blake2b_update(blake2b_state *S, const void *in, size_t inlen) {+    const uint8_t *pin = (const uint8_t *)in;++    if (inlen == 0) {+        return 0;+    }++    /* Sanity check */+    if (S == NULL || in == NULL) {+        return -1;+    }++    /* Is this a reused state? */+    if (S->f[0] != 0) {+        return -1;+    }++    if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) {+        /* Complete current block */+        size_t left = S->buflen;+        size_t fill = BLAKE2B_BLOCKBYTES - left;+        memcpy(&S->buf[left], pin, fill);+        blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);+        blake2b_compress(S, S->buf);+        S->buflen = 0;+        inlen -= fill;+        pin += fill;+        /* Avoid buffer copies when possible */+        while (inlen > BLAKE2B_BLOCKBYTES) {+            blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);+            blake2b_compress(S, pin);+            inlen -= BLAKE2B_BLOCKBYTES;+            pin += BLAKE2B_BLOCKBYTES;+        }+    }+    memcpy(&S->buf[S->buflen], pin, inlen);+    S->buflen += (unsigned int)inlen;+    return 0;+}++int blake2b_final(blake2b_state *S, void *out, size_t outlen) {+    uint8_t buffer[BLAKE2B_OUTBYTES] = {0};+    unsigned int i;++    /* Sanity checks */+    if (S == NULL || out == NULL || outlen < S->outlen) {+        return -1;+    }++    /* Is this a reused state? */+    if (S->f[0] != 0) {+        return -1;+    }++    blake2b_increment_counter(S, S->buflen);+    blake2b_set_lastblock(S);+    memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */+    blake2b_compress(S, S->buf);++    for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */+        store64(buffer + sizeof(S->h[i]) * i, S->h[i]);+    }++    memcpy(out, buffer, S->outlen);+    burn(buffer, sizeof(buffer));+    burn(S->buf, sizeof(S->buf));+    burn(S->h, sizeof(S->h));+    return 0;+}++int blake2b(void *out, size_t outlen, const void *in, size_t inlen,+            const void *key, size_t keylen) {+    blake2b_state S;+    int ret = -1;++    /* Verify parameters */+    if (NULL == in && inlen > 0) {+        goto fail;+    }++    if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) {+        goto fail;+    }++    if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) {+        goto fail;+    }++    if (keylen > 0) {+        if (blake2b_init_key(&S, outlen, key, keylen) < 0) {+            goto fail;+        }+    } else {+        if (blake2b_init(&S, outlen) < 0) {+            goto fail;+        }+    }++    if (blake2b_update(&S, in, inlen) < 0) {+        goto fail;+    }+    ret = blake2b_final(&S, out, outlen);++fail:+    burn(&S, sizeof(S));+    return ret;+}++/* Argon2 Team - Begin Code */+int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) {+    uint8_t *out = (uint8_t *)pout;+    blake2b_state blake_state;+    uint8_t outlen_bytes[sizeof(uint32_t)] = {0};+    int ret = -1;++    if (outlen > UINT32_MAX) {+        goto fail;+    }++    /* Ensure little-endian byte order! */+    store32(outlen_bytes, (uint32_t)outlen);++#define TRY(statement)                                                         \+    do {                                                                       \+        ret = statement;                                                       \+        if (ret < 0) {                                                         \+            goto fail;                                                         \+        }                                                                      \+    } while ((void)0, 0)++    if (outlen <= BLAKE2B_OUTBYTES) {+        TRY(blake2b_init(&blake_state, outlen));+        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));+        TRY(blake2b_update(&blake_state, in, inlen));+        TRY(blake2b_final(&blake_state, out, outlen));+    } else {+        uint32_t toproduce;+        uint8_t out_buffer[BLAKE2B_OUTBYTES];+        uint8_t in_buffer[BLAKE2B_OUTBYTES];+        TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));+        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));+        TRY(blake2b_update(&blake_state, in, inlen));+        TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));+        memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);+        out += BLAKE2B_OUTBYTES / 2;+        toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2;++        while (toproduce > BLAKE2B_OUTBYTES) {+            memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);+            TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer,+                        BLAKE2B_OUTBYTES, NULL, 0));+            memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);+            out += BLAKE2B_OUTBYTES / 2;+            toproduce -= BLAKE2B_OUTBYTES / 2;+        }++        memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);+        TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL,+                    0));+        memcpy(out, out_buffer, toproduce);+    }+fail:+    burn(&blake_state, sizeof(blake_state));+    return ret;+#undef TRY+}+/* Argon2 Team - End Code */
+ phc-winner-argon2/src/core.c view
@@ -0,0 +1,612 @@+/*+ * Argon2 source code package+ *+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ *+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ *+ * 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/>.+ */++/*For memory wiping*/+#ifdef _MSC_VER+#include <windows.h>+#include <winbase.h> /* For SecureZeroMemory */+#endif+#if defined __STDC_LIB_EXT1__+#define __STDC_WANT_LIB_EXT1__ 1+#endif+#define VC_GE_2005(version) (version >= 1400)++#include <inttypes.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>++#include "core.h"+#include "thread.h"+#include "blake2/blake2.h"+#include "blake2/blake2-impl.h"++#ifdef GENKAT+#include "genkat.h"+#endif++#if defined(__clang__)+#if __has_attribute(optnone)+#define NOT_OPTIMIZED __attribute__((optnone))+#endif+#elif defined(__GNUC__)+#define GCC_VERSION                                                            \+    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)+#if GCC_VERSION >= 40400+#define NOT_OPTIMIZED __attribute__((optimize("O0")))+#endif+#endif+#ifndef NOT_OPTIMIZED+#define NOT_OPTIMIZED+#endif++/***************Instance and Position constructors**********/+void init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); }++void copy_block(block *dst, const block *src) {+    memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK);+}++void xor_block(block *dst, const block *src) {+    int i;+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {+        dst->v[i] ^= src->v[i];+    }+}++static void load_block(block *dst, const void *input) {+    unsigned i;+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {+        dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i]));+    }+}++static void store_block(void *output, const block *src) {+    unsigned i;+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {+        store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);+    }+}++/***************Memory allocators*****************/+int allocate_memory(block **memory, uint32_t m_cost) {+    if (memory != NULL) {+        size_t memory_size = sizeof(block) * m_cost;+        if (m_cost != 0 &&+            memory_size / m_cost !=+                sizeof(block)) { /*1. Check for multiplication overflow*/+            return ARGON2_MEMORY_ALLOCATION_ERROR;+        }++        *memory = (block *)malloc(memory_size); /*2. Try to allocate*/++        if (!*memory) {+            return ARGON2_MEMORY_ALLOCATION_ERROR;+        }++        return ARGON2_OK;+    } else {+        return ARGON2_MEMORY_ALLOCATION_ERROR;+    }+}++void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {+#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)+    SecureZeroMemory(v, n);+#elif defined memset_s+    memset_s(v, n);+#elif defined(__OpenBSD__)+    explicit_bzero(v, n);+#else+    static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;+    memset_sec(v, 0, n);+#endif+}++/*********Memory functions*/++void clear_memory(argon2_instance_t *instance, int clear) {+    if (instance->memory != NULL && clear) {+        secure_wipe_memory(instance->memory,+                           sizeof(block) * instance->memory_blocks);+    }+}++void free_memory(block *memory) { free(memory); }++void finalize(const argon2_context *context, argon2_instance_t *instance) {+    if (context != NULL && instance != NULL) {+        block blockhash;+        uint32_t l;++        copy_block(&blockhash, instance->memory + instance->lane_length - 1);++        /* XOR the last blocks */+        for (l = 1; l < instance->lanes; ++l) {+            uint32_t last_block_in_lane =+                l * instance->lane_length + (instance->lane_length - 1);+            xor_block(&blockhash, instance->memory + last_block_in_lane);+        }++        /* Hash the result */+        {+            uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];+            store_block(blockhash_bytes, &blockhash);+            blake2b_long(context->out, context->outlen, blockhash_bytes,+                         ARGON2_BLOCK_SIZE);+            secure_wipe_memory(blockhash.v,+                               ARGON2_BLOCK_SIZE); /* clear blockhash */+            secure_wipe_memory(blockhash_bytes,+                               ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */+        }++#ifdef GENKAT+        print_tag(context->out, context->outlen);+#endif++        /* Clear memory */+        clear_memory(instance, context->flags & ARGON2_FLAG_CLEAR_PASSWORD);++        /* Deallocate the memory */+        if (NULL != context->free_cbk) {+            context->free_cbk((uint8_t *)instance->memory,+                              instance->memory_blocks * sizeof(block));+        } else {+            free_memory(instance->memory);+        }+    }+}++uint32_t index_alpha(const argon2_instance_t *instance,+                     const argon2_position_t *position, uint32_t pseudo_rand,+                     int same_lane) {+    /*+     * Pass 0:+     *      This lane : all already finished segments plus already constructed+     * blocks in this segment+     *      Other lanes : all already finished segments+     * Pass 1+:+     *      This lane : (SYNC_POINTS - 1) last segments plus already constructed+     * blocks in this segment+     *      Other lanes : (SYNC_POINTS - 1) last segments+     */+    uint32_t reference_area_size;+    uint64_t relative_position;+    uint32_t start_position, absolute_position;++    if (0 == position->pass) {+        /* First pass */+        if (0 == position->slice) {+            /* First slice */+            reference_area_size =+                position->index - 1; /* all but the previous */+        } else {+            if (same_lane) {+                /* The same lane => add current segment */+                reference_area_size =+                    position->slice * instance->segment_length ++                    position->index - 1;+            } else {+                reference_area_size =+                    position->slice * instance->segment_length ++                    ((position->index == 0) ? (-1) : 0);+            }+        }+    } else {+        /* Second pass */+        if (same_lane) {+            reference_area_size = instance->lane_length -+                                  instance->segment_length + position->index -+                                  1;+        } else {+            reference_area_size = instance->lane_length -+                                  instance->segment_length ++                                  ((position->index == 0) ? (-1) : 0);+        }+    }++    /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce+     * relative position */+    relative_position = pseudo_rand;+    relative_position = relative_position * relative_position >> 32;+    relative_position = reference_area_size - 1 -+                        (reference_area_size * relative_position >> 32);++    /* 1.2.5 Computing starting position */+    start_position = 0;++    if (0 != position->pass) {+        start_position = (position->slice == ARGON2_SYNC_POINTS - 1)+                             ? 0+                             : (position->slice + 1) * instance->segment_length;+    }++    /* 1.2.6. Computing absolute position */+    absolute_position = (start_position + relative_position) %+                        instance->lane_length; /* absolute position */+    return absolute_position;+}++#ifdef _WIN32+static unsigned __stdcall fill_segment_thr(void *thread_data)+#else+static void *fill_segment_thr(void *thread_data)+#endif+{+    argon2_thread_data *my_data = (argon2_thread_data *)thread_data;+    fill_segment(my_data->instance_ptr, my_data->pos);+    argon2_thread_exit();+    return 0;+}++void fill_memory_blocks(argon2_instance_t *instance) {+    uint32_t r, s;+    argon2_thread_handle_t *thread = NULL;+    argon2_thread_data *thr_data = NULL;++    if (instance == NULL || instance->lanes == 0) {+        return;+    }++    /* 1. Allocating space for threads */+    thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t));+    if (thread == NULL) {+        return;+    }++    thr_data = calloc(instance->lanes, sizeof(argon2_thread_data));+    if (thr_data == NULL) {+        free(thread);+        return;+    }++    for (r = 0; r < instance->passes; ++r) {+        for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {+            int rc;+            uint32_t l;++            /* 2. Calling threads */+            for (l = 0; l < instance->lanes; ++l) {+                argon2_position_t position;++                /* 2.1 Join a thread if limit is exceeded */+                if (l >= instance->threads) {+                    rc = argon2_thread_join(thread[l - instance->threads]);+                    if (rc) {+                        printf(+                            "ERROR; return code from pthread_join() #1 is %d\n",+                            rc);+                        exit(-1);+                    }+                }++                /* 2.2 Create thread */+                position.pass = r;+                position.lane = l;+                position.slice = (uint8_t)s;+                position.index = 0;+                thr_data[l].instance_ptr =+                    instance; /* preparing the thread input */+                memcpy(&(thr_data[l].pos), &position,+                       sizeof(argon2_position_t));+                rc = argon2_thread_create(&thread[l], &fill_segment_thr,+                                          (void *)&thr_data[l]);+                if (rc) {+                    printf("ERROR; return code from argon2_thread_create() is "+                           "%d\n",+                           rc);+                    exit(-1);+                }++                /* fill_segment(instance, position); */+                /*Non-thread equivalent of the lines above */+            }++            /* 3. Joining remaining threads */+            for (l = instance->lanes - instance->threads; l < instance->lanes;+                 ++l) {+                rc = argon2_thread_join(thread[l]);+                if (rc) {+                    printf("ERROR; return code from pthread_join() is %d\n",+                           rc);+                    exit(-1);+                }+            }+        }++#ifdef GENKAT+        internal_kat(instance, r); /* Print all memory blocks */+#endif+    }++    if (thread != NULL) {+        free(thread);+    }+    if (thr_data != NULL) {+        free(thr_data);+    }+}++int validate_inputs(const argon2_context *context) {+    if (NULL == context) {+        return ARGON2_INCORRECT_PARAMETER;+    }++    if (NULL == context->out) {+        return ARGON2_OUTPUT_PTR_NULL;+    }++    /* Validate output length */+    if (ARGON2_MIN_OUTLEN > context->outlen) {+        return ARGON2_OUTPUT_TOO_SHORT;+    }++    if (ARGON2_MAX_OUTLEN < context->outlen) {+        return ARGON2_OUTPUT_TOO_LONG;+    }++    /* Validate password length */+    if (NULL == context->pwd) {+        if (0 != context->pwdlen) {+            return ARGON2_PWD_PTR_MISMATCH;+        }+    } else {+        if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {+            return ARGON2_PWD_TOO_SHORT;+        }++        if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {+            return ARGON2_PWD_TOO_LONG;+        }+    }++    /* Validate salt length */+    if (NULL == context->salt) {+        if (0 != context->saltlen) {+            return ARGON2_SALT_PTR_MISMATCH;+        }+    } else {+        if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {+            return ARGON2_SALT_TOO_SHORT;+        }++        if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {+            return ARGON2_SALT_TOO_LONG;+        }+    }++    /* Validate secret length */+    if (NULL == context->secret) {+        if (0 != context->secretlen) {+            return ARGON2_SECRET_PTR_MISMATCH;+        }+    } else {+        if (ARGON2_MIN_SECRET > context->secretlen) {+            return ARGON2_SECRET_TOO_SHORT;+        }++        if (ARGON2_MAX_SECRET < context->secretlen) {+            return ARGON2_SECRET_TOO_LONG;+        }+    }++    /* Validate associated data */+    if (NULL == context->ad) {+        if (0 != context->adlen) {+            return ARGON2_AD_PTR_MISMATCH;+        }+    } else {+        if (ARGON2_MIN_AD_LENGTH > context->adlen) {+            return ARGON2_AD_TOO_SHORT;+        }++        if (ARGON2_MAX_AD_LENGTH < context->adlen) {+            return ARGON2_AD_TOO_LONG;+        }+    }++    /* Validate memory cost */+    if (ARGON2_MIN_MEMORY > context->m_cost) {+        return ARGON2_MEMORY_TOO_LITTLE;+    }++    if (ARGON2_MAX_MEMORY < context->m_cost) {+        return ARGON2_MEMORY_TOO_MUCH;+    }++    if (context->m_cost < 8*context->lanes) {+        return ARGON2_MEMORY_TOO_LITTLE;+    }++    /* Validate time cost */+    if (ARGON2_MIN_TIME > context->t_cost) {+        return ARGON2_TIME_TOO_SMALL;+    }++    if (ARGON2_MAX_TIME < context->t_cost) {+        return ARGON2_TIME_TOO_LARGE;+    }++    /* Validate lanes */+    if (ARGON2_MIN_LANES > context->lanes) {+        return ARGON2_LANES_TOO_FEW;+    }++    if (ARGON2_MAX_LANES < context->lanes) {+        return ARGON2_LANES_TOO_MANY;+    }++    /* Validate threads */+    if (ARGON2_MIN_THREADS > context->threads) {+        return ARGON2_THREADS_TOO_FEW;+    }++    if (ARGON2_MAX_THREADS < context->threads) {+        return ARGON2_THREADS_TOO_MANY;+    }++    if (NULL != context->allocate_cbk && NULL == context->free_cbk) {+        return ARGON2_FREE_MEMORY_CBK_NULL;+    }++    if (NULL == context->allocate_cbk && NULL != context->free_cbk) {+        return ARGON2_ALLOCATE_MEMORY_CBK_NULL;+    }++    return ARGON2_OK;+}++void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) {+    uint32_t l;+    /* Make the first and second block in each lane as G(H0||i||0) or+       G(H0||i||1) */+    uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];+    for (l = 0; l < instance->lanes; ++l) {++        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);+        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,+                     ARGON2_PREHASH_SEED_LENGTH);+        load_block(&instance->memory[l * instance->lane_length + 0],+                   blockhash_bytes);++        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);+        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,+                     ARGON2_PREHASH_SEED_LENGTH);+        load_block(&instance->memory[l * instance->lane_length + 1],+                   blockhash_bytes);+    }+    secure_wipe_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);+}++void initial_hash(uint8_t *blockhash, argon2_context *context,+                  argon2_type type) {+    blake2b_state BlakeHash;+    uint8_t value[sizeof(uint32_t)];++    if (NULL == context || NULL == blockhash) {+        return;+    }++    blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);++    store32(&value, context->lanes);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    store32(&value, context->outlen);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    store32(&value, context->m_cost);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    store32(&value, context->t_cost);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    store32(&value, ARGON2_VERSION_NUMBER);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    store32(&value, (uint32_t)type);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    store32(&value, context->pwdlen);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    if (context->pwd != NULL) {+        blake2b_update(&BlakeHash, (const uint8_t *)context->pwd,+                       context->pwdlen);++        if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {+            secure_wipe_memory(context->pwd, context->pwdlen);+            context->pwdlen = 0;+        }+    }++    store32(&value, context->saltlen);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    if (context->salt != NULL) {+        blake2b_update(&BlakeHash, (const uint8_t *)context->salt,+                       context->saltlen);+    }++    store32(&value, context->secretlen);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    if (context->secret != NULL) {+        blake2b_update(&BlakeHash, (const uint8_t *)context->secret,+                       context->secretlen);++        if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {+            secure_wipe_memory(context->secret, context->secretlen);+            context->secretlen = 0;+        }+    }++    store32(&value, context->adlen);+    blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value));++    if (context->ad != NULL) {+        blake2b_update(&BlakeHash, (const uint8_t *)context->ad,+                       context->adlen);+    }++    blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);+}++int initialize(argon2_instance_t *instance, argon2_context *context) {+    uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];+    int result = ARGON2_OK;++    if (instance == NULL || context == NULL)+        return ARGON2_INCORRECT_PARAMETER;++    /* 1. Memory allocation */++    if (NULL != context->allocate_cbk) {+        uint8_t *p;+        result = context->allocate_cbk(&p, instance->memory_blocks *+                                               ARGON2_BLOCK_SIZE);+        if (ARGON2_OK != result) {+            return result;+        }+        memcpy(&(instance->memory), p, sizeof(instance->memory));+    } else {+        result = allocate_memory(&(instance->memory), instance->memory_blocks);+        if (ARGON2_OK != result) {+            return result;+        }+    }++    /* 2. Initial hashing */+    /* H_0 + 8 extra bytes to produce the first blocks */+    /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */+    /* Hashing all inputs */+    initial_hash(blockhash, context, instance->type);+    /* Zeroing 8 extra bytes */+    secure_wipe_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,+                       ARGON2_PREHASH_SEED_LENGTH -+                           ARGON2_PREHASH_DIGEST_LENGTH);++#ifdef GENKAT+    initial_kat(blockhash, context, instance->type);+#endif++    /* 3. Creating first blocks, we always have at least two blocks in a slice+     */+    fill_first_blocks(blockhash, instance);+    /* Clearing the hash */+    secure_wipe_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);++    return ARGON2_OK;+}+
+ phc-winner-argon2/src/encoding.c view
@@ -0,0 +1,434 @@+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <limits.h>+#include "encoding.h"++#/*+ * Example code for a decoder and encoder of "hash strings", with Argon2i+ * parameters.+ *+ * This code comprises three sections:+ *+ *   -- The first section contains generic Base64 encoding and decoding+ *   functions. It is conceptually applicable to any hash function+ *   implementation that uses Base64 to encode and decode parameters,+ *   salts and outputs. It could be made into a library, provided that+ *   the relevant functions are made public (non-static) and be given+ *   reasonable names to avoid collisions with other functions.+ *+ *   -- The second section is specific to Argon2i. It encodes and decodes+ *   the parameters, salts and outputs. It does not compute the hash+ *   itself.+ *+ *   -- The third section is test code, with a main() function. With+ *   this section, the whole file compiles as a stand-alone program+ *   that exercises the encoding and decoding functions with some+ *   test vectors.+ *+ * The code was originally written by Thomas Pornin <pornin@bolet.org>,+ * to whom comments and remarks may be sent. It is released under what+ * should amount to Public Domain or its closest equivalent; the+ * following mantra is supposed to incarnate that fact with all the+ * proper legal rituals:+ *+ * ---------------------------------------------------------------------+ * This file is provided under the terms of Creative Commons CC0 1.0+ * Public Domain Dedication. To the extent possible under law, the+ * author (Thomas Pornin) has waived all copyright and related or+ * neighboring rights to this file. This work is published from: Canada.+ * ---------------------------------------------------------------------+ *+ * Copyright (c) 2015 Thomas Pornin+ */++/* ==================================================================== */+/*+ * Common code; could be shared between different hash functions.+ *+ * Note: the Base64 functions below assume that uppercase letters (resp.+ * lowercase letters) have consecutive numerical codes, that fit on 8+ * bits. All modern systems use ASCII-compatible charsets, where these+ * properties are true. If you are stuck with a dinosaur of a system+ * that still defaults to EBCDIC then you already have much bigger+ * interoperability issues to deal with.+ */++/*+ * Some macros for constant-time comparisons. These work over values in+ * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".+ */+#define EQ(x, y) ((((0U-((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)+#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)+#define GE(x, y) (GT(y, x) ^ 0xFF)+#define LT(x, y) GT(y, x)+#define LE(x, y) GE(y, x)++/*+ * Convert value x (0..63) to corresponding Base64 character.+ */+static int b64_byte_to_char(unsigned x) {+    return (LT(x, 26) & (x + 'A')) |+           (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |+           (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |+           (EQ(x, 63) & '/');+}++/*+ * Convert character c to the corresponding 6-bit value. If character c+ * is not a Base64 character, then 0xFF (255) is returned.+ */+static unsigned b64_char_to_byte(int c) {+    unsigned x;++    x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |+        (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |+        (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |+        (EQ(c, '/') & 63);+    return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));+}++/*+ * Convert some bytes to Base64. 'dst_len' is the length (in characters)+ * of the output buffer 'dst'; if that buffer is not large enough to+ * receive the result (including the terminating 0), then (size_t)-1+ * is returned. Otherwise, the zero-terminated Base64 string is written+ * in the buffer, and the output length (counted WITHOUT the terminating+ * zero) is returned.+ */+static size_t to_base64(char *dst, size_t dst_len, const void *src,+                        size_t src_len) {+    size_t olen;+    const unsigned char *buf;+    unsigned acc, acc_len;++    olen = (src_len / 3) << 2;+    switch (src_len % 3) {+    case 2:+        olen++;+    /* fall through */+    case 1:+        olen += 2;+        break;+    }+    if (dst_len <= olen) {+        return (size_t)-1;+    }+    acc = 0;+    acc_len = 0;+    buf = (const unsigned char *)src;+    while (src_len-- > 0) {+        acc = (acc << 8) + (*buf++);+        acc_len += 8;+        while (acc_len >= 6) {+            acc_len -= 6;+            *dst++ = (char) b64_byte_to_char((acc >> acc_len) & 0x3F);+        }+    }+    if (acc_len > 0) {+        *dst++ = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);+    }+    *dst++ = 0;+    return olen;+}++/*+ * Decode Base64 chars into bytes. The '*dst_len' value must initially+ * contain the length of the output buffer '*dst'; when the decoding+ * ends, the actual number of decoded bytes is written back in+ * '*dst_len'.+ *+ * Decoding stops when a non-Base64 character is encountered, or when+ * the output buffer capacity is exceeded. If an error occurred (output+ * buffer is too small, invalid last characters leading to unprocessed+ * buffered bits), then NULL is returned; otherwise, the returned value+ * points to the first non-Base64 character in the source stream, which+ * may be the terminating zero.+ */+static const char *from_base64(void *dst, size_t *dst_len, const char *src) {+    size_t len;+    unsigned char *buf;+    unsigned acc, acc_len;++    buf = (unsigned char *)dst;+    len = 0;+    acc = 0;+    acc_len = 0;+    for (;;) {+        unsigned d;++        d = b64_char_to_byte(*src);+        if (d == 0xFF) {+            break;+        }+        src++;+        acc = (acc << 6) + d;+        acc_len += 6;+        if (acc_len >= 8) {+            acc_len -= 8;+            if ((len++) >= *dst_len) {+                return NULL;+            }+            *buf++ = (acc >> acc_len) & 0xFF;+        }+    }++    /*+     * If the input length is equal to 1 modulo 4 (which is+     * invalid), then there will remain 6 unprocessed bits;+     * otherwise, only 0, 2 or 4 bits are buffered. The buffered+     * bits must also all be zero.+     */+    if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {+        return NULL;+    }+    *dst_len = len;+    return src;+}++/*+ * Decode decimal integer from 'str'; the value is written in '*v'.+ * Returned value is a pointer to the next non-decimal character in the+ * string. If there is no digit at all, or the value encoding is not+ * minimal (extra leading zeros), or the value does not fit in an+ * 'unsigned long', then NULL is returned.+ */+static const char *decode_decimal(const char *str, unsigned long *v) {+    const char *orig;+    unsigned long acc;++    acc = 0;+    for (orig = str;; str++) {+        int c;++        c = *str;+        if (c < '0' || c > '9') {+            break;+        }+        c -= '0';+        if (acc > (ULONG_MAX / 10)) {+            return NULL;+        }+        acc *= 10;+        if ((unsigned long)c > (ULONG_MAX - acc)) {+            return NULL;+        }+        acc += (unsigned long)c;+    }+    if (str == orig || (*orig == '0' && str != (orig + 1))) {+        return NULL;+    }+    *v = acc;+    return str;+}++/* ==================================================================== */+/*+ * Code specific to Argon2i.+ *+ * The code below applies the following format:+ *+ *  $argon2i$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]+ *+ * where <num> is a decimal integer (positive, fits in an 'unsigned long')+ * and <bin> is Base64-encoded data (no '=' padding characters, no newline+ * or whitespace). The "keyid" is a binary identifier for a key (up to 8+ * bytes); "data" is associated data (up to 32 bytes). When the 'keyid'+ * (resp. the 'data') is empty, then it is ommitted from the output.+ *+ * The last two binary chunks (encoded in Base64) are, in that order,+ * the salt and the output. Both are optional, but you cannot have an+ * output without a salt. The binary salt length is between 8 and 48 bytes.+ * The output length is always exactly 32 bytes.+ */++/*+ * Decode an Argon2i hash string into the provided structure 'ctx'.+ * Returned value is 1 on success, 0 on error.+ */+int decode_string(argon2_context *ctx, const char *str, argon2_type type) {+#define CC(prefix)                                                             \+    do {                                                                       \+        size_t cc_len = strlen(prefix);                                        \+        if (strncmp(str, prefix, cc_len) != 0) {                               \+            return 0;                                                          \+        }                                                                      \+        str += cc_len;                                                         \+    } while ((void)0, 0)++#define CC_opt(prefix, code)                                                   \+    do {                                                                       \+        size_t cc_len = strlen(prefix);                                        \+        if (strncmp(str, prefix, cc_len) == 0) {                               \+            str += cc_len;                                                     \+            { code; }                                                          \+        }                                                                      \+    } while ((void)0, 0)++#define DECIMAL(x)                                                             \+    do {                                                                       \+        unsigned long dec_x;                                                   \+        str = decode_decimal(str, &dec_x);                                     \+        if (str == NULL) {                                                     \+            return 0;                                                          \+        }                                                                      \+        (x) = dec_x;                                                           \+    } while ((void)0, 0)++#define BIN(buf, max_len, len)                                                 \+    do {                                                                       \+        size_t bin_len = (max_len);                                            \+        str = from_base64(buf, &bin_len, str);                                 \+        if (str == NULL || bin_len > UINT32_MAX) {                             \+            return 0;                                                          \+        }                                                                      \+        (len) = (uint32_t)bin_len;                                             \+    } while ((void)0, 0)++    size_t maxadlen = ctx->adlen;+    size_t maxsaltlen = ctx->saltlen;+    size_t maxoutlen = ctx->outlen;++    ctx->adlen = 0;+    ctx->saltlen = 0;+    ctx->outlen = 0;+    if (type == Argon2_i)+        CC("$argon2i");+    else if (type == Argon2_d)+        CC("$argon2d");+    else+        return 0;+    CC("$m=");+    DECIMAL(ctx->m_cost);+    CC(",t=");+    DECIMAL(ctx->t_cost);+    CC(",p=");+    DECIMAL(ctx->lanes);+    ctx->threads = ctx->lanes;++    /*+     * Both m and t must be no more than 2^32-1. The tests below+     * use a shift by 30 bits to avoid a direct comparison with+     * 0xFFFFFFFF, which may trigger a spurious compiler warning+     * on machines where 'unsigned long' is a 32-bit type.+     */+    if (ctx->m_cost < 1 || (ctx->m_cost >> 30) > 3) {+        return 0;+    }+    if (ctx->t_cost < 1 || (ctx->t_cost >> 30) > 3) {+        return 0;+    }++    /*+     * The parallelism p must be between 1 and 255. The memory cost+     * parameter, expressed in kilobytes, must be at least 8 times+     * the value of p.+     */+    if (ctx->lanes < 1 || ctx->lanes > 255) {+        return 0;+    }+    if (ctx->m_cost < (ctx->lanes << 3)) {+        return 0;+    }++    CC_opt(",data=", BIN(ctx->ad, maxadlen, ctx->adlen));+    if (*str == 0) {+        return 1;+    }+    CC("$");+    BIN(ctx->salt, maxsaltlen, ctx->saltlen);+    if (ctx->saltlen < 8) {+        return 0;+    }+    if (*str == 0) {+        return 1;+    }+    CC("$");+    BIN(ctx->out, maxoutlen, ctx->outlen);+    if (ctx->outlen < 12) {+        return 0;+    }+    return *str == 0;++#undef CC+#undef CC_opt+#undef DECIMAL+#undef BIN+}++/*+ * encode an argon2i hash string into the provided buffer. 'dst_len'+ * contains the size, in characters, of the 'dst' buffer; if 'dst_len'+ * is less than the number of required characters (including the+ * terminating 0), then this function returns 0.+ *+ * if pp->output_len is 0, then the hash string will be a salt string+ * (no output). if pp->salt_len is also 0, then the string will be a+ * parameter-only string (no salt and no output).+ *+ * on success, 1 is returned.+ */+int encode_string(char *dst, size_t dst_len, argon2_context *ctx,+                  argon2_type type) {+#define SS(str)                                                                \+    do {                                                                       \+        size_t pp_len = strlen(str);                                           \+        if (pp_len >= dst_len) {                                               \+            return 0;                                                          \+        }                                                                      \+        memcpy(dst, str, pp_len + 1);                                          \+        dst += pp_len;                                                         \+        dst_len -= pp_len;                                                     \+    } while ((void)0, 0)++#define SX(x)                                                                  \+    do {                                                                       \+        char tmp[30];                                                          \+        sprintf(tmp, "%lu", (unsigned long)(x));                               \+        SS(tmp);                                                               \+    } while ((void)0, 0)++#define SB(buf, len)                                                           \+    do {                                                                       \+        size_t sb_len = to_base64(dst, dst_len, buf, len);                     \+        if (sb_len == (size_t)-1) {                                            \+            return 0;                                                          \+        }                                                                      \+        dst += sb_len;                                                         \+        dst_len -= sb_len;                                                     \+    } while ((void)0, 0)++    if (type == Argon2_i)+        SS("$argon2i$m=");+    else if (type == Argon2_d)+        SS("$argon2d$m=");+    else+        return 0;+    SX(ctx->m_cost);+    SS(",t=");+    SX(ctx->t_cost);+    SS(",p=");+    SX(ctx->lanes);++    if (ctx->adlen > 0) {+        SS(",data=");+        SB(ctx->ad, ctx->adlen);+    }++    if (ctx->saltlen == 0)+        return 1;++    SS("$");+    SB(ctx->salt, ctx->saltlen);++    if (ctx->outlen == 0)+        return 1;++    SS("$");+    SB(ctx->out, ctx->outlen);+    return 1;++#undef SS+#undef SX+#undef SB+}
+ phc-winner-argon2/src/ref.c view
@@ -0,0 +1,177 @@+/*+ * Argon2 source code package+ *+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015+ *+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.+ *+ * 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 <stdint.h>+#include <string.h>+#include <stdlib.h>++#include "argon2.h"+#include "core.h"+#include "ref.h"++#include "blake2/blamka-round-ref.h"+#include "blake2/blake2-impl.h"+#include "blake2/blake2.h"++void fill_block(const block *prev_block, const block *ref_block,+                block *next_block) {+    block blockR, block_tmp;+    unsigned i;++    copy_block(&blockR, ref_block);+    xor_block(&blockR, prev_block);+    copy_block(&block_tmp, &blockR);++    /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then+       (16,17,..31)... finally (112,113,...127) */+    for (i = 0; i < 8; ++i) {+        BLAKE2_ROUND_NOMSG(+            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],+            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],+            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],+            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],+            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],+            blockR.v[16 * i + 15]);+    }++    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then+       (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */+    for (i = 0; i < 8; i++) {+        BLAKE2_ROUND_NOMSG(+            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],+            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],+            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],+            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],+            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],+            blockR.v[2 * i + 113]);+    }++    copy_block(next_block, &block_tmp);+    xor_block(next_block, &blockR);+}++void generate_addresses(const argon2_instance_t *instance,+                        const argon2_position_t *position,+                        uint64_t *pseudo_rands) {+    block zero_block, input_block, address_block;+    uint32_t i;++    init_block_value(&zero_block, 0);+    init_block_value(&input_block, 0);+    init_block_value(&address_block, 0);++    if (instance != NULL && position != NULL) {+        input_block.v[0] = position->pass;+        input_block.v[1] = position->lane;+        input_block.v[2] = position->slice;+        input_block.v[3] = instance->memory_blocks;+        input_block.v[4] = instance->passes;+        input_block.v[5] = instance->type;++        for (i = 0; i < instance->segment_length; ++i) {+            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {+                input_block.v[6]++;+                fill_block(&zero_block, &input_block, &address_block);+                fill_block(&zero_block, &address_block, &address_block);+            }++            pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];+        }+    }+}++void fill_segment(const argon2_instance_t *instance,+                  argon2_position_t position) {+    block *ref_block = NULL, *curr_block = NULL;+    uint64_t pseudo_rand, ref_index, ref_lane;+    uint32_t prev_offset, curr_offset;+    uint32_t starting_index;+    uint32_t i;+    int data_independent_addressing;+    /* Pseudo-random values that determine the reference block position */+    uint64_t *pseudo_rands = NULL;++    if (instance == NULL) {+        return;+    }++    data_independent_addressing = (instance->type == Argon2_i);++    pseudo_rands =+        (uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length));++    if (pseudo_rands == NULL) {+        return;+    }++    if (data_independent_addressing) {+        generate_addresses(instance, &position, pseudo_rands);+    }++    starting_index = 0;++    if ((0 == position.pass) && (0 == position.slice)) {+        starting_index = 2; /* we have already generated the first two blocks */+    }++    /* Offset of the current block */+    curr_offset = position.lane * instance->lane_length ++                  position.slice * instance->segment_length + starting_index;++    if (0 == curr_offset % instance->lane_length) {+        /* Last block in this lane */+        prev_offset = curr_offset + instance->lane_length - 1;+    } else {+        /* Previous block */+        prev_offset = curr_offset - 1;+    }++    for (i = starting_index; i < instance->segment_length;+         ++i, ++curr_offset, ++prev_offset) {+        /*1.1 Rotating prev_offset if needed */+        if (curr_offset % instance->lane_length == 1) {+            prev_offset = curr_offset - 1;+        }++        /* 1.2 Computing the index of the reference block */+        /* 1.2.1 Taking pseudo-random value from the previous block */+        if (data_independent_addressing) {+            pseudo_rand = pseudo_rands[i];+        } else {+            pseudo_rand = instance->memory[prev_offset].v[0];+        }++        /* 1.2.2 Computing the lane of the reference block */+        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;++        if ((position.pass == 0) && (position.slice == 0)) {+            /* Can not reference other lanes yet */+            ref_lane = position.lane;+        }++        /* 1.2.3 Computing the number of possible reference block within the+         * lane.+         */+        position.index = i;+        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,+                                ref_lane == position.lane);++        /* 2 Creating a new block */+        ref_block =+            instance->memory + instance->lane_length * ref_lane + ref_index;+        curr_block = instance->memory + curr_offset;+        fill_block(instance->memory + prev_offset, ref_block, curr_block);+    }++    free(pseudo_rands);+}
+ phc-winner-argon2/src/thread.c view
@@ -0,0 +1,36 @@+#include "thread.h"+#if defined(_WIN32)+#include <Windows.h>+#endif++int argon2_thread_create(argon2_thread_handle_t *handle,+                         argon2_thread_func_t func, void *args) {+    if (NULL == handle || func == NULL) {+        return -1;+    }+#if defined(_WIN32)+    *handle = _beginthreadex(NULL, 0, func, args, 0, NULL);+    return *handle != 0 ? 0 : -1;+#else+    return pthread_create(handle, NULL, func, args);+#endif+}++int argon2_thread_join(argon2_thread_handle_t handle) {+#if defined(_WIN32)+    if (WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0) {+        return CloseHandle((HANDLE)handle) != 0 ? 0 : -1;+    }+    return -1;+#else+    return pthread_join(handle, NULL);+#endif+}++void argon2_thread_exit(void) {+#if defined(_WIN32)+    _endthreadex(0);+#else+    pthread_exit(NULL);+#endif+}
+ src/Crypto/Argon2.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE RecordWildCards #-}++module Crypto.Argon2 (hashEncoded, hash, HashOptions(..), Argon2Variant(..), defaultHashOptions) where++import Control.Exception+import Data.Typeable+import Foreign+import Foreign.C+import Numeric.Natural+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.ByteString as BS+import qualified Data.Text.Encoding as T+import qualified Data.Text as T+import qualified Crypto.Argon2.FFI as FFI++data Argon2Variant = Argon2i | Argon2d++data HashOptions =+  HashOptions {hashIterations :: !Word32+              ,hashMemory :: !Word32+              ,hashParallelism :: !Word32+              ,hashVariant :: !Argon2Variant}++defaultHashOptions :: HashOptions+defaultHashOptions =+  HashOptions {hashIterations = 3+              ,hashMemory = 2 ^ 12+              ,hashParallelism = 1+              ,hashVariant = Argon2i}++hashEncoded :: HashOptions -- ^ Options pertaining to how expensive the hash is to calculate+            -> BS.ByteString -- ^ The password to hash+            -> BS.ByteString -- ^ The salt to use when hashing+            -> T.Text -- ^ The encoded password hash+hashEncoded options password salt =+  unsafePerformIO (hash' options password salt FFI.argon2i_hash_encoded FFI.argon2d_hash_encoded asText)+  where asText = fmap T.decodeUtf8 . BS.packCString++hash :: HashOptions -- ^ Options pertaining to how expensive the hash is to calculate+     -> BS.ByteString -- ^ The password to hash+     -> BS.ByteString -- ^ The salt to use when hashing+     -> BS.ByteString -- ^ The un-encoded password hash+hash options password salt =+  unsafePerformIO (hash' options password salt FFI.argon2i_hash_encoded FFI.argon2d_hash_encoded BS.packCString)++variant :: a -> a -> Argon2Variant -> a+variant a _ Argon2i = a+variant _ b Argon2d = b+{-# INLINE variant #-}++type Argon2 a = Word32 -> Word32 -> Word32 -> CString -> Word64 -> CString -> Word64 -> Word64 -> a -> Word64 -> IO Int32++data Argon2Exception+  = Argon2PasswordLengthOutOfRange Word64 Word64 Word64+  | Argon2SaltLengthOutOfRange Word64 Word64 Word64+  | Argon2MemoryUseOutOfRange Word32 Word32 Word32+  | Argon2IterationCountOutOfRange Word32 Word32 Word32+  | Argon2ParallelismOutOfRange Word32 Word32 Word32+  | Argon2Exception Int32+  deriving (Typeable, Show)++instance Exception Argon2Exception++hash' :: HashOptions+      -> BS.ByteString+      -> BS.ByteString+      -> Argon2 (Ptr a)+      -> Argon2 (Ptr a)+      -> (Ptr a -> IO b)+      -> IO b+hash' HashOptions{..} password salt argon2i argon2d postProcess =+  do out <- mallocBytes 512+     let saltLen = fromIntegral (BS.length salt)+         passwordLen = fromIntegral (BS.length password)+     res <-+       BS.useAsCString password $+       \password' ->+         BS.useAsCString salt $+         \salt' ->+           argon2 hashIterations+                  hashMemory+                  hashParallelism+                  password'+                  passwordLen+                  salt'+                  saltLen+                  64+                  out+                  512+     case res of+       a+         | a `elem` [FFI.ARGON2_OK] -> postProcess out+         | a `elem` [FFI.ARGON2_SALT_TOO_SHORT,FFI.ARGON2_SALT_TOO_LONG] ->+           throwIO (Argon2SaltLengthOutOfRange saltLen+                                               FFI.ARGON2_MIN_SALT_LENGTH+                                               FFI.ARGON2_MAX_SALT_LENGTH)+         | a `elem` [FFI.ARGON2_PWD_TOO_SHORT,FFI.ARGON2_PWD_TOO_LONG] ->+           throwIO (Argon2PasswordLengthOutOfRange passwordLen+                                                   FFI.ARGON2_MIN_PWD_LENGTH+                                                   FFI.ARGON2_MAX_PWD_LENGTH)+         | a `elem` [FFI.ARGON2_TIME_TOO_SMALL,FFI.ARGON2_TIME_TOO_LARGE] ->+           throwIO (Argon2IterationCountOutOfRange hashIterations+                                                   FFI.ARGON2_MIN_TIME+                                                   FFI.ARGON2_MAX_TIME)+         | a `elem` [FFI.ARGON2_MEMORY_TOO_LITTLE,FFI.ARGON2_MEMORY_TOO_MUCH] ->+           throwIO (Argon2MemoryUseOutOfRange+                      hashMemory+                      (max FFI.ARGON2_MIN_MEMORY (8 * hashParallelism))+                      FFI.ARGON2_MAX_MEMORY)+         | a `elem` [FFI.ARGON2_LANES_TOO_FEW,FFI.ARGON2_LANES_TOO_MANY] ->+           throwIO (Argon2ParallelismOutOfRange hashParallelism+                                                FFI.ARGON2_MIN_LANES+                                                FFI.ARGON2_MAX_LANES)+         | otherwise -> throwIO (Argon2Exception a)+  where argon2 = variant argon2i argon2d hashVariant
+ src/Crypto/Argon2/FFI.hsc view
@@ -0,0 +1,88 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE PatternSynonyms #-}++module Crypto.Argon2.FFI where++#include <argon2.h>+#include <stdint.h>++import Foreign+import Foreign.C++foreign import ccall unsafe "argon2.h argon2i_hash_encoded" argon2i_hash_encoded :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> (#type const size_t) -> Ptr b -> (# type const size_t) -> (#type const size_t) -> CString -> (#type const size_t) -> IO (#type int)++foreign import ccall unsafe "argon2.h argon2i_hash_raw" argon2i_hash_raw :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> (#type const size_t) -> Ptr b -> (#type size_t) -> Ptr c -> (#type const size_t) -> IO (#type int)++foreign import ccall unsafe "argon2.h argon2d_hash_encoded" argon2d_hash_encoded :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> (#type const size_t) -> Ptr b -> (# type const size_t) -> (#type const size_t) -> CString -> (#type const size_t) -> IO (#type int)++foreign import ccall unsafe "argon2.h argon2d_hash_raw" argon2d_hash_raw :: (#type const uint32_t) -> (#type const uint32_t) -> (#type const uint32_t) -> Ptr a -> (#type const size_t) -> Ptr b -> (#type size_t) -> Ptr c -> (#type const size_t) -> IO (#type int)++pattern ARGON2_OK = (#const ARGON2_OK)+pattern ARGON2_OUTPUT_PTR_NULL = (#const ARGON2_OUTPUT_PTR_NULL)+pattern ARGON2_OUTPUT_TOO_SHORT = (#const ARGON2_OUTPUT_TOO_SHORT)+pattern ARGON2_OUTPUT_TOO_LONG = (#const ARGON2_OUTPUT_TOO_LONG)+pattern ARGON2_PWD_TOO_SHORT = (#const ARGON2_PWD_TOO_SHORT)+pattern ARGON2_PWD_TOO_LONG = (#const ARGON2_PWD_TOO_LONG)+pattern ARGON2_SALT_TOO_SHORT = (#const ARGON2_SALT_TOO_SHORT)+pattern ARGON2_SALT_TOO_LONG = (#const ARGON2_SALT_TOO_LONG)+pattern ARGON2_AD_TOO_SHORT = (#const ARGON2_AD_TOO_SHORT)+pattern ARGON2_AD_TOO_LONG = (#const ARGON2_AD_TOO_LONG)+pattern ARGON2_SECRET_TOO_SHORT = (#const ARGON2_SECRET_TOO_SHORT)+pattern ARGON2_SECRET_TOO_LONG = (#const ARGON2_SECRET_TOO_LONG)+pattern ARGON2_TIME_TOO_SMALL = (#const ARGON2_TIME_TOO_SMALL)+pattern ARGON2_TIME_TOO_LARGE = (#const ARGON2_TIME_TOO_LARGE)+pattern ARGON2_MEMORY_TOO_LITTLE = (#const ARGON2_MEMORY_TOO_LITTLE)+pattern ARGON2_MEMORY_TOO_MUCH = (#const ARGON2_MEMORY_TOO_MUCH)+pattern ARGON2_LANES_TOO_FEW = (#const ARGON2_LANES_TOO_FEW)+pattern ARGON2_LANES_TOO_MANY = (#const ARGON2_LANES_TOO_MANY)+pattern ARGON2_PWD_PTR_MISMATCH = (#const ARGON2_PWD_PTR_MISMATCH)+pattern ARGON2_SALT_PTR_MISMATCH = (#const ARGON2_SALT_PTR_MISMATCH)+pattern ARGON2_SECRET_PTR_MISMATCH = (#const ARGON2_SECRET_PTR_MISMATCH)+pattern ARGON2_AD_PTR_MISMATCH = (#const ARGON2_AD_PTR_MISMATCH)+pattern ARGON2_MEMORY_ALLOCATION_ERROR = (#const ARGON2_MEMORY_ALLOCATION_ERROR)+pattern ARGON2_FREE_MEMORY_CBK_NULL = (#const ARGON2_FREE_MEMORY_CBK_NULL)+pattern ARGON2_ALLOCATE_MEMORY_CBK_NULL = (#const ARGON2_ALLOCATE_MEMORY_CBK_NULL)+pattern ARGON2_INCORRECT_PARAMETER = (#const ARGON2_INCORRECT_PARAMETER)+pattern ARGON2_INCORRECT_TYPE = (#const ARGON2_INCORRECT_TYPE)+pattern ARGON2_OUT_PTR_MISMATCH = (#const ARGON2_OUT_PTR_MISMATCH)+pattern ARGON2_THREADS_TOO_FEW = (#const ARGON2_THREADS_TOO_FEW)+pattern ARGON2_THREADS_TOO_MANY = (#const ARGON2_THREADS_TOO_MANY)+pattern ARGON2_MISSING_ARGS = (#const ARGON2_MISSING_ARGS)+pattern ARGON2_ENCODING_FAIL = (#const ARGON2_ENCODING_FAIL)+pattern ARGON2_DECODING_FAIL = (#const ARGON2_DECODING_FAIL)++pattern ARGON2_MIN_LANES = (#const ARGON2_MIN_LANES)+pattern ARGON2_MAX_LANES = (#const ARGON2_MAX_LANES)++pattern ARGON2_MIN_THREADS = (#const ARGON2_MIN_THREADS)+pattern ARGON2_MAX_THREADS = (#const ARGON2_MAX_THREADS)++pattern ARGON2_SYNC_POINTS = (#const ARGON2_SYNC_POINTS)++pattern ARGON2_MIN_OUTLEN = (#const ARGON2_MIN_OUTLEN)+pattern ARGON2_MAX_OUTLEN = (#const ARGON2_MAX_OUTLEN)++pattern ARGON2_MIN_MEMORY = (#const ARGON2_MIN_MEMORY)++pattern ARGON2_MAX_MEMORY_BITS = (#const ARGON2_MAX_MEMORY_BITS)+pattern ARGON2_MAX_MEMORY = (#const ARGON2_MAX_MEMORY)++pattern ARGON2_MIN_TIME = (#const ARGON2_MIN_TIME)+pattern ARGON2_MAX_TIME = (#const ARGON2_MAX_TIME)++pattern ARGON2_MIN_PWD_LENGTH = (#const ARGON2_MIN_PWD_LENGTH)+pattern ARGON2_MAX_PWD_LENGTH = (#const ARGON2_MAX_PWD_LENGTH)++pattern ARGON2_MIN_AD_LENGTH = (#const ARGON2_MIN_AD_LENGTH)+pattern ARGON2_MAX_AD_LENGTH = (#const ARGON2_MAX_AD_LENGTH)++pattern ARGON2_MIN_SALT_LENGTH = (#const ARGON2_MIN_SALT_LENGTH)+pattern ARGON2_MAX_SALT_LENGTH = (#const ARGON2_MAX_SALT_LENGTH)++pattern ARGON2_MIN_SECRET = (#const ARGON2_MIN_SECRET)+pattern ARGON2_MAX_SECRET = (#const ARGON2_MAX_SECRET)++pattern ARGON2_FLAG_CLEAR_PASSWORD = (#const ARGON2_FLAG_CLEAR_PASSWORD)+pattern ARGON2_FLAG_CLEAR_SECRET = (#const ARGON2_FLAG_CLEAR_SECRET)+pattern ARGON2_FLAG_CLEAR_MEMORY = (#const ARGON2_FLAG_CLEAR_MEMORY)+pattern ARGON2_DEFAULT_FLAGS = (#const ARGON2_DEFAULT_FLAGS)