argon2 1.1.4 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -21,7 +21,7 @@
21
21
  #include "blake2.h"
22
22
  #include "blake2-impl.h"
23
23
 
24
- /*designed by the Lyra PHC team */
24
+ /* designed by the Lyra PHC team */
25
25
  static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {
26
26
  const uint64_t m = UINT64_C(0xFFFFFFFF);
27
27
  const uint64_t xy = (x & m) * (y & m);
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -25,7 +25,6 @@
25
25
  #endif
26
26
  #define VC_GE_2005(version) (version >= 1400)
27
27
 
28
- #include <inttypes.h>
29
28
  #include <stdio.h>
30
29
  #include <stdlib.h>
31
30
  #include <string.h>
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -20,14 +20,6 @@
20
20
 
21
21
  #include "argon2.h"
22
22
 
23
- #if defined(_MSC_VER)
24
- #define ALIGN(n) __declspec(align(16))
25
- #elif defined(__GNUC__) || defined(__clang)
26
- #define ALIGN(x) __attribute__((__aligned__(x)))
27
- #else
28
- #define ALIGN(x)
29
- #endif
30
-
31
23
  #define CONST_CAST(x) (x)(uintptr_t)
32
24
 
33
25
  /**********************Argon2 internal constants*******************************/
@@ -37,6 +29,8 @@ enum argon2_core_constants {
37
29
  ARGON2_BLOCK_SIZE = 1024,
38
30
  ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
39
31
  ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
32
+ ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
33
+ ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
40
34
 
41
35
  /* Number of pseudo-random values generated by one call to Blake in Argon2i
42
36
  to
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -15,7 +15,6 @@
15
15
  * software. If not, they may be obtained at the above URLs.
16
16
  */
17
17
 
18
- #include <inttypes.h>
19
18
  #include <stdio.h>
20
19
  #include <stdlib.h>
21
20
  #include <string.h>
@@ -116,8 +115,8 @@ void internal_kat(const argon2_instance_t *instance, uint32_t pass) {
116
115
  : ARGON2_QWORDS_IN_BLOCK;
117
116
 
118
117
  for (j = 0; j < how_many_words; ++j)
119
- printf("Block %.4u [%3u]: %016" PRIx64 "\n", i, j,
120
- instance->memory[i].v[j]);
118
+ printf("Block %.4u [%3u]: %016llx\n", i, j,
119
+ (unsigned long long)instance->memory[i].v[j]);
121
120
  }
122
121
  }
123
122
  }
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -34,6 +34,79 @@
34
34
  * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
35
35
  * @pre all block pointers must be valid
36
36
  */
37
+ #if defined(__AVX512F__)
38
+ static void fill_block(__m512i *state, const block *ref_block,
39
+ block *next_block, int with_xor) {
40
+ __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];
41
+ unsigned int i;
42
+
43
+ if (with_xor) {
44
+ for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
45
+ state[i] = _mm512_xor_si512(
46
+ state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
47
+ block_XY[i] = _mm512_xor_si512(
48
+ state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));
49
+ }
50
+ } else {
51
+ for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
52
+ block_XY[i] = state[i] = _mm512_xor_si512(
53
+ state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
54
+ }
55
+ }
56
+
57
+ for (i = 0; i < 2; ++i) {
58
+ BLAKE2_ROUND_1(
59
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
60
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
61
+ }
62
+
63
+ for (i = 0; i < 2; ++i) {
64
+ BLAKE2_ROUND_2(
65
+ state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],
66
+ state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);
67
+ }
68
+
69
+ for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
70
+ state[i] = _mm512_xor_si512(state[i], block_XY[i]);
71
+ _mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);
72
+ }
73
+ }
74
+ #elif defined(__AVX2__)
75
+ static void fill_block(__m256i *state, const block *ref_block,
76
+ block *next_block, int with_xor) {
77
+ __m256i block_XY[ARGON2_HWORDS_IN_BLOCK];
78
+ unsigned int i;
79
+
80
+ if (with_xor) {
81
+ for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
82
+ state[i] = _mm256_xor_si256(
83
+ state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
84
+ block_XY[i] = _mm256_xor_si256(
85
+ state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));
86
+ }
87
+ } else {
88
+ for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
89
+ block_XY[i] = state[i] = _mm256_xor_si256(
90
+ state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
91
+ }
92
+ }
93
+
94
+ for (i = 0; i < 4; ++i) {
95
+ BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
96
+ state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
97
+ }
98
+
99
+ for (i = 0; i < 4; ++i) {
100
+ BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],
101
+ state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
102
+ }
103
+
104
+ for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
105
+ state[i] = _mm256_xor_si256(state[i], block_XY[i]);
106
+ _mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);
107
+ }
108
+ }
109
+ #else
37
110
  static void fill_block(__m128i *state, const block *ref_block,
38
111
  block *next_block, int with_xor) {
39
112
  __m128i block_XY[ARGON2_OWORDS_IN_BLOCK];
@@ -70,11 +143,20 @@ static void fill_block(__m128i *state, const block *ref_block,
70
143
  _mm_storeu_si128((__m128i *)next_block->v + i, state[i]);
71
144
  }
72
145
  }
