File: chkhash.c

package info (click to toggle)
shadow 1%3A4.19.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 67,276 kB
  • sloc: sh: 44,701; ansic: 34,184; xml: 12,350; exp: 3,691; makefile: 1,656; python: 1,409; perl: 120; sed: 16
file content (82 lines) | stat: -rw-r--r-- 1,901 bytes parent folder | download
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
#include "config.h"

#include "chkhash.h"

#include <regex.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>

#include "string/strcmp/streq.h"
#include "string/strcmp/strprefix.h"


/*
 * match_regex - return true if match, false if not
 */
bool 
match_regex(const char *pattern, const char *string) 
{
	regex_t regex;
	int result;

	if (regcomp(&regex, pattern, REG_EXTENDED) != 0)
		return false;

	result = regexec(&regex, string, 0, NULL, 0);
	regfree(&regex);

	return result == 0;
}


/*
 * is_valid_hash - check if the given string is a valid password hash
 *
 * Returns true if the string appears to be a valid hash, false otherwise.
 *
 * regex from: https://man.archlinux.org/man/crypt.5.en
 */
bool 
is_valid_hash(const char *hash) 
{
	hash = strprefix(hash, "!") ?: hash;

	// Passwordless account; discouraged
	if (streq(hash, ""))
		return true;

	if (streq(hash, "*"))
		return true;

	// Minimum hash length
	if (strlen(hash) < 13)
		return false;

	// Yescrypt: $y$ + algorithm parameters + $ + salt + $ + 43-char (minimum) hash
	if (match_regex("^\\$y\\$[./A-Za-z0-9]+\\$[./A-Za-z0-9]{1,86}\\$[./A-Za-z0-9]{43}$", hash))
		return true;

	// Bcrypt: $2[abxy]$ + 2-digit cost + $ + 53-char hash
	if (match_regex("^\\$2[abxy]\\$[0-9]{2}\\$[./A-Za-z0-9]{53}$", hash))
		return true;

	// SHA-512: $6$ + salt + $ + 86-char hash
	if (match_regex("^\\$6\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\n]{1,16}\\$[./A-Za-z0-9]{86}$", hash))
		return true;

	// SHA-256: $5$ + salt + $ + 43-char hash
	if (match_regex("^\\$5\\$(rounds=[1-9][0-9]{3,8}\\$)?[^$:\n]{1,16}\\$[./A-Za-z0-9]{43}$", hash))
		return true;

	// MD5: $1$ + salt + $ + 22-char hash
	if (match_regex("^\\$1\\$[^$:\n]{1,8}\\$[./A-Za-z0-9]{22}$", hash))
		return true;

	// DES: exactly 13 characters from [A-Za-z0-9./]
	if (match_regex("^[./A-Za-z0-9]{13}$", hash))
		return true;

	// Not a valid hash
	return false;
}