summaryrefslogtreecommitdiff
path: root/crypto_scrypt-check.c
blob: 5ed7ab0aac2673d26d74a887d195860c43e3400c (plain)
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
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

#include "b64.h"
#include "slowequals.h"
#include "libscrypt.h"

#ifdef _WIN32
/* On windows, strtok uses a thread-local static variable in strtok to
 * make strtok thread-safe.  It also neglects to provide a strtok_r. */
#define strtok_r(str, val, saveptr) strtok((str), (val))
#endif

/* pow() works with doubles. Sounds like it should cast to int correctly,
* but doesn't always. This is faster anyway
*/
static uint16_t ipow(uint16_t base, uint32_t exp)
{
    uint16_t result = 1;
    while (exp != 0)
    {
        if ((exp & 1) != 0)
            result *= base;
        exp >>= 1;
        base *= base;
    }

    return result;
}

int libscrypt_check(char *mcf, const char *password)
{
	/* Return values:
	* <0 error
	* == 0 password incorrect
	* >0 correct password
	*/

#ifndef _WIN32
	char *saveptr = NULL;
#endif
	uint32_t params;
	uint64_t N;
	uint8_t r, p;
	int retval;
	uint8_t hashbuf[64];
	char outbuf[128];
	uint8_t salt[32];
	char *tok;

	if(memcmp(mcf, SCRYPT_MCF_ID, 3) != 0)
	{
		/* Only version 0 supported */
		return -1;
	}

	tok = strtok_r(mcf, "$", &saveptr);
	if ( !tok )
		return -1;

	tok = strtok_r(NULL, "$", &saveptr);

	if ( !tok )
		return -1;

	params = (uint32_t)strtoul(tok, NULL, 16);
	if ( params == 0 )
		return -1;

	tok = strtok_r(NULL, "$", &saveptr);

	if ( !tok )
		return -1;

	p = params & 0xff;
	r = (params >> 8) & 0xff;
	N = params >> 16;

	if (N > SCRYPT_SAFE_N)
		return -1;

	N = ipow(2, N);

	/* Useful debugging:
	printf("We've obtained salt 'N' r p of '%s' %d %d %d\n", tok, N,r,p);
	*/

	memset(salt, 0, sizeof(salt)); /* Keeps splint happy */
	retval = libscrypt_b64_decode(tok, (unsigned char*)salt, sizeof(salt));
	if (retval < 1)
		return -1;

	retval = libscrypt_scrypt((uint8_t*)password, strlen(password), salt,
            (uint32_t)retval, N, r, p, hashbuf, sizeof(hashbuf));

	if (retval != 0)
		return retval;

	retval = libscrypt_b64_encode((unsigned char*)hashbuf, sizeof(hashbuf), 
            outbuf, sizeof(outbuf));

	if (retval == 0)
		return -1;

	tok = strtok_r(NULL, "$", &saveptr);

	if ( !tok )
		return -1;

	if(slow_equals(tok, outbuf) == 0)
	{
		return 0;
	}

	return 1; /* This is the "else" condition */
}