luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

Argon2.c (9098B)


      1 /*
      2  * Argon2id Implementation
      3  * RFC 9106
      4  *
      5  * Argon2id = hybrid of Argon2i and Argon2d
      6  * Winner of Password Hashing Competition (2015)
      7  * Resistant to side-channel and GPU attacks
      8  */
      9 
     10 #include "Argon2.h"
     11 #include "hashing/BLAKE2.h"
     12 #include <string.h>
     13 #include <stdlib.h>
     14 
     15 #define ARGON2_BLOCK_SIZE 1024
     16 #define ARGON2_SYNC_POINTS 4
     17 
     18 /* Load 64-bit little-endian */
     19 static inline uint64_t load64_le(const uint8_t *src) {
     20     return (uint64_t)src[0] |
     21            ((uint64_t)src[1] << 8) |
     22            ((uint64_t)src[2] << 16) |
     23            ((uint64_t)src[3] << 24) |
     24            ((uint64_t)src[4] << 32) |
     25            ((uint64_t)src[5] << 40) |
     26            ((uint64_t)src[6] << 48) |
     27            ((uint64_t)src[7] << 56);
     28 }
     29 
     30 /* Store 64-bit little-endian */
     31 static inline void store64_le(uint8_t *dst, uint64_t w) {
     32     dst[0] = (uint8_t)w;
     33     dst[1] = (uint8_t)(w >> 8);
     34     dst[2] = (uint8_t)(w >> 16);
     35     dst[3] = (uint8_t)(w >> 24);
     36     dst[4] = (uint8_t)(w >> 32);
     37     dst[5] = (uint8_t)(w >> 40);
     38     dst[6] = (uint8_t)(w >> 48);
     39     dst[7] = (uint8_t)(w >> 56);
     40 }
     41 
     42 /* Store 32-bit little-endian */
     43 static inline void store32_le(uint8_t *dst, uint32_t w) {
     44     dst[0] = (uint8_t)w;
     45     dst[1] = (uint8_t)(w >> 8);
     46     dst[2] = (uint8_t)(w >> 16);
     47     dst[3] = (uint8_t)(w >> 24);
     48 }
     49 
     50 /* Argon2 block (1024 bytes = 128 uint64_t) */
     51 typedef struct {
     52     uint64_t v[128];
     53 } argon2_block;
     54 
     55 /* Rotate right */
     56 #define ROR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
     57 
     58 /* Blake2b-based hash function */
     59 static void argon2_hash(uint8_t *out, size_t outlen,
     60                         const uint8_t *in, size_t inlen) {
     61     if (outlen <= 64) {
     62         blake2b(in, inlen, out, outlen);
     63     } else {
     64         /* Extended output */
     65         uint8_t out_buffer[64];
     66         uint32_t toproduce = (uint32_t)outlen;
     67 
     68         blake2b(in, inlen, out_buffer, 64);
     69 
     70         uint32_t to_copy = (toproduce > 32) ? 32 : toproduce;
     71         memcpy(out, out_buffer + 32, to_copy);
     72         out += to_copy;
     73         toproduce -= to_copy;
     74 
     75         while (toproduce > 64) {
     76             blake2b(out_buffer, 64, out_buffer, 64);
     77             memcpy(out, out_buffer + 32, 32);
     78             out += 32;
     79             toproduce -= 32;
     80         }
     81 
     82         if (toproduce > 0) {
     83             blake2b(out_buffer, 64, out_buffer, toproduce);
     84             memcpy(out, out_buffer, toproduce);
     85         }
     86     }
     87 }
     88 
     89 /* GB function */
     90 static void gb(uint64_t *a, uint64_t *b, uint64_t *c, uint64_t *d) {
     91     *a = *a + *b + 2 * (*a & 0xFFFFFFFF) * (*b & 0xFFFFFFFF);
     92     *d = ROR64(*d ^ *a, 32);
     93     *c = *c + *d + 2 * (*c & 0xFFFFFFFF) * (*d & 0xFFFFFFFF);
     94     *b = ROR64(*b ^ *c, 24);
     95     *a = *a + *b + 2 * (*a & 0xFFFFFFFF) * (*b & 0xFFFFFFFF);
     96     *d = ROR64(*d ^ *a, 16);
     97     *c = *c + *d + 2 * (*c & 0xFFFFFFFF) * (*d & 0xFFFFFFFF);
     98     *b = ROR64(*b ^ *c, 63);
     99 }
    100 
    101 /* Permutation P */
    102 static void argon2_permute(argon2_block *block) {
    103     for (int i = 0; i < 8; i++) {
    104         gb(&block->v[16 * i], &block->v[16 * i + 1], &block->v[16 * i + 2], &block->v[16 * i + 3]);
    105         gb(&block->v[16 * i + 4], &block->v[16 * i + 5], &block->v[16 * i + 6], &block->v[16 * i + 7]);
    106         gb(&block->v[16 * i + 8], &block->v[16 * i + 9], &block->v[16 * i + 10], &block->v[16 * i + 11]);
    107         gb(&block->v[16 * i + 12], &block->v[16 * i + 13], &block->v[16 * i + 14], &block->v[16 * i + 15]);
    108         gb(&block->v[16 * i], &block->v[16 * i + 4], &block->v[16 * i + 8], &block->v[16 * i + 12]);
    109         gb(&block->v[16 * i + 1], &block->v[16 * i + 5], &block->v[16 * i + 9], &block->v[16 * i + 13]);
    110         gb(&block->v[16 * i + 2], &block->v[16 * i + 6], &block->v[16 * i + 10], &block->v[16 * i + 14]);
    111         gb(&block->v[16 * i + 3], &block->v[16 * i + 7], &block->v[16 * i + 11], &block->v[16 * i + 15]);
    112     }
    113 
    114     for (int i = 0; i < 8; i++) {
    115         gb(&block->v[2 * i], &block->v[2 * i + 1], &block->v[2 * i + 16], &block->v[2 * i + 17]);
    116         gb(&block->v[2 * i + 32], &block->v[2 * i + 33], &block->v[2 * i + 48], &block->v[2 * i + 49]);
    117         gb(&block->v[2 * i + 64], &block->v[2 * i + 65], &block->v[2 * i + 80], &block->v[2 * i + 81]);
    118         gb(&block->v[2 * i + 96], &block->v[2 * i + 97], &block->v[2 * i + 112], &block->v[2 * i + 113]);
    119         gb(&block->v[2 * i], &block->v[2 * i + 32], &block->v[2 * i + 64], &block->v[2 * i + 96]);
    120         gb(&block->v[2 * i + 1], &block->v[2 * i + 33], &block->v[2 * i + 65], &block->v[2 * i + 97]);
    121         gb(&block->v[2 * i + 16], &block->v[2 * i + 48], &block->v[2 * i + 80], &block->v[2 * i + 112]);
    122         gb(&block->v[2 * i + 17], &block->v[2 * i + 49], &block->v[2 * i + 81], &block->v[2 * i + 113]);
    123     }
    124 }
    125 
    126 /* Compression function G */
    127 static void argon2_g(argon2_block *result, const argon2_block *x, const argon2_block *y) {
    128     argon2_block r;
    129 
    130     /* R = X xor Y */
    131     for (int i = 0; i < 128; i++) {
    132         r.v[i] = x->v[i] ^ y->v[i];
    133     }
    134 
    135     /* Q = P(R) */
    136     argon2_permute(&r);
    137 
    138     /* Z = R xor Q xor X */
    139     for (int i = 0; i < 128; i++) {
    140         result->v[i] = r.v[i] ^ x->v[i] ^ y->v[i];
    141     }
    142 }
    143 
    144 /* Simplified Argon2id - optimized for typical use case */
    145 /* Debug output function */
    146 extern void terminal_writestring(const char *s);
    147 
    148 int argon2id(const uint8_t *password, size_t pwdlen,
    149              const uint8_t *salt, size_t saltlen,
    150              uint32_t t_cost, uint32_t m_cost,
    151              uint8_t *out, size_t outlen) {
    152 
    153     if (!password || !salt || !out) {
    154         terminal_writestring("[Argon2] ERROR: NULL parameter\n");
    155         return -1;
    156     }
    157     if (t_cost < 1) t_cost = 1;
    158     if (m_cost < 8) m_cost = 8;  /* Minimum 8 KB */
    159 
    160     /* Allocate memory blocks */
    161     uint32_t memory_blocks = m_cost;
    162     terminal_writestring("[Argon2] Allocating memory...\n");
    163     argon2_block *memory = calloc(memory_blocks, sizeof(argon2_block));
    164     if (!memory) {
    165         terminal_writestring("[Argon2] ERROR: calloc failed!\n");
    166         return -1;
    167     }
    168     terminal_writestring("[Argon2] Memory allocated, computing...\n");
    169 
    170     /* Initial hash H0 */
    171     uint8_t h0[64];
    172     uint8_t blockhash[1024];
    173     size_t pos = 0;
    174 
    175     store32_le(blockhash + pos, 1); pos += 4;  /* parallelism */
    176     store32_le(blockhash + pos, (uint32_t)outlen); pos += 4;
    177     store32_le(blockhash + pos, m_cost); pos += 4;
    178     store32_le(blockhash + pos, t_cost); pos += 4;
    179     store32_le(blockhash + pos, 0x13); pos += 4;  /* version 0x13 */
    180     store32_le(blockhash + pos, 2); pos += 4;  /* type = Argon2id */
    181     store32_le(blockhash + pos, (uint32_t)pwdlen); pos += 4;
    182     memcpy(blockhash + pos, password, pwdlen); pos += pwdlen;
    183     store32_le(blockhash + pos, (uint32_t)saltlen); pos += 4;
    184     memcpy(blockhash + pos, salt, saltlen); pos += saltlen;
    185     store32_le(blockhash + pos, 0); pos += 4;  /* no secret */
    186     store32_le(blockhash + pos, 0); pos += 4;  /* no associated data */
    187 
    188     blake2b(blockhash, pos, h0, 64);
    189 
    190     /* Generate first two blocks */
    191     for (int i = 0; i < 2; i++) {
    192         uint8_t block_bytes[1024];
    193         store32_le(blockhash, (uint32_t)outlen);
    194         memcpy(blockhash + 4, h0, 64);
    195         store32_le(blockhash + 68, 0);  /* lane */
    196         store32_le(blockhash + 72, i);  /* slice */
    197 
    198         argon2_hash(block_bytes, 1024, blockhash, 76);
    199 
    200         for (int j = 0; j < 128; j++) {
    201             memory[i].v[j] = load64_le(block_bytes + j * 8);
    202         }
    203     }
    204 
    205     /* Fill remaining blocks using simplified scheme */
    206     for (uint32_t i = 2; i < memory_blocks; i++) {
    207         uint32_t ref_index = (i - 1) % memory_blocks;
    208         uint32_t ref_index2 = (i - 2) % memory_blocks;
    209         argon2_g(&memory[i], &memory[ref_index], &memory[ref_index2]);
    210     }
    211 
    212     /* Additional passes */
    213     for (uint32_t pass = 1; pass < t_cost; pass++) {
    214         for (uint32_t i = 0; i < memory_blocks; i++) {
    215             uint32_t ref_index = (i + memory_blocks - 1) % memory_blocks;
    216             uint32_t ref_index2 = (i + memory_blocks - 2) % memory_blocks;
    217             argon2_block tmp;
    218             argon2_g(&tmp, &memory[i], &memory[ref_index]);
    219             argon2_g(&memory[i], &tmp, &memory[ref_index2]);
    220         }
    221     }
    222 
    223     /* Final block */
    224     argon2_block final_block = memory[memory_blocks - 1];
    225     for (uint32_t i = 0; i < memory_blocks - 1; i++) {
    226         for (int j = 0; j < 128; j++) {
    227             final_block.v[j] ^= memory[i].v[j];
    228         }
    229     }
    230 
    231     /* Extract output */
    232     uint8_t final_bytes[1024];
    233     for (int i = 0; i < 128; i++) {
    234         store64_le(final_bytes + i * 8, final_block.v[i]);
    235     }
    236 
    237     argon2_hash(out, outlen, final_bytes, 1024);
    238 
    239     /* Clean up */
    240     memset(memory, 0, memory_blocks * sizeof(argon2_block));
    241     memset(blockhash, 0, sizeof(blockhash));
    242     memset(h0, 0, sizeof(h0));
    243     memset(final_bytes, 0, sizeof(final_bytes));
    244     free(memory);
    245 
    246     return 0;
    247 }
    248 
    249 /* Simple interface with recommended defaults */
    250 int argon2id_simple(const uint8_t *password, size_t pwdlen,
    251                     const uint8_t *salt, size_t saltlen,
    252                     uint8_t *out, size_t outlen) {
    253     /* Recommended defaults: t=3, m=64MB */
    254     return argon2id(password, pwdlen, salt, saltlen, 3, 65536, out, outlen);
    255 }