630f18f7667822a2df350d06c6ddc5475575a6fe
[platform/upstream/cryptsetup.git] / lib / gcrypt.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <errno.h>
5 #include <gcrypt.h>
6
7 #include "libcryptsetup.h"
8 #include "internal.h"
9
10 #define MAX_DIGESTS             64
11 #define GCRYPT_REQ_VERSION      "1.1.42"
12
13 int init_crypto(void)
14 {
15         if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
16                 if (!gcry_check_version (GCRYPT_REQ_VERSION))
17                         return -ENOSYS;
18                 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
19                 gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
20                 gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
21                 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
22         }
23
24         return 0;
25 }
26
27 static int gcrypt_hash(void *data, int size, char *key,
28                        int sizep, const char *passphrase)
29 {
30         gcry_md_hd_t md;
31         int algo = *((int *)data);
32         int len = gcry_md_get_algo_dlen(algo);
33         int round, i;
34
35         if (gcry_md_open(&md, algo, 0))
36                 return -1;
37
38         for(round = 0; size; round++) {
39                 /* hack from hashalot to avoid null bytes in key */
40                 for(i = 0; i < round; i++)
41                         gcry_md_write(md, "A", 1);
42
43                 gcry_md_write(md, passphrase, sizep);
44
45                 if (len > size)
46                         len = size;
47                 memcpy(key, gcry_md_read(md, algo), len);
48
49                 key += len;
50                 size -= len;
51                 if (size)
52                         gcry_md_reset(md);
53         }
54
55         gcry_md_close(md);
56         return 0;
57 }
58
59 static struct hash_type *gcrypt_get_hashes(void)
60 {
61         struct hash_type *hashes;
62         int size = MAX_DIGESTS;
63         int *list;
64         int i;
65         gcry_error_t r;
66
67         if (!gcry_check_version(GCRYPT_REQ_VERSION))
68                 return NULL;
69
70         list = (int *)malloc(sizeof(*list) * size);
71         if (!list)
72                 return NULL;
73
74         r = gcry_md_list(list, &size);
75         if (r || !size) {
76                 free(list);
77                 return NULL;
78         }
79
80         hashes = malloc(sizeof(*hashes) * (size + 1));
81         if (!hashes) {
82                 free(list);
83                 return NULL;
84         }
85
86         for(i = 0; i < size; i++) {
87                 hashes[i].name = NULL;
88                 hashes[i].private = NULL;
89         }
90
91         for(i = 0; i < size; i++) {
92                 char *p;
93
94                 hashes[i].name = strdup(gcry_md_algo_name(list[i]));
95                 if(!hashes[i].name)
96                         goto err;
97                 for(p = (char *)hashes[i].name; *p; p++)
98                         *p = tolower(*p);
99                 hashes[i].private = malloc(sizeof(int));
100                 if(!hashes[i].private)
101                         goto err;
102                 *((int *)hashes[i].private) = list[i];
103                 hashes[i].fn = gcrypt_hash;
104         }
105         hashes[i].name = NULL;
106         hashes[i].private = NULL;
107         hashes[i].fn = NULL;
108
109         free(list);
110
111         return hashes;
112
113 err:
114         free(list);
115         for(i = 0; i < size; i++) {
116                 free(hashes[i].name);
117                 free(hashes[i].private);
118         }
119         free(hashes);
120         return NULL;
121 }
122
123 static void gcrypt_free_hashes(struct hash_type *hashes)
124 {
125         struct hash_type *hash;
126
127         for(hash = hashes; hash->name; hash++) {
128                 free(hash->name);
129                 free(hash->private);
130         }
131
132         free(hashes);
133 }
134
135 struct hash_backend hash_gcrypt_backend = {
136         .name = "libgcrypt",
137         .get_hashes = gcrypt_get_hashes,
138         .free_hashes = gcrypt_free_hashes
139 };