Merge branch 'upstream' into tizen
[platform/upstream/cryptsetup.git] / tests / unit-utils-crypt.c
1 /*
2  * cryptsetup crypto name and hex conversion helper test vectors
3  *
4  * Copyright (C) 2022-2023 Milan Broz
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "utils_crypt.h"
26 #include "libcryptsetup.h"
27
28 #ifndef ARRAY_SIZE
29 # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
30 #endif
31
32 /*
33  * Cryptsetup/dm-crypt algorithm naming conversion test
34  */
35 struct mode_test_vector {
36         const char *input;
37         const char *cipher;
38         const char *mode;
39         int keys;
40 };
41 static struct mode_test_vector mode_test_vectors[] = {
42         { "aes-xts-plain", "aes", "xts-plain", 1 },
43         { "aes-xts-plain64", "aes", "xts-plain64", 1 },
44         { "aes-cbc-plain", "aes", "cbc-plain", 1 },
45         { "aes-cbc-plain64", "aes", "cbc-plain64", 1 },
46         { "aes-cbc-essiv:sha256", "aes", "cbc-essiv:sha256", 1 },
47         { "aes", "aes", "cbc-plain", 1 },
48         { "twofish", "twofish", "cbc-plain", 1 },
49         { "cipher_null", "cipher_null", "ecb", 0 },
50         { "null", "cipher_null", "ecb", 0 },
51         { "xchacha12,aes-adiantum-plain64", "xchacha12,aes", "adiantum-plain64", 1 },
52         { "xchacha20,aes-adiantum-plain64", "xchacha20,aes", "adiantum-plain64", 1 },
53         { "aes:64-cbc-lmk", "aes:64", "cbc-lmk", 64 },
54         { "des3_ede-cbc-tcw", "des3_ede" ,"cbc-tcw", 1 },
55         { "aes-lrw-benbi", "aes","lrw-benbi", 1 },
56 };
57
58 static int test_parse_mode(void)
59 {
60         char cipher[MAX_CIPHER_LEN], mode[MAX_CIPHER_LEN];
61         unsigned int i;
62         int keys;
63
64         printf("MODECONV:");
65         for (i = 0; i < ARRAY_SIZE(mode_test_vectors); i++) {
66                 if (i && !(i % 8))
67                         printf("\n");
68                 keys = -1;
69                 memset(cipher, 0, sizeof(cipher));
70                 memset(mode, 0, sizeof(mode));
71                 printf("[%s]", mode_test_vectors[i].input ?: "NULL");
72                 if (crypt_parse_name_and_mode(mode_test_vectors[i].input, cipher, &keys, mode) < 0 ||
73                         strcmp(mode_test_vectors[i].cipher, cipher) ||
74                         strcmp(mode_test_vectors[i].mode, mode) ||
75                         mode_test_vectors[i].keys != keys) {
76                         printf("[FAILED (%s / %s / %i)]\n", cipher, mode, keys);
77                         return EXIT_FAILURE;
78                 }
79         }
80         printf("[OK]\n");
81
82         return EXIT_SUCCESS;
83 }
84
85 /*
86  * Cryptsetup/dm-crypt/dm-integrity algorithm naming conversion test
87  */
88 struct integrity_test_vector {
89         bool int_mode; /* non-null if it is supported as integrity mode for LUKS2 */
90         const char *input;
91         const char *integrity;
92         int key_size;
93 };
94 static struct integrity_test_vector integrity_test_vectors[] = {
95         { true, "aead", "aead", 0 },
96         { true, "poly1305", "poly1305", 0 },
97         { true, "none", "none", 0 },
98         { false, "crc32", "crc32", 0 },
99         { true, "hmac-sha1", "hmac(sha1)", 20 },
100         { true, "hmac-sha256", "hmac(sha256)", 32 },
101         { true, "hmac-sha512", "hmac(sha512)", 64 },
102         { true, "cmac-aes", "cmac(aes)", 16 },
103         { false, "blake2b-256", "blake2b-256", 0 },
104 };
105
106 static int test_parse_integrity_mode(void)
107 {
108         char integrity[MAX_CIPHER_LEN];
109         unsigned int i;
110         int key_size;
111
112         printf("INTEGRITYCONV:");
113         for (i = 0; i < ARRAY_SIZE(integrity_test_vectors); i++) {
114                 memset(integrity, 0, sizeof(integrity));
115                 printf("[%s,%i]", integrity_test_vectors[i].input ?: "NULL", integrity_test_vectors[i].key_size);
116                 if (crypt_parse_hash_integrity_mode(integrity_test_vectors[i].input, integrity) < 0 ||
117                         strcmp(integrity_test_vectors[i].integrity, integrity)) {
118                         printf("[FAILED (%s)]\n", integrity);
119                         return EXIT_FAILURE;
120                 }
121                 key_size = -1;
122                 memset(integrity, 0, sizeof(integrity));
123                 if (integrity_test_vectors[i].int_mode &&
124                     (crypt_parse_integrity_mode(integrity_test_vectors[i].input, integrity, &key_size) < 0 ||
125                         strcmp(integrity_test_vectors[i].integrity, integrity) ||
126                         integrity_test_vectors[i].key_size != key_size)) {
127                         printf("[FAILED (%s / %i)]\n", integrity, key_size);
128                         return EXIT_FAILURE;
129                 }
130         }
131         printf("[OK]\n");
132
133         return EXIT_SUCCESS;
134 }
135
136 /*
137  * Cryptsetup null cipher bypass algorithm name
138  */
139 struct null_test_vector {
140         const char *cipher;
141         bool ok;
142 };
143 static struct null_test_vector null_test_vectors[] = {
144         { "cipher_null-ecb", true },
145         { "cipher_null", true },
146         { "null", true },
147         { "cipher-null", false },
148         { "aes-ecb", false },
149         { NULL, false },
150 };
151
152 static int test_cipher_null(void)
153 {
154         unsigned int i;
155
156         printf("NULLCONV:");
157         for (i = 0; i < ARRAY_SIZE(null_test_vectors); i++) {
158                 printf("[%s]", null_test_vectors[i].cipher ?: "NULL");
159                 if (crypt_is_cipher_null(null_test_vectors[i].cipher) !=
160                         null_test_vectors[i].ok) {
161                         printf("[FAILED]\n");
162                         return EXIT_FAILURE;
163                 }
164         }
165         printf("[OK]\n");
166
167         return EXIT_SUCCESS;
168 }
169
170 struct hex_test_vector {
171         const char *hex;
172         const char *bytes;
173         ssize_t bytes_size;
174         bool ok;
175 };
176 static struct hex_test_vector hex_test_vectors[] = {
177         { "0000000000000000", "\x00\x00\x00\x00\x00\x00\x00\x00", 8, true },
178         { "abcdef0123456789", "\xab\xcd\xef\x01\x23\x45\x67\x89", 8, true },
179         { "aBCDef0123456789", "\xab\xcd\xef\x01\x23\x45\x67\x89", 8, true },
180         { "ff", "\xff", 1, true },
181         { "f", NULL , 1, false },
182         { "a-cde", NULL, 2, false },
183         { "FAKE", NULL, 2, false },
184         { "\x01\x02\xff", NULL, 3, false },
185         { NULL, NULL, 1, false },
186         { "fff", NULL, 2, false },
187         { "fg", NULL, 1, false },
188 };
189
190 /*
191  * Hexa conversion test (also should be constant time)
192  */
193 static int test_hex_conversion(void)
194 {
195         char *bytes, *hex;
196         ssize_t len;
197         unsigned int i;
198
199         printf("HEXCONV:");
200         for (i = 0; i < ARRAY_SIZE(hex_test_vectors); i++) {
201                 bytes = NULL;
202                 hex = NULL;
203                 if (hex_test_vectors[i].hex && *hex_test_vectors[i].hex >= '0')
204                         printf("[%s]", hex_test_vectors[i].hex);
205                 else
206                         printf("[INV:%i]", i);
207                 len = crypt_hex_to_bytes(hex_test_vectors[i].hex, &bytes, 1);
208                 if ((hex_test_vectors[i].ok && len != hex_test_vectors[i].bytes_size) ||
209                    (!hex_test_vectors[i].ok && len >= 0)) {
210                         printf("[FAILED]\n");
211                         crypt_safe_free(bytes);
212                         return EXIT_FAILURE;
213                 }
214                 crypt_safe_free(bytes);
215                 hex = crypt_bytes_to_hex(hex_test_vectors[i].bytes_size, hex_test_vectors[i].bytes);
216                 if ((hex_test_vectors[i].ok && strcasecmp(hex, hex_test_vectors[i].hex)) ||
217                    (!hex_test_vectors[i].ok && hex)) {
218                         printf("[FAILED]\n");
219                         crypt_safe_free(hex);
220                         return EXIT_FAILURE;
221                 }
222                 crypt_safe_free(hex);
223         }
224         printf("[OK]\n");
225
226         return EXIT_SUCCESS;
227 }
228
229 static void __attribute__((noreturn)) exit_test(const char *msg, int r)
230 {
231         if (msg)
232                 printf("%s\n", msg);
233         exit(r);
234 }
235
236 int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[])
237 {
238         setvbuf(stdout, NULL, _IONBF, 0);
239
240 #ifndef NO_CRYPTSETUP_PATH
241         if (getenv("CRYPTSETUP_PATH")) {
242                 printf("Cannot run this test with CRYPTSETUP_PATH set.\n");
243                 exit(77);
244         }
245 #endif
246         if (test_parse_mode())
247                 exit_test("Parse mode test failed.", EXIT_FAILURE);
248
249         if (test_parse_integrity_mode())
250                 exit_test("Parse integrity mode test failed.", EXIT_FAILURE);
251
252         if (test_cipher_null())
253                 exit_test("CIPHER null test failed.", EXIT_FAILURE);
254
255         if (test_hex_conversion())
256                 exit_test("HEX conversion test failed.", EXIT_FAILURE);
257
258         exit_test(NULL, EXIT_SUCCESS);
259 }