Allow manipulate with device with only header on it (no data).
[platform/upstream/cryptsetup.git] / lib / backends.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <errno.h>
5
6 #include "libcryptsetup.h"
7 #include "internal.h"
8
9 extern struct hash_backend hash_gcrypt_backend;
10
11 static struct hash_backend *hash_backends[] = {
12         &hash_gcrypt_backend,
13         NULL
14 };
15
16 struct hash_backend *get_hash_backend(const char *name)
17 {
18         struct hash_backend **backend;
19
20         for(backend = hash_backends; *backend; backend++)
21                 if (!name || strcmp(name, (*backend)->name) == 0)
22                         break;
23
24         return *backend;
25 }
26
27 void put_hash_backend(struct hash_backend *backend)
28 {
29 }
30
31 int hash(const char *backend_name, const char *hash_name,
32          char *result, size_t size,
33          const char *passphrase, size_t sizep)
34 {
35         struct hash_backend *backend;
36         struct hash_type *hashes = NULL, *hash;
37         char hash_name_buf[256], *s;
38         size_t pad = 0;
39         int r = -ENOENT;
40
41         if (strlen(hash_name) >= sizeof(hash_name_buf)) {
42                 set_error("hash name too long: %s", hash_name);
43                 return -ENAMETOOLONG;
44         }
45
46         if ((s = strchr(hash_name, ':'))) {
47                 size_t hlen;
48                 strcpy(hash_name_buf, hash_name);
49                 hash_name_buf[s-hash_name] = '\0';
50                 hash_name = hash_name_buf;
51                 hlen = atoi(++s);
52                 if (hlen > size) {
53                         set_error("requested hash length (%zd) > key length (%zd)", hlen, size);
54                         return -EINVAL;
55                 }
56                 pad = size-hlen;
57                 size = hlen;
58         }
59
60         backend = get_hash_backend(backend_name);
61         if (!backend) {
62                 set_error("No hash backend found");
63                 return -ENOSYS;
64         }
65
66         hashes = backend->get_hashes();
67         if (!hashes) {
68                 set_error("No hash functions available");
69                 goto out;
70         }
71
72         for(hash = hashes; hash->name; hash++)
73                 if (strcmp(hash->name, hash_name) == 0)
74                         break;
75         if (!hash->name) {
76                 set_error("Unknown hash type %s", hash_name);
77                 goto out;
78         }
79
80         r = hash->fn(hash->private, size, result, sizep, passphrase);
81         if (r < 0) {
82                 set_error("Error hashing passphrase");
83                 goto out;
84         }
85
86         if (pad) {
87                 memset(result+size, 0, pad);
88         }
89
90 out:
91         if (hashes)
92                 backend->free_hashes(hashes);
93         put_hash_backend(backend);
94
95         return r;
96 }