]> git.proxmox.com Git - mirror_qemu.git/blob - crypto/block-qcow.c
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20160321-1' into staging
[mirror_qemu.git] / crypto / block-qcow.c
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
9 * version 2 of the License, or (at your option) any later version.
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"
28
29 #include "crypto/block-qcow.h"
30 #include "crypto/secret.h"
31
32 #define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512
33
34
35 static bool
36 qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
37 size_t buf_size G_GNUC_UNUSED)
38 {
39 return false;
40 }
41
42
43 static int
44 qcrypto_block_qcow_init(QCryptoBlock *block,
45 const char *keysecret,
46 Error **errp)
47 {
48 char *password;
49 int ret;
50 uint8_t keybuf[16];
51 int len;
52
53 memset(keybuf, 0, 16);
54
55 password = qcrypto_secret_lookup_as_utf8(keysecret, errp);
56 if (!password) {
57 return -1;
58 }
59
60 len = strlen(password);
61 memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
62 g_free(password);
63
64 block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
65 QCRYPTO_CIPHER_MODE_CBC);
66 block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64,
67 0, 0, NULL, 0, errp);
68 if (!block->ivgen) {
69 ret = -ENOTSUP;
70 goto fail;
71 }
72
73 block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
74 QCRYPTO_CIPHER_MODE_CBC,
75 keybuf, G_N_ELEMENTS(keybuf),
76 errp);
77 if (!block->cipher) {
78 ret = -ENOTSUP;
79 goto fail;
80 }
81
82 block->payload_offset = 0;
83
84 return 0;
85
86 fail:
87 qcrypto_cipher_free(block->cipher);
88 qcrypto_ivgen_free(block->ivgen);
89 return ret;
90 }
91
92
93 static int
94 qcrypto_block_qcow_open(QCryptoBlock *block,
95 QCryptoBlockOpenOptions *options,
96 QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
97 void *opaque G_GNUC_UNUSED,
98 unsigned int flags,
99 Error **errp)
100 {
101 if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
102 return 0;
103 } else {
104 if (!options->u.qcow.key_secret) {
105 error_setg(errp,
106 "Parameter 'key-secret' is required for cipher");
107 return -1;
108 }
109 return qcrypto_block_qcow_init(block,
110 options->u.qcow.key_secret, errp);
111 }
112 }
113
114
115 static int
116 qcrypto_block_qcow_create(QCryptoBlock *block,
117 QCryptoBlockCreateOptions *options,
118 QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
119 QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
120 void *opaque G_GNUC_UNUSED,
121 Error **errp)
122 {
123 if (!options->u.qcow.key_secret) {
124 error_setg(errp, "Parameter 'key-secret' is required for cipher");
125 return -1;
126 }
127 /* QCow2 has no special header, since everything is hardwired */
128 return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
129 }
130
131
132 static void
133 qcrypto_block_qcow_cleanup(QCryptoBlock *block)
134 {
135 }
136
137
138 static int
139 qcrypto_block_qcow_decrypt(QCryptoBlock *block,
140 uint64_t startsector,
141 uint8_t *buf,
142 size_t len,
143 Error **errp)
144 {
145 return qcrypto_block_decrypt_helper(block->cipher,
146 block->niv, block->ivgen,
147 QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
148 startsector, buf, len, errp);
149 }
150
151
152 static int
153 qcrypto_block_qcow_encrypt(QCryptoBlock *block,
154 uint64_t startsector,
155 uint8_t *buf,
156 size_t len,
157 Error **errp)
158 {
159 return qcrypto_block_encrypt_helper(block->cipher,
160 block->niv, block->ivgen,
161 QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
162 startsector, buf, len, errp);
163 }
164
165
166 const QCryptoBlockDriver qcrypto_block_driver_qcow = {
167 .open = qcrypto_block_qcow_open,
168 .create = qcrypto_block_qcow_create,
169 .cleanup = qcrypto_block_qcow_cleanup,
170 .decrypt = qcrypto_block_qcow_decrypt,
171 .encrypt = qcrypto_block_qcow_encrypt,
172 .has_format = qcrypto_block_qcow_has_format,
173 };