/src/cryptsetup/lib/crypt_plain.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * cryptsetup plain device helper functions |
4 | | * |
5 | | * Copyright (C) 2004 Jana Saout <jana@saout.de> |
6 | | * Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved. |
7 | | * Copyright (C) 2010-2025 Milan Broz |
8 | | */ |
9 | | |
10 | | #include <string.h> |
11 | | #include <stdio.h> |
12 | | #include <errno.h> |
13 | | |
14 | | #include "libcryptsetup.h" |
15 | | #include "internal.h" |
16 | | |
17 | | static int hash(const char *hash_name, size_t key_size, char *key, |
18 | | size_t passphrase_size, const char *passphrase) |
19 | 0 | { |
20 | 0 | struct crypt_hash *md = NULL; |
21 | 0 | size_t len; |
22 | 0 | int round, i, r = 0; |
23 | |
|
24 | 0 | if (crypt_hash_init(&md, hash_name)) |
25 | 0 | return -ENOENT; |
26 | | |
27 | 0 | len = crypt_hash_size(hash_name); |
28 | |
|
29 | 0 | for(round = 0; key_size && !r; round++) { |
30 | | /* hack from hashalot to avoid null bytes in key */ |
31 | 0 | for(i = 0; i < round; i++) |
32 | 0 | if (crypt_hash_write(md, "A", 1)) |
33 | 0 | r = 1; |
34 | |
|
35 | 0 | if (crypt_hash_write(md, passphrase, passphrase_size)) |
36 | 0 | r = 1; |
37 | |
|
38 | 0 | if (len > key_size) |
39 | 0 | len = key_size; |
40 | |
|
41 | 0 | if (crypt_hash_final(md, key, len)) |
42 | 0 | r = 1; |
43 | |
|
44 | 0 | key += len; |
45 | 0 | key_size -= len; |
46 | 0 | } |
47 | |
|
48 | 0 | crypt_hash_destroy(md); |
49 | 0 | return r; |
50 | 0 | } |
51 | | |
52 | 0 | #define PLAIN_HASH_LEN_MAX 256 |
53 | | |
54 | | int crypt_plain_hash(struct crypt_device *cd, |
55 | | const char *hash_name, |
56 | | char *key, size_t key_size, |
57 | | const char *passphrase, size_t passphrase_size) |
58 | 0 | { |
59 | 0 | char hash_name_buf[PLAIN_HASH_LEN_MAX], *s; |
60 | 0 | size_t hash_size, pad_size; |
61 | 0 | int r; |
62 | |
|
63 | 0 | log_dbg(cd, "Plain: hashing passphrase using %s.", hash_name); |
64 | |
|
65 | 0 | if (strlen(hash_name) >= PLAIN_HASH_LEN_MAX) |
66 | 0 | return -EINVAL; |
67 | 0 | strncpy(hash_name_buf, hash_name, PLAIN_HASH_LEN_MAX); |
68 | 0 | hash_name_buf[PLAIN_HASH_LEN_MAX - 1] = '\0'; |
69 | | |
70 | | /* hash[:hash_length] */ |
71 | 0 | if ((s = strchr(hash_name_buf, ':'))) { |
72 | 0 | *s = '\0'; |
73 | 0 | s++; |
74 | 0 | if (!*s || sscanf(s, "%zd", &hash_size) != 1) { |
75 | 0 | log_dbg(cd, "Hash length is not a number"); |
76 | 0 | return -EINVAL; |
77 | 0 | } |
78 | 0 | if (hash_size > key_size) { |
79 | 0 | log_dbg(cd, "Hash length %zd > key length %zd", |
80 | 0 | hash_size, key_size); |
81 | 0 | return -EINVAL; |
82 | 0 | } |
83 | 0 | pad_size = key_size - hash_size; |
84 | 0 | } else { |
85 | 0 | hash_size = key_size; |
86 | 0 | pad_size = 0; |
87 | 0 | } |
88 | | |
89 | | /* No hash, copy passphrase directly */ |
90 | 0 | if (!strcmp(hash_name_buf, "plain")) { |
91 | 0 | if (passphrase_size < hash_size) { |
92 | 0 | log_dbg(cd, "Too short plain passphrase."); |
93 | 0 | return -EINVAL; |
94 | 0 | } |
95 | 0 | crypt_safe_memcpy(key, passphrase, hash_size); |
96 | 0 | r = 0; |
97 | 0 | } else |
98 | 0 | r = hash(hash_name_buf, hash_size, key, passphrase_size, passphrase); |
99 | | |
100 | 0 | if (r == 0 && pad_size) |
101 | 0 | memset(key + hash_size, 0, pad_size); |
102 | |
|
103 | 0 | return r; |
104 | 0 | } |