argon2-encoding.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include "argon2-encoding.h"
  2. #include "argon2-core.h"
  3. #include "utils.h"
  4. #include <limits.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. /*
  9. * Example code for a decoder and encoder of "hash strings", with Argon2
  10. * parameters.
  11. *
  12. * The code was originally written by Thomas Pornin <pornin@bolet.org>,
  13. * to whom comments and remarks may be sent. It is released under what
  14. * should amount to Public Domain or its closest equivalent; the
  15. * following mantra is supposed to incarnate that fact with all the
  16. * proper legal rituals:
  17. *
  18. * ---------------------------------------------------------------------
  19. * This file is provided under the terms of Creative Commons CC0 1.0
  20. * Public Domain Dedication. To the extent possible under law, the
  21. * author (Thomas Pornin) has waived all copyright and related or
  22. * neighboring rights to this file. This work is published from: Canada.
  23. * ---------------------------------------------------------------------
  24. *
  25. * Copyright (c) 2015 Thomas Pornin
  26. */
  27. /* ==================================================================== */
  28. /*
  29. * Decode decimal integer from 'str'; the value is written in '*v'.
  30. * Returned value is a pointer to the next non-decimal character in the
  31. * string. If there is no digit at all, or the value encoding is not
  32. * minimal (extra leading zeros), or the value does not fit in an
  33. * 'unsigned long', then NULL is returned.
  34. */
  35. static const char *
  36. decode_decimal(const char *str, unsigned long *v)
  37. {
  38. const char *orig;
  39. unsigned long acc;
  40. acc = 0;
  41. for (orig = str;; str++) {
  42. int c;
  43. c = *str;
  44. if (c < '0' || c > '9') {
  45. break;
  46. }
  47. c -= '0';
  48. if (acc > (ULONG_MAX / 10)) {
  49. return NULL;
  50. }
  51. acc *= 10;
  52. if ((unsigned long) c > (ULONG_MAX - acc)) {
  53. return NULL;
  54. }
  55. acc += (unsigned long) c;
  56. }
  57. if (str == orig || (*orig == '0' && str != (orig + 1))) {
  58. return NULL;
  59. }
  60. *v = acc;
  61. return str;
  62. }
  63. /* ==================================================================== */
  64. /*
  65. * Code specific to Argon2.
  66. *
  67. * The code below applies the following format:
  68. *
  69. * $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<bin>$<bin>
  70. *
  71. * where <T> is either 'i', <num> is a decimal integer (positive, fits in an
  72. * 'unsigned long') and <bin> is Base64-encoded data (no '=' padding characters,
  73. * no newline or whitespace).
  74. *
  75. * The last two binary chunks (encoded in Base64) are, in that order,
  76. * the salt and the output. Both are required. The binary salt length and the
  77. * output length must be in the allowed ranges defined in argon2.h.
  78. *
  79. * The ctx struct must contain buffers large enough to hold the salt and pwd
  80. * when it is fed into argon2_decode_string.
  81. */
  82. /*
  83. * Decode an Argon2i hash string into the provided structure 'ctx'.
  84. * Returned value is ARGON2_OK on success.
  85. */
  86. int
  87. argon2_decode_string(argon2_context *ctx, const char *str, argon2_type type)
  88. {
  89. /* Prefix checking */
  90. #define CC(prefix) \
  91. do { \
  92. size_t cc_len = strlen(prefix); \
  93. if (strncmp(str, prefix, cc_len) != 0) { \
  94. return ARGON2_DECODING_FAIL; \
  95. } \
  96. str += cc_len; \
  97. } while ((void) 0, 0)
  98. /* Optional prefix checking with supplied code */
  99. #define CC_opt(prefix, code) \
  100. do { \
  101. size_t cc_len = strlen(prefix); \
  102. if (strncmp(str, prefix, cc_len) == 0) { \
  103. str += cc_len; \
  104. { \
  105. code; \
  106. } \
  107. } \
  108. } while ((void) 0, 0)
  109. /* Decoding prefix into decimal */
  110. #define DECIMAL(x) \
  111. do { \
  112. unsigned long dec_x; \
  113. str = decode_decimal(str, &dec_x); \
  114. if (str == NULL) { \
  115. return ARGON2_DECODING_FAIL; \
  116. } \
  117. (x) = dec_x; \
  118. } while ((void) 0, 0)
  119. /* Decoding prefix into uint32_t decimal */
  120. #define DECIMAL_U32(x) \
  121. do { \
  122. unsigned long dec_x; \
  123. str = decode_decimal(str, &dec_x); \
  124. if (str == NULL || dec_x > UINT32_MAX) { \
  125. return ARGON2_DECODING_FAIL; \
  126. } \
  127. (x) = (uint32_t)dec_x; \
  128. } while ((void)0, 0)
  129. /* Decoding base64 into a binary buffer */
  130. #define BIN(buf, max_len, len) \
  131. do { \
  132. size_t bin_len = (max_len); \
  133. const char *str_end; \
  134. if (sodium_base642bin((buf), (max_len), str, strlen(str), NULL, \
  135. &bin_len, &str_end, \
  136. sodium_base64_VARIANT_ORIGINAL_NO_PADDING) != 0 || \
  137. bin_len > UINT32_MAX) { \
  138. return ARGON2_DECODING_FAIL; \
  139. } \
  140. (len) = (uint32_t) bin_len; \
  141. str = str_end; \
  142. } while ((void) 0, 0)
  143. size_t maxsaltlen = ctx->saltlen;
  144. size_t maxoutlen = ctx->outlen;
  145. int validation_result;
  146. uint32_t version = 0;
  147. ctx->saltlen = 0;
  148. ctx->outlen = 0;
  149. if (type == Argon2_id) {
  150. CC("$argon2id");
  151. } else if (type == Argon2_i) {
  152. CC("$argon2i");
  153. } else {
  154. return ARGON2_INCORRECT_TYPE;
  155. }
  156. CC("$v=");
  157. DECIMAL_U32(version);
  158. if (version != ARGON2_VERSION_NUMBER) {
  159. return ARGON2_INCORRECT_TYPE;
  160. }
  161. CC("$m=");
  162. DECIMAL_U32(ctx->m_cost);
  163. if (ctx->m_cost > UINT32_MAX) {
  164. return ARGON2_INCORRECT_TYPE;
  165. }
  166. CC(",t=");
  167. DECIMAL_U32(ctx->t_cost);
  168. if (ctx->t_cost > UINT32_MAX) {
  169. return ARGON2_INCORRECT_TYPE;
  170. }
  171. CC(",p=");
  172. DECIMAL_U32(ctx->lanes);
  173. if (ctx->lanes > UINT32_MAX) {
  174. return ARGON2_INCORRECT_TYPE;
  175. }
  176. ctx->threads = ctx->lanes;
  177. CC("$");
  178. BIN(ctx->salt, maxsaltlen, ctx->saltlen);
  179. CC("$");
  180. BIN(ctx->out, maxoutlen, ctx->outlen);
  181. validation_result = argon2_validate_inputs(ctx);
  182. if (validation_result != ARGON2_OK) {
  183. return validation_result;
  184. }
  185. if (*str == 0) {
  186. return ARGON2_OK;
  187. }
  188. return ARGON2_DECODING_FAIL;
  189. #undef CC
  190. #undef CC_opt
  191. #undef DECIMAL
  192. #undef BIN
  193. }
  194. #define U32_STR_MAXSIZE 11U
  195. static void
  196. u32_to_string(char *str, uint32_t x)
  197. {
  198. char tmp[U32_STR_MAXSIZE - 1U];
  199. size_t i;
  200. i = sizeof tmp;
  201. do {
  202. tmp[--i] = (x % (uint32_t) 10U) + '0';
  203. x /= (uint32_t) 10U;
  204. } while (x != 0U && i != 0U);
  205. memcpy(str, &tmp[i], (sizeof tmp) - i);
  206. str[(sizeof tmp) - i] = 0;
  207. }
  208. /*
  209. * Encode an argon2i hash string into the provided buffer. 'dst_len'
  210. * contains the size, in characters, of the 'dst' buffer; if 'dst_len'
  211. * is less than the number of required characters (including the
  212. * terminating 0), then this function returns 0.
  213. *
  214. * If pp->output_len is 0, then the hash string will be a salt string
  215. * (no output). if pp->salt_len is also 0, then the string will be a
  216. * parameter-only string (no salt and no output).
  217. *
  218. * On success, ARGON2_OK is returned.
  219. */
  220. int
  221. argon2_encode_string(char *dst, size_t dst_len, argon2_context *ctx,
  222. argon2_type type)
  223. {
  224. #define SS(str) \
  225. do { \
  226. size_t pp_len = strlen(str); \
  227. if (pp_len >= dst_len) { \
  228. return ARGON2_ENCODING_FAIL; \
  229. } \
  230. memcpy(dst, str, pp_len + 1); \
  231. dst += pp_len; \
  232. dst_len -= pp_len; \
  233. } while ((void) 0, 0)
  234. #define SX(x) \
  235. do { \
  236. char tmp[U32_STR_MAXSIZE]; \
  237. u32_to_string(tmp, x); \
  238. SS(tmp); \
  239. } while ((void) 0, 0)
  240. #define SB(buf, len) \
  241. do { \
  242. size_t sb_len; \
  243. if (sodium_bin2base64(dst, dst_len, (buf), (len), \
  244. sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == NULL) { \
  245. return ARGON2_ENCODING_FAIL; \
  246. } \
  247. sb_len = strlen(dst); \
  248. dst += sb_len; \
  249. dst_len -= sb_len; \
  250. } while ((void) 0, 0)
  251. int validation_result;
  252. switch (type) {
  253. case Argon2_id:
  254. SS("$argon2id$v="); break;
  255. case Argon2_i:
  256. SS("$argon2i$v="); break;
  257. default:
  258. return ARGON2_ENCODING_FAIL;
  259. }
  260. validation_result = argon2_validate_inputs(ctx);
  261. if (validation_result != ARGON2_OK) {
  262. return validation_result;
  263. }
  264. SX(ARGON2_VERSION_NUMBER);
  265. SS("$m=");
  266. SX(ctx->m_cost);
  267. SS(",t=");
  268. SX(ctx->t_cost);
  269. SS(",p=");
  270. SX(ctx->lanes);
  271. SS("$");
  272. SB(ctx->salt, ctx->saltlen);
  273. SS("$");
  274. SB(ctx->out, ctx->outlen);
  275. return ARGON2_OK;
  276. #undef SS
  277. #undef SX
  278. #undef SB
  279. }