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 }