aboutsummaryrefslogtreecommitdiffstats
path: root/librecrypt_verify.c
blob: 990f37e5a04796b25f5243a4a624a4be16a2c9ab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST


int
librecrypt_verify(const char *phrase, size_t len, const char *settings, void *reserved)
{
	char *hash = NULL;
	size_t size = 0u;
	size_t off;
	ssize_t n;
	int ret, err;

	/* Measure base64 hash size */
	n = librecrypt_hash_(NULL, 0u, phrase, len, settings, reserved, ASCII_HASH);
	if (n < 0) {
		if (errno == EOVERFLOW)
			errno = ENOMEM; /* $covered$ (on 32-bit) */
		return -1;
	}

	/* Get position of hash in `settings` */
	off = librecrypt_settings_prefix(settings, NULL, reserved);
	if (settings[off] == '*') {
		if ('0' <= settings[off + 1u] && settings[off + 1u] <= '9') {
			errno = EINVAL;
			return -1;
		}
	} else if (!settings[off]) {
		errno = EINVAL;
		return -1;
	}

	/* Allocate hash output buffer for comparsion */
	size = (size_t)n + 128u; /* a little extra so the hasher don't need to allocate output scratch */
	hash = malloc(size);
	if (!hash)
		return -1;

	/* Calculate password hash and encode to base64 */
	n = librecrypt_hash_(hash, size, phrase, len, settings, reserved, ASCII_HASH);
	if (n < 0) {
		err = errno;
		librecrypt_wipe(hash, size);
		free(hash);
		if (err == EOVERFLOW)
			err = ENOMEM; /* $covered$ (impossible) */
		errno = err;
		return -1;
	}
	if ((size_t)n > size)
		abort(); /* $covered$ (impossible) */

	/* Compare hash */
	ret = librecrypt_equal(hash, &settings[off]);

	librecrypt_wipe(hash, size);
	free(hash);
	return ret;
}


#else


int
main(void)
{
	char conf[256];
	int r;

	SET_UP_ALARM();
	INIT_RESOURCE_TEST();

	errno = 0;
	EXPECT(librecrypt_verify(NULL, 0u, "$~no~such~algorithm~$", NULL) == -1);
	EXPECT(errno == ENOSYS);

#if defined(SUPPORT_ARGON2ID)
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL) == 1);
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/", NULL) == 0);
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4x", NULL) == 0);
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/a", NULL) == 0);
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$a29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/a", NULL) == 0);
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$af65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL) == 0);
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMRauIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL) == 0);

	errno = 0;
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$", NULL) == -1);
	EXPECT(errno == EINVAL);
	errno = 0;
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$*64", NULL) == -1);
	EXPECT(errno == EINVAL);
	errno = 0;
	EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$*16$nf65EOgLrQMRauIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL) == -1);
	EXPECT(errno == EINVAL);

	if (libtest_have_custom_malloc()) {
		libtest_set_alloc_failure_in(1u);
		errno = 0;
		EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL) == -1);
		assert(errno == ENOMEM);
		assert(libtest_get_alloc_failure_in() == 0u);

		libtest_set_alloc_failure_in(2u);
		errno = 0;
		EXPECT(librecrypt_verify("password", 8u, "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4", NULL) == -1);
		assert(errno == ENOMEM);
		assert(libtest_get_alloc_failure_in() == 0u);
	}

        r = snprintf(conf, sizeof(conf), "$argon2id$m=256,t=8,p=1$AAAABBBBCCCC$*%zu", SIZE_MAX / 4u * 3u + 3u);
        assert(r > 0 && (size_t)r < sizeof(conf));
        errno = 0;
	EXPECT(librecrypt_verify(NULL, 0u, conf, NULL) == -1);
# if SIZE_MAX > UINT32_MAX
        EXPECT(errno == EINVAL);
# else
        EXPECT(errno == EOVERFLOW);
# endif
#endif

	STOP_RESOURCE_TEST();
	return 0;
}


#endif