xref: /openbmc/qemu/crypto/block.c (revision 7d9690148ac25bc755a759adab7d63f517d092b1)
1*7d969014SDaniel P. Berrange /*
2*7d969014SDaniel P. Berrange  * QEMU Crypto block device encryption
3*7d969014SDaniel P. Berrange  *
4*7d969014SDaniel P. Berrange  * Copyright (c) 2015-2016 Red Hat, Inc.
5*7d969014SDaniel P. Berrange  *
6*7d969014SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
7*7d969014SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
8*7d969014SDaniel P. Berrange  * License as published by the Free Software Foundation; either
9*7d969014SDaniel P. Berrange  * version 2 of the License, or (at your option) any later version.
10*7d969014SDaniel P. Berrange  *
11*7d969014SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
12*7d969014SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*7d969014SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*7d969014SDaniel P. Berrange  * Lesser General Public License for more details.
15*7d969014SDaniel P. Berrange  *
16*7d969014SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
17*7d969014SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*7d969014SDaniel P. Berrange  *
19*7d969014SDaniel P. Berrange  */
20*7d969014SDaniel P. Berrange 
21*7d969014SDaniel P. Berrange #include "qemu/osdep.h"
22*7d969014SDaniel P. Berrange #include "crypto/blockpriv.h"
23*7d969014SDaniel P. Berrange #include "crypto/block-qcow.h"
24*7d969014SDaniel P. Berrange 
25*7d969014SDaniel P. Berrange static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
26*7d969014SDaniel P. Berrange     [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
27*7d969014SDaniel P. Berrange };
28*7d969014SDaniel P. Berrange 
29*7d969014SDaniel P. Berrange 
30*7d969014SDaniel P. Berrange bool qcrypto_block_has_format(QCryptoBlockFormat format,
31*7d969014SDaniel P. Berrange                               const uint8_t *buf,
32*7d969014SDaniel P. Berrange                               size_t len)
33*7d969014SDaniel P. Berrange {
34*7d969014SDaniel P. Berrange     const QCryptoBlockDriver *driver;
35*7d969014SDaniel P. Berrange 
36*7d969014SDaniel P. Berrange     if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
37*7d969014SDaniel P. Berrange         !qcrypto_block_drivers[format]) {
38*7d969014SDaniel P. Berrange         return false;
39*7d969014SDaniel P. Berrange     }
40*7d969014SDaniel P. Berrange 
41*7d969014SDaniel P. Berrange     driver = qcrypto_block_drivers[format];
42*7d969014SDaniel P. Berrange 
43*7d969014SDaniel P. Berrange     return driver->has_format(buf, len);
44*7d969014SDaniel P. Berrange }
45*7d969014SDaniel P. Berrange 
46*7d969014SDaniel P. Berrange 
47*7d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
48*7d969014SDaniel P. Berrange                                  QCryptoBlockReadFunc readfunc,
49*7d969014SDaniel P. Berrange                                  void *opaque,
50*7d969014SDaniel P. Berrange                                  unsigned int flags,
51*7d969014SDaniel P. Berrange                                  Error **errp)
52*7d969014SDaniel P. Berrange {
53*7d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
54*7d969014SDaniel P. Berrange 
55*7d969014SDaniel P. Berrange     block->format = options->format;
56*7d969014SDaniel P. Berrange 
57*7d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
58*7d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
59*7d969014SDaniel P. Berrange         error_setg(errp, "Unsupported block driver %d", options->format);
60*7d969014SDaniel P. Berrange         g_free(block);
61*7d969014SDaniel P. Berrange         return NULL;
62*7d969014SDaniel P. Berrange     }
63*7d969014SDaniel P. Berrange 
64*7d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
65*7d969014SDaniel P. Berrange 
66*7d969014SDaniel P. Berrange     if (block->driver->open(block, options,
67*7d969014SDaniel P. Berrange                             readfunc, opaque, flags, errp) < 0) {
68*7d969014SDaniel P. Berrange         g_free(block);
69*7d969014SDaniel P. Berrange         return NULL;
70*7d969014SDaniel P. Berrange     }
71*7d969014SDaniel P. Berrange 
72*7d969014SDaniel P. Berrange     return block;
73*7d969014SDaniel P. Berrange }
74*7d969014SDaniel P. Berrange 
75*7d969014SDaniel P. Berrange 
76*7d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
77*7d969014SDaniel P. Berrange                                    QCryptoBlockInitFunc initfunc,
78*7d969014SDaniel P. Berrange                                    QCryptoBlockWriteFunc writefunc,
79*7d969014SDaniel P. Berrange                                    void *opaque,
80*7d969014SDaniel P. Berrange                                    Error **errp)
81*7d969014SDaniel P. Berrange {
82*7d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
83*7d969014SDaniel P. Berrange 
84*7d969014SDaniel P. Berrange     block->format = options->format;
85*7d969014SDaniel P. Berrange 
86*7d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
87*7d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
88*7d969014SDaniel P. Berrange         error_setg(errp, "Unsupported block driver %d", options->format);
89*7d969014SDaniel P. Berrange         g_free(block);
90*7d969014SDaniel P. Berrange         return NULL;
91*7d969014SDaniel P. Berrange     }
92*7d969014SDaniel P. Berrange 
93*7d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
94*7d969014SDaniel P. Berrange 
95*7d969014SDaniel P. Berrange     if (block->driver->create(block, options, initfunc,
96*7d969014SDaniel P. Berrange                               writefunc, opaque, errp) < 0) {
97*7d969014SDaniel P. Berrange         g_free(block);
98*7d969014SDaniel P. Berrange         return NULL;
99*7d969014SDaniel P. Berrange     }
100*7d969014SDaniel P. Berrange 
101*7d969014SDaniel P. Berrange     return block;
102*7d969014SDaniel P. Berrange }
103*7d969014SDaniel P. Berrange 
104*7d969014SDaniel P. Berrange 
105*7d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block,
106*7d969014SDaniel P. Berrange                           uint64_t startsector,
107*7d969014SDaniel P. Berrange                           uint8_t *buf,
108*7d969014SDaniel P. Berrange                           size_t len,
109*7d969014SDaniel P. Berrange                           Error **errp)
110*7d969014SDaniel P. Berrange {
111*7d969014SDaniel P. Berrange     return block->driver->decrypt(block, startsector, buf, len, errp);
112*7d969014SDaniel P. Berrange }
113*7d969014SDaniel P. Berrange 
114*7d969014SDaniel P. Berrange 
115*7d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block,
116*7d969014SDaniel P. Berrange                           uint64_t startsector,
117*7d969014SDaniel P. Berrange                           uint8_t *buf,
118*7d969014SDaniel P. Berrange                           size_t len,
119*7d969014SDaniel P. Berrange                           Error **errp)
120*7d969014SDaniel P. Berrange {
121*7d969014SDaniel P. Berrange     return block->driver->encrypt(block, startsector, buf, len, errp);
122*7d969014SDaniel P. Berrange }
123*7d969014SDaniel P. Berrange 
124*7d969014SDaniel P. Berrange 
125*7d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
126*7d969014SDaniel P. Berrange {
127*7d969014SDaniel P. Berrange     return block->cipher;
128*7d969014SDaniel P. Berrange }
129*7d969014SDaniel P. Berrange 
130*7d969014SDaniel P. Berrange 
131*7d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
132*7d969014SDaniel P. Berrange {
133*7d969014SDaniel P. Berrange     return block->ivgen;
134*7d969014SDaniel P. Berrange }
135*7d969014SDaniel P. Berrange 
136*7d969014SDaniel P. Berrange 
137*7d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
138*7d969014SDaniel P. Berrange {
139*7d969014SDaniel P. Berrange     return block->kdfhash;
140*7d969014SDaniel P. Berrange }
141*7d969014SDaniel P. Berrange 
142*7d969014SDaniel P. Berrange 
143*7d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
144*7d969014SDaniel P. Berrange {
145*7d969014SDaniel P. Berrange     return block->payload_offset;
146*7d969014SDaniel P. Berrange }
147*7d969014SDaniel P. Berrange 
148*7d969014SDaniel P. Berrange 
149*7d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block)
150*7d969014SDaniel P. Berrange {
151*7d969014SDaniel P. Berrange     if (!block) {
152*7d969014SDaniel P. Berrange         return;
153*7d969014SDaniel P. Berrange     }
154*7d969014SDaniel P. Berrange 
155*7d969014SDaniel P. Berrange     block->driver->cleanup(block);
156*7d969014SDaniel P. Berrange 
157*7d969014SDaniel P. Berrange     qcrypto_cipher_free(block->cipher);
158*7d969014SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
159*7d969014SDaniel P. Berrange     g_free(block);
160*7d969014SDaniel P. Berrange }
161*7d969014SDaniel P. Berrange 
162*7d969014SDaniel P. Berrange 
163*7d969014SDaniel P. Berrange int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
164*7d969014SDaniel P. Berrange                                  size_t niv,
165*7d969014SDaniel P. Berrange                                  QCryptoIVGen *ivgen,
166*7d969014SDaniel P. Berrange                                  int sectorsize,
167*7d969014SDaniel P. Berrange                                  uint64_t startsector,
168*7d969014SDaniel P. Berrange                                  uint8_t *buf,
169*7d969014SDaniel P. Berrange                                  size_t len,
170*7d969014SDaniel P. Berrange                                  Error **errp)
171*7d969014SDaniel P. Berrange {
172*7d969014SDaniel P. Berrange     uint8_t *iv;
173*7d969014SDaniel P. Berrange     int ret = -1;
174*7d969014SDaniel P. Berrange 
175*7d969014SDaniel P. Berrange     iv = niv ? g_new0(uint8_t, niv) : NULL;
176*7d969014SDaniel P. Berrange 
177*7d969014SDaniel P. Berrange     while (len > 0) {
178*7d969014SDaniel P. Berrange         size_t nbytes;
179*7d969014SDaniel P. Berrange         if (niv) {
180*7d969014SDaniel P. Berrange             if (qcrypto_ivgen_calculate(ivgen,
181*7d969014SDaniel P. Berrange                                         startsector,
182*7d969014SDaniel P. Berrange                                         iv, niv,
183*7d969014SDaniel P. Berrange                                         errp) < 0) {
184*7d969014SDaniel P. Berrange                 goto cleanup;
185*7d969014SDaniel P. Berrange             }
186*7d969014SDaniel P. Berrange 
187*7d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
188*7d969014SDaniel P. Berrange                                      iv, niv,
189*7d969014SDaniel P. Berrange                                      errp) < 0) {
190*7d969014SDaniel P. Berrange                 goto cleanup;
191*7d969014SDaniel P. Berrange             }
192*7d969014SDaniel P. Berrange         }
193*7d969014SDaniel P. Berrange 
194*7d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
195*7d969014SDaniel P. Berrange         if (qcrypto_cipher_decrypt(cipher, buf, buf,
196*7d969014SDaniel P. Berrange                                    nbytes, errp) < 0) {
197*7d969014SDaniel P. Berrange             goto cleanup;
198*7d969014SDaniel P. Berrange         }
199*7d969014SDaniel P. Berrange 
200*7d969014SDaniel P. Berrange         startsector++;
201*7d969014SDaniel P. Berrange         buf += nbytes;
202*7d969014SDaniel P. Berrange         len -= nbytes;
203*7d969014SDaniel P. Berrange     }
204*7d969014SDaniel P. Berrange 
205*7d969014SDaniel P. Berrange     ret = 0;
206*7d969014SDaniel P. Berrange  cleanup:
207*7d969014SDaniel P. Berrange     g_free(iv);
208*7d969014SDaniel P. Berrange     return ret;
209*7d969014SDaniel P. Berrange }
210*7d969014SDaniel P. Berrange 
211*7d969014SDaniel P. Berrange 
212*7d969014SDaniel P. Berrange int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
213*7d969014SDaniel P. Berrange                                  size_t niv,
214*7d969014SDaniel P. Berrange                                  QCryptoIVGen *ivgen,
215*7d969014SDaniel P. Berrange                                  int sectorsize,
216*7d969014SDaniel P. Berrange                                  uint64_t startsector,
217*7d969014SDaniel P. Berrange                                  uint8_t *buf,
218*7d969014SDaniel P. Berrange                                  size_t len,
219*7d969014SDaniel P. Berrange                                  Error **errp)
220*7d969014SDaniel P. Berrange {
221*7d969014SDaniel P. Berrange     uint8_t *iv;
222*7d969014SDaniel P. Berrange     int ret = -1;
223*7d969014SDaniel P. Berrange 
224*7d969014SDaniel P. Berrange     iv = niv ? g_new0(uint8_t, niv) : NULL;
225*7d969014SDaniel P. Berrange 
226*7d969014SDaniel P. Berrange     while (len > 0) {
227*7d969014SDaniel P. Berrange         size_t nbytes;
228*7d969014SDaniel P. Berrange         if (niv) {
229*7d969014SDaniel P. Berrange             if (qcrypto_ivgen_calculate(ivgen,
230*7d969014SDaniel P. Berrange                                         startsector,
231*7d969014SDaniel P. Berrange                                         iv, niv,
232*7d969014SDaniel P. Berrange                                         errp) < 0) {
233*7d969014SDaniel P. Berrange                 goto cleanup;
234*7d969014SDaniel P. Berrange             }
235*7d969014SDaniel P. Berrange 
236*7d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
237*7d969014SDaniel P. Berrange                                      iv, niv,
238*7d969014SDaniel P. Berrange                                      errp) < 0) {
239*7d969014SDaniel P. Berrange                 goto cleanup;
240*7d969014SDaniel P. Berrange             }
241*7d969014SDaniel P. Berrange         }
242*7d969014SDaniel P. Berrange 
243*7d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
244*7d969014SDaniel P. Berrange         if (qcrypto_cipher_encrypt(cipher, buf, buf,
245*7d969014SDaniel P. Berrange                                    nbytes, errp) < 0) {
246*7d969014SDaniel P. Berrange             goto cleanup;
247*7d969014SDaniel P. Berrange         }
248*7d969014SDaniel P. Berrange 
249*7d969014SDaniel P. Berrange         startsector++;
250*7d969014SDaniel P. Berrange         buf += nbytes;
251*7d969014SDaniel P. Berrange         len -= nbytes;
252*7d969014SDaniel P. Berrange     }
253*7d969014SDaniel P. Berrange 
254*7d969014SDaniel P. Berrange     ret = 0;
255*7d969014SDaniel P. Berrange  cleanup:
256*7d969014SDaniel P. Berrange     g_free(iv);
257*7d969014SDaniel P. Berrange     return ret;
258*7d969014SDaniel P. Berrange }
259