1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 #include <string.h>
14 #include <xcrypt.h>
15 #include <sha1.h>
16 #include <base64.h>
17 
18 #include "menu.h"
19 
passwd_compare_sha1(const char * passwd,const char * entry)20 static int passwd_compare_sha1(const char *passwd, const char *entry)
21 {
22     struct {
23 	SHA1_CTX ctx;
24 	unsigned char sha1[20], pwdsha1[20];
25     } d;
26     const char *p;
27     int rv;
28 
29     SHA1Init(&d.ctx);
30 
31     if ((p = strchr(passwd + 3, '$'))) {
32 	SHA1Update(&d.ctx, (void *)passwd + 3, p - (passwd + 3));
33 	p++;
34     } else {
35 	p = passwd + 3;		/* Assume no salt */
36     }
37 
38     SHA1Update(&d.ctx, (void *)entry, strlen(entry));
39     SHA1Final(d.sha1, &d.ctx);
40 
41     memset(d.pwdsha1, 0, 20);
42     unbase64(d.pwdsha1, 20, p);
43 
44     rv = !memcmp(d.sha1, d.pwdsha1, 20);
45 
46     memset(&d, 0, sizeof d);
47     return rv;
48 }
49 
passwd_compare_md5(const char * passwd,const char * entry)50 static int passwd_compare_md5(const char *passwd, const char *entry)
51 {
52     const char *crypted = crypt_md5(entry, passwd + 3);
53     int len = strlen(crypted);
54 
55     return !strncmp(crypted, passwd, len) &&
56 	(passwd[len] == '\0' || passwd[len] == '$');
57 }
58 
passwd_compare_sha256(const char * passwd,const char * entry)59 static int passwd_compare_sha256(const char *passwd, const char *entry)
60 {
61     const char *crypted = sha256_crypt(entry, passwd + 3);
62     int len = strlen(crypted);
63 
64     return !strncmp(crypted, passwd, len) &&
65 	(passwd[len] == '\0' || passwd[len] == '$');
66 }
67 
passwd_compare_sha512(const char * passwd,const char * entry)68 static int passwd_compare_sha512(const char *passwd, const char *entry)
69 {
70     const char *crypted = sha512_crypt(entry, passwd + 3);
71     int len = strlen(crypted);
72 
73     return !strncmp(crypted, passwd, len) &&
74 	(passwd[len] == '\0' || passwd[len] == '$');
75 }
76 
passwd_compare(const char * passwd,const char * entry)77 int passwd_compare(const char *passwd, const char *entry)
78 {
79     if (passwd[0] != '$' || !passwd[1] || passwd[2] != '$') {
80 	/* Plaintext passwd, yuck! */
81 	return !strcmp(entry, passwd);
82     } else {
83 	switch (passwd[1]) {
84 	case '1':
85 	    return passwd_compare_md5(passwd, entry);
86 	case '4':
87 	    return passwd_compare_sha1(passwd, entry);
88 	case '5':
89 	    return passwd_compare_sha256(passwd, entry);
90 	case '6':
91 	    return passwd_compare_sha512(passwd, entry);
92 	default:
93 	    return 0;		/* Unknown encryption algorithm -> false */
94 	}
95     }
96 }
97