146
+ #endif
73
147
 
74
148
  static void next_addresses(block *address_block, block *input_block) {
75
149
  /*Temporary zero-initialized blocks*/
150
+ #if defined(__AVX512F__)
151
+ __m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];
152
+ __m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];
153
+ #elif defined(__AVX2__)
154
+ __m256i zero_block[ARGON2_HWORDS_IN_BLOCK];
155
+ __m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];
156
+ #else
76
157
  __m128i zero_block[ARGON2_OWORDS_IN_BLOCK];
77
158
  __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];
159
+ #endif
78
160
 
79
161
  memset(zero_block, 0, sizeof(zero_block));
80
162
  memset(zero2_block, 0, sizeof(zero2_block));
@@ -96,7 +178,13 @@ void fill_segment(const argon2_instance_t *instance,
96
178
  uint64_t pseudo_rand, ref_index, ref_lane;
97
179
  uint32_t prev_offset, curr_offset;
98
180
  uint32_t starting_index, i;
99
- __m128i state[64];
181
+ #if defined(__AVX512F__)
182
+ __m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];
183
+ #elif defined(__AVX2__)
184
+ __m256i state[ARGON2_HWORDS_IN_BLOCK];
185
+ #else
186
+ __m128i state[ARGON2_OWORDS_IN_BLOCK];
187
+ #endif
100
188
  int data_independent_addressing;
101
189
 
