19a62e224be77203ecc4ad9b77d92d81d7520583
[platform/upstream/cryptsetup.git] / crypt_plain.c
1 /*
2  * cryptsetup plain device helper functions
3  *
4  * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
5  * Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <string.h>
22 #include <stdlib.h>
23 #include <errno.h>
24
25 #include "internal.h"
26 #include "crypto_backend.h"
27
28 static int hash(const char *hash_name, size_t key_size, char *key,
29                 size_t passphrase_size, const char *passphrase)
30 {
31         struct crypt_hash *md = NULL;
32         size_t len;
33         int round, i, r = 0;
34
35         if (crypt_hash_init(&md, hash_name))
36                 return -ENOENT;
37
38         len = crypt_hash_size(hash_name);
39
40         for(round = 0; key_size && !r; round++) {
41                 /* hack from hashalot to avoid null bytes in key */
42                 for(i = 0; i < round; i++)
43                         if (crypt_hash_write(md, "A", 1))
44                                 r = 1;
45
46                 if (crypt_hash_write(md, passphrase, passphrase_size))
47                         r = 1;
48
49                 if (len > key_size)
50                         len = key_size;
51
52                 if (crypt_hash_final(md, key, len))
53                         r = 1;
54
55                 key += len;
56                 key_size -= len;
57         }
58
59         crypt_hash_destroy(md);
60         return r;
61 }
62
63 #define PLAIN_HASH_LEN_MAX 256
64
65 int crypt_plain_hash(struct crypt_device *ctx __attribute__((unused)),
66                      const char *hash_name,
67                      char *key, size_t key_size,
68                      const char *passphrase, size_t passphrase_size)
69 {
70         char hash_name_buf[PLAIN_HASH_LEN_MAX], *s;
71         size_t hash_size, pad_size;
72         int r;
73
74         log_dbg("Plain: hashing passphrase using %s.", hash_name);
75
76         if (strlen(hash_name) >= PLAIN_HASH_LEN_MAX)
77                 return -EINVAL;
78         strncpy(hash_name_buf, hash_name, PLAIN_HASH_LEN_MAX);
79         hash_name_buf[PLAIN_HASH_LEN_MAX - 1] = '\0';
80
81         /* hash[:hash_length] */
82         if ((s = strchr(hash_name_buf, ':'))) {
83                 *s = '\0';
84                 hash_size = atoi(++s);
85                 if (hash_size > key_size) {
86                         log_dbg("Hash length %zd > key length %zd",
87                                 hash_size, key_size);
88                         return -EINVAL;
89                 }
90                 pad_size = key_size - hash_size;
91         } else {
92                 hash_size = key_size;
93                 pad_size = 0;
94         }
95
96         r = hash(hash_name_buf, hash_size, key, passphrase_size, passphrase);
97
98         if (r == 0 && pad_size)
99                 memset(key + hash_size, 0, pad_size);
100
101         return r;
102 }