2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
5 * GRUB 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, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/auth.h>
20 #include <grub/crypto.h>
21 #include <grub/list.h>
23 #include <grub/misc.h>
25 #include <grub/normal.h>
27 #include <grub/i18n.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 static grub_dl_t my_mod
;
33 struct pbkdf2_password
38 grub_uint8_t
*expected
;
43 check_password (const char *user
, const char *entered
, void *pin
)
46 struct pbkdf2_password
*pass
= pin
;
49 buf
= grub_malloc (pass
->buflen
);
51 return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY
);
53 err
= grub_crypto_pbkdf2 (GRUB_MD_SHA512
, (grub_uint8_t
*) entered
,
54 grub_strlen (entered
),
55 pass
->salt
, pass
->saltlen
, pass
->c
,
60 return grub_crypto_gcry_error (err
);
63 if (grub_crypto_memcmp (buf
, pass
->expected
, pass
->buflen
) != 0)
64 return GRUB_ACCESS_DENIED
;
66 grub_auth_authenticate (user
);
74 if ('0' <= hex
&& hex
<= '9')
76 if ('a' <= hex
&& hex
<= 'f')
77 return hex
- 'a' + 10;
78 if ('A' <= hex
&& hex
<= 'F')
79 return hex
- 'A' + 10;
84 grub_cmd_password (grub_command_t cmd
__attribute__ ((unused
)),
85 int argc
, char **args
)
90 struct pbkdf2_password
*pass
;
93 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("two arguments expected"));
95 if (grub_memcmp (args
[1], "grub.pbkdf2.sha512.",
96 sizeof ("grub.pbkdf2.sha512.") - 1) != 0)
97 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("invalid PBKDF2 password"));
99 ptr
= args
[1] + sizeof ("grub.pbkdf2.sha512.") - 1;
101 pass
= grub_malloc (sizeof (*pass
));
105 pass
->c
= grub_strtoul (ptr
, &ptr
, 0);
111 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("invalid PBKDF2 password"));
115 ptr2
= grub_strchr (ptr
, '.');
116 if (!ptr2
|| ((ptr2
- ptr
) & 1) || grub_strlen (ptr2
+ 1) & 1)
119 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("invalid PBKDF2 password"));
122 pass
->saltlen
= (ptr2
- ptr
) >> 1;
123 pass
->buflen
= grub_strlen (ptr2
+ 1) >> 1;
124 ptro
= pass
->salt
= grub_malloc (pass
->saltlen
);
133 hex1
= hex2val (*ptr
);
135 hex2
= hex2val (*ptr
);
137 if (hex1
< 0 || hex2
< 0)
139 grub_free (pass
->salt
);
141 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
142 /* TRANSLATORS: it means that the string which
143 was supposed to be a password hash doesn't
144 have a correct format, not to password
146 N_("invalid PBKDF2 password"));
149 *ptro
= (hex1
<< 4) | hex2
;
153 ptro
= pass
->expected
= grub_malloc (pass
->buflen
);
156 grub_free (pass
->salt
);
161 ptr2
+= grub_strlen (ptr2
);
165 hex1
= hex2val (*ptr
);
167 hex2
= hex2val (*ptr
);
169 if (hex1
< 0 || hex2
< 0)
171 grub_free (pass
->expected
);
172 grub_free (pass
->salt
);
174 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
175 N_("invalid PBKDF2 password"));
178 *ptro
= (hex1
<< 4) | hex2
;
182 err
= grub_auth_register_authentication (args
[0], check_password
, pass
);
188 grub_dl_ref (my_mod
);
189 return GRUB_ERR_NONE
;
192 static grub_command_t cmd
;
194 GRUB_MOD_INIT(password_pbkdf2
)
197 cmd
= grub_register_command ("password_pbkdf2", grub_cmd_password
,
198 N_("USER PBKDF2_PASSWORD"),
199 N_("Set user password (PBKDF2). "));
202 GRUB_MOD_FINI(password_pbkdf2
)
204 grub_unregister_command (cmd
);