102
190
  if (instance == NULL) {
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -17,7 +17,6 @@
17
17
 
18
18
  #define _GNU_SOURCE 1
19
19
 
20
- #include <inttypes.h>
21
20
  #include <stdint.h>
22
21
  #include <stdio.h>
23
22
  #include <stdlib.h>
@@ -37,8 +36,9 @@
37
36
  #define UNUSED_PARAMETER(x) (void)(x)
38
37
 
39
38
  static void usage(const char *cmd) {
40
- printf("Usage: %s [-h] salt [-i|-d|-id] [-t iterations] [-m memory] "
41
- "[-p parallelism] [-l hash length] [-e|-r] [-v (10|13)]\n",
39
+ printf("Usage: %s [-h] salt [-i|-d|-id] [-t iterations] "
40
+ "[-m log2(memory in KiB) | -k memory in KiB] [-p parallelism] "
41
+ "[-l hash length] [-e|-r] [-v (10|13)]\n",
42
42
  cmd);
43
43
  printf("\tPassword is read from stdin\n");
44
44
  printf("Parameters:\n");
@@ -50,6 +50,8 @@ static void usage(const char *cmd) {
50
50
  T_COST_DEF);
51
51
  printf("\t-m N\t\tSets the memory usage of 2^N KiB (default %d)\n",
52
52
  LOG_M_COST_DEF);
53
+ printf("\t-k N\t\tSets the memory usage of N KiB (default %d)\n",
54
+ 1 << LOG_M_COST_DEF);
53
55
  printf("\t-p N\t\tSets parallelism to N threads (default %d)\n",
54
56
  THREADS_DEF);
55
57
  printf("\t-l N\t\tSets hash output length to N bytes (default %d)\n",
@@ -89,11 +91,11 @@ Base64-encoded hash string
89
91
  @raw_only display only the hexadecimal of the hash
90
92
  @version Argon2 version
91
93
  */
92
- static void run(uint32_t outlen, char *pwd, char *salt, uint32_t t_cost,
94
+ static void run(uint32_t outlen, char *pwd, size_t pwdlen, char *salt, uint32_t t_cost,
93
95
  uint32_t m_cost, uint32_t lanes, uint32_t threads,
94
96
  argon2_type type, int encoded_only, int raw_only, uint32_t version) {
95
97
  clock_t start_time, stop_time;
96
- size_t pwdlen, saltlen, encodedlen;
98
+ size_t saltlen, encodedlen;
97
99
  int result;
98
100
  unsigned char * out = NULL;
99
101
  char * encoded = NULL;
@@ -105,11 +107,10 @@ static void run(uint32_t outlen, char *pwd, char *salt, uint32_t t_cost,
105
107
  }
106
108
 
107
109
  if (!salt) {
108
- clear_internal_memory(pwd, strlen(pwd));
110
+ clear_internal_memory(pwd, pwdlen);
109
111
  fatal("salt missing");
110
112
  }
111
113
 
112
- pwdlen = strlen(pwd);
113
114
  saltlen = strlen(salt);
114
115
  if(UINT32_MAX < saltlen) {
115
116
  fatal("salt is too long");
@@ -119,14 +120,14 @@ static void run(uint32_t outlen, char *pwd, char *salt, uint32_t t_cost,
119
120
 
120
121
  out = malloc(outlen + 1);
121
122
  if (!out) {
122
- clear_internal_memory(pwd, strlen(pwd));
123
+ clear_internal_memory(pwd, pwdlen);
123
124
  fatal("could not allocate memory for output");
124
125
  }
125
126
 
126
127
  encodedlen = argon2_encodedlen(t_cost, m_cost, lanes, (uint32_t)saltlen, outlen, type);
127
128
  encoded = malloc(encodedlen + 1);
128
129
  if (!encoded) {
129
- clear_internal_memory(pwd, strlen(pwd));
130
+ clear_internal_memory(pwd, pwdlen);
130
131
  fatal("could not allocate memory for hash");
131
132
  }
132
133
 
@@ -174,11 +175,12 @@ int main(int argc, char *argv[]) {
174
175
  uint32_t threads = THREADS_DEF;
175
176
  argon2_type type = Argon2_i; /* Argon2i is the default type */
176
177
  int types_specified = 0;
178
+ int m_cost_specified = 0;
177
179
  int encoded_only = 0;
178
180
  int raw_only = 0;
179
181
  uint32_t version = ARGON2_VERSION_NUMBER;
180
182
  int i;
181
- size_t n;
183
+ size_t pwdlen;
182
184
  char pwd[MAX_PASS_LEN], *salt;
183
185
 
184
186
  if (argc < 2) {
@@ -190,19 +192,14 @@ int main(int argc, char *argv[]) {
190
192
  }
191
193
 
192
194
  /* get password from stdin */
193
- n = fread(pwd, 1, sizeof pwd - 1, stdin);
194
- if(n < 1) {
195
+ pwdlen = fread(pwd, 1, sizeof pwd, stdin);
196
+ if(pwdlen < 1) {
195
197
  fatal("no password read");
196
198
  }
197
- if(n == MAX_PASS_LEN-1) {
199
+ if(pwdlen == MAX_PASS_LEN) {
198
200
  fatal("Provided password longer than supported in command line utility");
199
201
  }
200
202
 
201
- pwd[n] = '\0';
202
- if (pwd[n - 1] == '\n') {
203
- pwd[n - 1] = '\0';
204
- }
205
-
206
203
  salt = argv[1];
207
204
 
208
205
  /* parse options */
@@ -213,6 +210,10 @@ int main(int argc, char *argv[]) {
213
210
  usage(argv[0]);
214
211
  return 1;
215
212
  } else if (!strcmp(a, "-m")) {
213
+ if (m_cost_specified) {
214
+ fatal("-m or -k can only be used once");
215
+ }
216
+ m_cost_specified = 1;
216
217
  if (i < argc - 1) {
217
218
  i++;
218
219
  input = strtoul(argv[i], NULL, 10);
@@ -228,6 +229,25 @@ int main(int argc, char *argv[]) {
228
229
  } else {
229
230
  fatal("missing -m argument");
230
231
  }
232
+ } else if (!strcmp(a, "-k")) {
233
+ if (m_cost_specified) {
234
+ fatal("-m or -k can only be used once");
235
+ }
236
+ m_cost_specified = 1;
237
+ if (i < argc - 1) {
238
+ i++;
239
+ input = strtoul(argv[i], NULL, 10);
240
+ if (input == 0 || input == ULONG_MAX) {
241
+ fatal("bad numeric input for -k");
242
+ }
243
+ m_cost = ARGON2_MIN(input, UINT32_C(0xFFFFFFFF));
244
+ if (m_cost > ARGON2_MAX_MEMORY) {
245
+ fatal("m_cost overflow");
246
+ }
247
+ continue;
248
+ } else {
249
+ fatal("missing -k argument");
250
+ }
231
251
  } else if (!strcmp(a, "-t")) {
232
252
  if (i < argc - 1) {
233
253
  i++;
@@ -304,12 +324,12 @@ int main(int argc, char *argv[]) {
304
324
 
305
325
  if(!encoded_only && !raw_only) {
306
326
  printf("Type:\t\t%s\n", argon2_type2string(type, 1));
307
- printf("Iterations:\t%" PRIu32 " \n", t_cost);
308
- printf("Memory:\t\t%" PRIu32 " KiB\n", m_cost);
309
- printf("Parallelism:\t%" PRIu32 " \n", lanes);
327
+ printf("Iterations:\t%u\n", t_cost);
328
+ printf("Memory:\t\t%u KiB\n", m_cost);
329
+ printf("Parallelism:\t%u\n", lanes);
310
330
  }
311
331
 
312
- run(outlen, pwd, salt, t_cost, m_cost, lanes, threads, type,
332
+ run(outlen, pwd, pwdlen, salt, t_cost, m_cost, lanes, threads, type,
313
333
  encoded_only, raw_only, version);
314
334
 
315
335
  return ARGON2_OK;
@@ -4,7 +4,7 @@
4
4
  * Copyright 2015
5
5
  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6
6
  *
7
- * You may use this work under the terms of a Creative Commons CC0 1.0
7
+ * You may use this work under the terms of a Creative Commons CC0 1.0
8
8
  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9
9
  * these licenses can be found at:
10
10
  *
@@ -17,7 +17,6 @@
17
17
 
18
18
  #include <stdio.h>
19
19
  #include <stdint.h>
20
- #include <inttypes.h>
21
20
  #include <stdlib.h>
22
21
  #include <string.h>
23
22
  #include <time.h>
@@ -81,7 +80,7 @@ int main() {
81
80
  "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ"
82
81
  "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ");
83
82
  #ifdef TEST_LARGE_RAM
84
- hashtest(version, 2, 20, 1, "password", "somesalt",
83
+ hashtest(version, 2, 20, 1, "password", "somesalt",
85
84
  "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9",
86
85
  "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ"
87
86
  "$lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk");
@@ -160,10 +159,10 @@ int main() {
160
159
  "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ"
161
160
  "$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA");
162
161
  #ifdef TEST_LARGE_RAM
163
- hashtest(version, 2, 20, 1, "password", "somesalt",
162
+ hashtest(version, 2, 20, 1, "password", "somesalt",
164
163
  "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41",
165
- "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ"
166
- "$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E");
164
+ "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ"
165
+ "$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E");
167
166
  #endif
168
167
  hashtest(version, 2, 18, 1, "password", "somesalt",
169
168
  "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb",