]>
Commit | Line | Data |
---|---|---|
7d969014 DB |
1 | /* |
2 | * QEMU Crypto block device encryption QCow/QCow2 AES-CBC format | |
3 | * | |
4 | * Copyright (c) 2015-2016 Red Hat, Inc. | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
b7cbb874 | 9 | * version 2.1 of the License, or (at your option) any later version. |
7d969014 DB |
10 | * |
11 | * This library 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 GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | * | |
19 | */ | |
20 | ||
21 | /* | |
22 | * Note that the block encryption implemented in this file is broken | |
23 | * by design. This exists only to allow data to be liberated from | |
24 | * existing qcow[2] images and should not be used in any new areas. | |
25 | */ | |
26 | ||
27 | #include "qemu/osdep.h" | |
da34e65c | 28 | #include "qapi/error.h" |
7d969014 | 29 | |
986bc8de | 30 | #include "block-qcow.h" |
7d969014 DB |
31 | #include "crypto/secret.h" |
32 | ||
33 | #define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512 | |
34 | ||
35 | ||
36 | static bool | |
37 | qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED, | |
38 | size_t buf_size G_GNUC_UNUSED) | |
39 | { | |
40 | return false; | |
41 | } | |
42 | ||
43 | ||
44 | static int | |
45 | qcrypto_block_qcow_init(QCryptoBlock *block, | |
46 | const char *keysecret, | |
c972fa12 | 47 | size_t n_threads, |
7d969014 DB |
48 | Error **errp) |
49 | { | |
50 | char *password; | |
51 | int ret; | |
52 | uint8_t keybuf[16]; | |
53 | int len; | |
54 | ||
55 | memset(keybuf, 0, 16); | |
56 | ||
57 | password = qcrypto_secret_lookup_as_utf8(keysecret, errp); | |
58 | if (!password) { | |
59 | return -1; | |
60 | } | |
61 | ||
62 | len = strlen(password); | |
63 | memcpy(keybuf, password, MIN(len, sizeof(keybuf))); | |
64 | g_free(password); | |
65 | ||
66 | block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128, | |
67 | QCRYPTO_CIPHER_MODE_CBC); | |
68 | block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64, | |
69 | 0, 0, NULL, 0, errp); | |
70 | if (!block->ivgen) { | |
71 | ret = -ENOTSUP; | |
72 | goto fail; | |
73 | } | |
74 | ||
c972fa12 VSO |
75 | ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALG_AES_128, |
76 | QCRYPTO_CIPHER_MODE_CBC, | |
77 | keybuf, G_N_ELEMENTS(keybuf), | |
78 | n_threads, errp); | |
79 | if (ret < 0) { | |
7d969014 DB |
80 | ret = -ENOTSUP; |
81 | goto fail; | |
82 | } | |
83 | ||
850f49de | 84 | block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE; |
7d969014 DB |
85 | block->payload_offset = 0; |
86 | ||
87 | return 0; | |
88 | ||
89 | fail: | |
c972fa12 | 90 | qcrypto_block_free_cipher(block); |
7d969014 DB |
91 | qcrypto_ivgen_free(block->ivgen); |
92 | return ret; | |
93 | } | |
94 | ||
95 | ||
96 | static int | |
97 | qcrypto_block_qcow_open(QCryptoBlock *block, | |
98 | QCryptoBlockOpenOptions *options, | |
1cd9a787 | 99 | const char *optprefix, |
7d969014 DB |
100 | QCryptoBlockReadFunc readfunc G_GNUC_UNUSED, |
101 | void *opaque G_GNUC_UNUSED, | |
102 | unsigned int flags, | |
c972fa12 | 103 | size_t n_threads, |
7d969014 DB |
104 | Error **errp) |
105 | { | |
106 | if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) { | |
07809a7f DB |
107 | block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE; |
108 | block->payload_offset = 0; | |
7d969014 DB |
109 | return 0; |
110 | } else { | |
111 | if (!options->u.qcow.key_secret) { | |
112 | error_setg(errp, | |
1cd9a787 DB |
113 | "Parameter '%skey-secret' is required for cipher", |
114 | optprefix ? optprefix : ""); | |
7d969014 DB |
115 | return -1; |
116 | } | |
c972fa12 VSO |
117 | return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, |
118 | n_threads, errp); | |
7d969014 DB |
119 | } |
120 | } | |
121 | ||
122 | ||
123 | static int | |
124 | qcrypto_block_qcow_create(QCryptoBlock *block, | |
125 | QCryptoBlockCreateOptions *options, | |
1cd9a787 | 126 | const char *optprefix, |
7d969014 DB |
127 | QCryptoBlockInitFunc initfunc G_GNUC_UNUSED, |
128 | QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED, | |
129 | void *opaque G_GNUC_UNUSED, | |
130 | Error **errp) | |
131 | { | |
132 | if (!options->u.qcow.key_secret) { | |
1cd9a787 DB |
133 | error_setg(errp, "Parameter '%skey-secret' is required for cipher", |
134 | optprefix ? optprefix : ""); | |
7d969014 DB |
135 | return -1; |
136 | } | |
137 | /* QCow2 has no special header, since everything is hardwired */ | |
c972fa12 | 138 | return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, 1, errp); |
7d969014 DB |
139 | } |
140 | ||
141 | ||
142 | static void | |
143 | qcrypto_block_qcow_cleanup(QCryptoBlock *block) | |
144 | { | |
145 | } | |
146 | ||
147 | ||
148 | static int | |
149 | qcrypto_block_qcow_decrypt(QCryptoBlock *block, | |
4609742a | 150 | uint64_t offset, |
7d969014 DB |
151 | uint8_t *buf, |
152 | size_t len, | |
153 | Error **errp) | |
154 | { | |
4609742a DB |
155 | assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE)); |
156 | assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE)); | |
0f0d596c VSO |
157 | return qcrypto_block_decrypt_helper(block, |
158 | QCRYPTO_BLOCK_QCOW_SECTOR_SIZE, | |
159 | offset, buf, len, errp); | |
7d969014 DB |
160 | } |
161 | ||
162 | ||
163 | static int | |
164 | qcrypto_block_qcow_encrypt(QCryptoBlock *block, | |
4609742a | 165 | uint64_t offset, |
7d969014 DB |
166 | uint8_t *buf, |
167 | size_t len, | |
168 | Error **errp) | |
169 | { | |
4609742a DB |
170 | assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE)); |
171 | assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE)); | |
0f0d596c VSO |
172 | return qcrypto_block_encrypt_helper(block, |
173 | QCRYPTO_BLOCK_QCOW_SECTOR_SIZE, | |
174 | offset, buf, len, errp); | |
7d969014 DB |
175 | } |
176 | ||
177 | ||
178 | const QCryptoBlockDriver qcrypto_block_driver_qcow = { | |
179 | .open = qcrypto_block_qcow_open, | |
180 | .create = qcrypto_block_qcow_create, | |
181 | .cleanup = qcrypto_block_qcow_cleanup, | |
182 | .decrypt = qcrypto_block_qcow_decrypt, | |
183 | .encrypt = qcrypto_block_qcow_encrypt, | |
184 | .has_format = qcrypto_block_qcow_has_format, | |
185 | }; |