Skip to content

Commit a3b4be9

Browse files
committed
Add argon2 backend
Argon2 is a memory-hard function for password-hashing and proof-of-work applications. It aims at the highest memory filling rate and effective use of multiple computing units, while still providing defense against tradeoff attacks. See: https://github.com/P-H-C/phc-winner-argon2 The argon2 hashes require libargon2, which is an optional dependency. Compatible with output of argon2 executable.
1 parent b475497 commit a3b4be9

12 files changed

Lines changed: 480 additions & 21 deletions

AUTHORS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
The Argon2 hash module is based on algorithms and ideas developed
2+
by Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and
3+
Samuel Neves. See: https://github.com/P-H-C/phc-winner-argon2 for
4+
reference.
5+
16
The yescrypt code comes from yescrypt by Solar Designer <solar at
27
openwall.com>. It builds upon Colin Percival's scrypt.
38
See: http://openwall.com/yescrypt/ for reference.

LICENSING

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ source tree. For specific licensing terms consult the files themselves.
8989
* Copyright <vt at altlinux.org>; 0-clause BSD:
9090
crypt-yescrypt.c, test-crypt-yescrypt.c
9191

92+
* Copyright Daniel Dinu et al.; CC0 1.0 Universal/Apache 2.0:
93+
alg-argon2-encoding.c
94+
95+
* Copyright <ferivoz at riseup.net>; 0-clause BSD:
96+
crypt-argon2.c
97+
9298
* Copyright Kevin Cernekee; FSF All Permissive License:
9399
m4/ax_check_vscript.m4
94100

Makefile.am

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ nodist_noinst_HEADERS = \
6363
crypt-hashes.h \
6464
crypt-symbol-vers.h
6565
noinst_HEADERS = \
66+
lib/alg-argon2-encoding.h \
6667
lib/alg-des.h \
6768
lib/alg-gost3411-2012-const.h \
6869
lib/alg-gost3411-2012-core.h \
@@ -97,6 +98,7 @@ lib_LTLIBRARIES = \
9798
libcrypt.la
9899

99100
libcrypt_la_SOURCES = \
101+
lib/alg-argon2-encoding.c \
100102
lib/alg-des-tables.c \
101103
lib/alg-des.c \
102104
lib/alg-gost3411-2012-core.c \
@@ -109,6 +111,7 @@ libcrypt_la_SOURCES = \
109111
lib/alg-sha512.c \
110112
lib/alg-yescrypt-common.c \
111113
lib/alg-yescrypt-opt.c \
114+
lib/crypt-argon2.c \
112115
lib/crypt-bcrypt.c \
113116
lib/crypt-common.c \
114117
lib/crypt-des.c \

NEWS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ libxcrypt NEWS -- history of user-visible changes.
33
Please send bug reports, questions and suggestions to
44
<https://github.com/besser82/libxcrypt/issues>.
55

6-
Version 4.4.18
6+
Version 4.5
7+
* Support for the argon2 family of hashing algorithms added
8+
($argon2d$, $argon2i$, $argon2id$).
79

810
Version 4.4.17
911
* Fix compilation error in 'alignas (type)' with older versions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ README for libxcrypt
99

1010
libxcrypt is a modern library for one-way hashing of passwords. It
1111
supports a wide variety of both modern and historical hashing methods:
12-
yescrypt, gost-yescrypt, scrypt, bcrypt, sha512crypt, sha256crypt,
12+
argon2i, yescrypt, gost-yescrypt, scrypt, bcrypt, sha512crypt, sha256crypt,
1313
md5crypt, SunMD5, sha1crypt, NT, bsdicrypt, bigcrypt, and descrypt.
1414
It provides the traditional Unix `crypt` and `crypt_r` interfaces, as
1515
well as a set of extended interfaces pioneered by Openwall Linux,

TODO.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ It was last updated 20 October 2018.
3535
whether we can use these.
3636

3737
* Additional hashing methods
38-
* Argon2 <https://password-hashing.net/>
3938
* ...?
4039

4140
* Runtime configurability (in progress on the [crypt.conf branch][])

configure.ac

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Process this file with autoconf to produce a configure script.
22
m4_include([m4/zw_automodern.m4])
33
AC_INIT([xcrypt],
4-
[4.4.18],
4+
[4.5],
55
[https://github.com/besser82/libxcrypt/issues],
66
[libxcrypt],
77
[https://github.com/besser82/libxcrypt])
@@ -405,6 +405,14 @@ case "$hashes_enabled" in
405405
;;
406406
esac
407407

408+
# The argon2 hashes require libargon2.
409+
AS_CASE(["$hashes_enabled"],
410+
[*argon2*], [
411+
AC_SEARCH_LIBS([argon2_hash], [argon2])
412+
AS_IF([test x"$ac_cv_search_argon2_hash" = xno],
413+
[AC_MSG_ERROR([Argon2 hashes require libargon2, which was not found])])
414+
])
415+
408416
# If the obsolete APIs are disabled, the stubs implicitly disabled as well.
409417
if test x"$COMPAT_ABI" = xno && test x"$enable_obsolete_api_enosys" = x1; then
410418
AC_MSG_WARN(

doc/crypt.5

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,30 @@ The algorithm was specifically designed to make it costly to perform
189189
large-scale custom hardware attacks by requiring large amounts of memory.
190190
In 2016, the scrypt algorithm was published by IETF as RFC 7914.
191191
.hash "$7$" "\e$7\e$[./A-Za-z0-9]{11,97}\e$[./A-Za-z0-9]{43}" unlimited 8 256 256 "up to 512" "6 to 11 (logarithmic)"
192+
.Ss argon2_d
193+
Argon2d is a memory-hard function for password-hashing and proof-of-work
194+
applications. It aims at the highest memory filling rate and effective use
195+
of multiple computing units, while still providing defense against tradeoff
196+
attacks. Argon2d uses data-dependent memory access, which makes it suitable
197+
for cryptocurrencies and proof-of-work applications with no threats from
198+
side-channel timing attacks.
199+
.hash "$argon2d$" "\e$argon2i\e$v=[0-9]{2}\e$m=[0-9]{1,10},t=[0-9]{1,10},p=[0-9]{1,10}\e$[A-Za-z0-9/+]{11,86}$[A-Za-z0-9/+]{43}" unlimited 8 256 256 "64 to 512" "1 to 4,294,967,295"
200+
.Ss argon2_i
201+
argon2_i is a memory-hard function for password-hashing and proof-of-work
202+
applications. It aims at the highest memory filling rate and effective use
203+
of multiple computing units, while still providing defense against tradeoff
204+
attacks. Argon2i uses data-independent memory access, which is preferred
205+
for password hashing and password-based key derivation.
206+
.hash "$argon2i$" "\e$argon2i\e$v=[0-9]{2}\e$m=[0-9]{1,10},t=[0-9]{1,10},p=[0-9]{1,10}\e$[A-Za-z0-9/+]{11,86}$[A-Za-z0-9/+]{43}" unlimited 8 256 256 "64 to 512" "1 to 4,294,967,295"
207+
.Ss argon2_id
208+
Argon2id is a memory-hard function for password-hashing and proof-of-work
209+
applications. It aims at the highest memory filling rate and effective use
210+
of multiple computing units, while still providing defense against tradeoff
211+
attacks. Argon2id works as Argon2i for the first half of the first pass
212+
over the memory, and as Argon2d for the rest, thus providing both
213+
side-channel attack protection and brute-force cost savings due to
214+
time-memory tradeoffs.
215+
.hash "$argon2id$" "\e$argon2i\e$v=[0-9]{2}\e$m=[0-9]{1,10},t=[0-9]{1,10},p=[0-9]{1,10}\e$[A-Za-z0-9/+]{11,86}$[A-Za-z0-9/+]{43}" unlimited 8 256 256 "64 to 512" "1 to 4,294,967,295"
192216
.Ss bcrypt
193217
A hash based on the Blowfish block cipher,
194218
modified to have an extra-expensive key schedule.

lib/alg-argon2-encoding.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Copyright 2015
3+
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
4+
*
5+
* You may use this work under the terms of a Creative Commons CC0 1.0
6+
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
7+
* these licenses can be found at:
8+
*
9+
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
10+
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* You should have received a copy of both of these licenses along with this
13+
* software. If not, they may be obtained at the above URLs.
14+
*/
15+
16+
#include <argon2.h>
17+
18+
#include "alg-argon2-encoding.h"
19+
20+
/*
21+
* Some macros for constant-time comparisons. These work over values in
22+
* the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
23+
*/
24+
#define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
25+
#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
26+
#define GE(x, y) (GT(y, x) ^ 0xFF)
27+
#define LT(x, y) GT(y, x)
28+
#define LE(x, y) GE(y, x)
29+
30+
/*
31+
* Convert value x (0..63) to corresponding Base64 character.
32+
*/
33+
static unsigned b64_byte_to_char(unsigned x) {
34+
return (LT(x, 26) & (x + 'A')) |
35+
(GE(x, 26) & LT(x, 52) & (x + (unsigned)('a' - 26))) |
36+
(GE(x, 52) & LT(x, 62) & (x + (unsigned)('0' - 52))) | (EQ(x, 62) & '+') |
37+
(EQ(x, 63) & '/');
38+
}
39+
40+
/*
41+
* Convert character c to the corresponding 6-bit value. If character c
42+
* is not a Base64 character, then 0xFF (255) is returned.
43+
*/
44+
static unsigned b64_char_to_byte(int c) {
45+
unsigned x;
46+
47+
x = (GE(c, 'A') & LE(c, 'Z') & (unsigned)(c - 'A')) |
48+
(GE(c, 'a') & LE(c, 'z') & (unsigned)(c - ('a' - 26))) |
49+
(GE(c, '0') & LE(c, '9') & (unsigned)(c - ('0' - 52))) | (EQ(c, '+') & 62) |
50+
(EQ(c, '/') & 63);
51+
return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
52+
}
53+
54+
/*
55+
* Convert some bytes to Base64. 'dst_len' is the length (in characters)
56+
* of the output buffer 'dst'; if that buffer is not large enough to
57+
* receive the result (including the terminating 0), then (size_t)-1
58+
* is returned. Otherwise, the zero-terminated Base64 string is written
59+
* in the buffer, and the output length (counted WITHOUT the terminating
60+
* zero) is returned.
61+
*/
62+
size_t argon2_encode64(char *dst, size_t dst_len, const uint8_t *src,
63+
size_t src_len) {
64+
size_t olen;
65+
const unsigned char *buf;
66+
unsigned acc, acc_len;
67+
68+
olen = (src_len / 3) << 2;
69+
switch (src_len % 3) {
70+
case 2:
71+
olen++;
72+
/* fall through */
73+
case 1:
74+
olen += 2;
75+
break;
76+
}
77+
if (dst_len <= olen) {
78+
return (size_t)-1;
79+
}
80+
acc = 0;
81+
acc_len = 0;
82+
buf = (const unsigned char *)src;
83+
while (src_len-- > 0) {
84+
acc = (acc << 8) + (*buf++);
85+
acc_len += 8;
86+
while (acc_len >= 6) {
87+
acc_len -= 6;
88+
*dst++ = (char)b64_byte_to_char((acc >> acc_len) & 0x3F);
89+
}
90+
}
91+
if (acc_len > 0) {
92+
*dst++ = (char)b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
93+
}
94+
*dst++ = 0;
95+
return olen;
96+
}
97+
98+
/*
99+
* Decode Base64 chars into bytes. The '*dst_len' value must initially
100+
* contain the length of the output buffer '*dst'; when the decoding
101+
* ends, the actual number of decoded bytes is written back in
102+
* '*dst_len'.
103+
*
104+
* Decoding stops when a non-Base64 character is encountered, or when
105+
* the output buffer capacity is exceeded. If an error occurred (output
106+
* buffer is too small, invalid last characters leading to unprocessed
107+
* buffered bits), then NULL is returned; otherwise, the returned value
108+
* points to the first non-Base64 character in the source stream, which
109+
* may be the terminating zero.
110+
*/
111+
const char *argon2_decode64(uint8_t *dst, size_t *dst_len, const char *src) {
112+
size_t len;
113+
unsigned char *buf;
114+
unsigned acc, acc_len;
115+
116+
buf = (unsigned char *)dst;
117+
len = 0;
118+
acc = 0;
119+
acc_len = 0;
120+
for (;;) {
121+
unsigned d;
122+
123+
d = b64_char_to_byte(*src);
124+
if (d == 0xFF) {
125+
break;
126+
}
127+
src++;
128+
acc = (acc << 6) + d;
129+
acc_len += 6;
130+
if (acc_len >= 8) {
131+
acc_len -= 8;
132+
if ((len++) >= *dst_len) {
133+
return NULL;
134+
}
135+
*buf++ = (acc >> acc_len) & 0xFF;
136+
}
137+
}
138+
139+
/*
140+
* If the input length is equal to 1 modulo 4 (which is
141+
* invalid), then there will remain 6 unprocessed bits;
142+
* otherwise, only 0, 2 or 4 bits are buffered. The buffered
143+
* bits must also all be zero.
144+
*/
145+
if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {
146+
return NULL;
147+
}
148+
*dst_len = len;
149+
return src;
150+
}
151+

lib/alg-argon2-encoding.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2015
3+
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
4+
*
5+
* You may use this work under the terms of a Creative Commons CC0 1.0
6+
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
7+
* these licenses can be found at:
8+
*
9+
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
10+
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* You should have received a copy of both of these licenses along with this
13+
* software. If not, they may be obtained at the above URLs.
14+
*/
15+
16+
#ifndef ALG_ARGON2_ENCODING_H
17+
#define ALG_ARGON2_ENCODING_H
18+
19+
#include <stdint.h>
20+
21+
size_t argon2_encode64 (char *dst, size_t dst_len, const uint8_t *src,
22+
size_t src_len);
23+
const char *argon2_decode64 (uint8_t *dst, size_t *dst_len, const char *src);
24+
25+
#endif

0 commit comments

Comments
 (0)