There are a number of different algorithms that can be used to generate initialization vectors for disk encryption. This introduces a simple internal QCryptoBlockIV object to provide a consistent internal API to the different algorithms. The initially implemented algorithms are 'plain', 'plain64' and 'essiv', each matching the same named algorithm provided by the Linux kernel dm-crypt driver. Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
207 lines
5.8 KiB
C
207 lines
5.8 KiB
C
/*
|
|
* QEMU Crypto block IV generator
|
|
*
|
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#ifndef QCRYPTO_IVGEN_H__
|
|
#define QCRYPTO_IVGEN_H__
|
|
|
|
#include "crypto/cipher.h"
|
|
#include "crypto/hash.h"
|
|
|
|
/**
|
|
* This module provides a framework for generating initialization
|
|
* vectors for block encryption schemes using chained cipher modes
|
|
* CBC. The principle is that each disk sector is assigned a unique
|
|
* initialization vector for use for encryption of data in that
|
|
* sector.
|
|
*
|
|
* <example>
|
|
* <title>Encrypting block data with initialiation vectors</title>
|
|
* <programlisting>
|
|
* uint8_t *data = ....data to encrypt...
|
|
* size_t ndata = XXX;
|
|
* uint8_t *key = ....some encryption key...
|
|
* size_t nkey = XXX;
|
|
* uint8_t *iv;
|
|
* size_t niv;
|
|
* size_t sector = 0;
|
|
*
|
|
* g_assert((ndata % 512) == 0);
|
|
*
|
|
* QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_ESSIV,
|
|
* QCRYPTO_CIPHER_ALG_AES_128,
|
|
* QCRYPTO_HASH_ALG_SHA256,
|
|
* key, nkey, errp);
|
|
* if (!ivgen) {
|
|
* return -1;
|
|
* }
|
|
*
|
|
* QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
|
* QCRYPTO_CIPHER_MODE_CBC,
|
|
* key, nkey, errp);
|
|
* if (!cipher) {
|
|
* goto error;
|
|
* }
|
|
*
|
|
* niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
|
|
* QCRYPTO_CIPHER_MODE_CBC);
|
|
* iv = g_new0(uint8_t, niv);
|
|
*
|
|
*
|
|
* while (ndata) {
|
|
* if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp) < 0) {
|
|
* goto error;
|
|
* }
|
|
* if (qcrypto_cipher_setiv(cipher, iv, niv, errp) < 0) {
|
|
* goto error;
|
|
* }
|
|
* if (qcrypto_cipher_encrypt(cipher,
|
|
* data + (sector * 512),
|
|
* data + (sector * 512),
|
|
* 512, errp) < 0) {
|
|
* goto error;
|
|
* }
|
|
* sector++;
|
|
* ndata -= 512;
|
|
* }
|
|
*
|
|
* g_free(iv);
|
|
* qcrypto_ivgen_free(ivgen);
|
|
* qcrypto_cipher_free(cipher);
|
|
* return 0;
|
|
*
|
|
*error:
|
|
* g_free(iv);
|
|
* qcrypto_ivgen_free(ivgen);
|
|
* qcrypto_cipher_free(cipher);
|
|
* return -1;
|
|
* </programlisting>
|
|
* </example>
|
|
*/
|
|
|
|
typedef struct QCryptoIVGen QCryptoIVGen;
|
|
|
|
/* See also QCryptoIVGenAlgorithm enum in qapi/crypto.json */
|
|
|
|
|
|
/**
|
|
* qcrypto_ivgen_new:
|
|
* @alg: the initialization vector generation algorithm
|
|
* @cipheralg: the cipher algorithm or 0
|
|
* @hash: the hash algorithm or 0
|
|
* @key: the encryption key or NULL
|
|
* @nkey: the size of @key in bytes
|
|
*
|
|
* Create a new initialization vector generator that uses
|
|
* the algorithm @alg. Whether the remaining parameters
|
|
* are required or not depends on the choice of @alg
|
|
* requested.
|
|
*
|
|
* - QCRYPTO_IVGEN_ALG_PLAIN
|
|
*
|
|
* The IVs are generated by the 32-bit truncated sector
|
|
* number. This should never be used for block devices
|
|
* that are larger than 2^32 sectors in size.
|
|
* All the other parameters are unused.
|
|
*
|
|
* - QCRYPTO_IVGEN_ALG_PLAIN64
|
|
*
|
|
* The IVs are generated by the 64-bit sector number.
|
|
* All the other parameters are unused.
|
|
*
|
|
* - QCRYPTO_IVGEN_ALG_ESSIV:
|
|
*
|
|
* The IVs are generated by encrypting the 64-bit sector
|
|
* number with a hash of an encryption key. The @cipheralg,
|
|
* @hash, @key and @nkey parameters are all required.
|
|
*
|
|
* Returns: a new IV generator, or NULL on error
|
|
*/
|
|
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
|
|
QCryptoCipherAlgorithm cipheralg,
|
|
QCryptoHashAlgorithm hash,
|
|
const uint8_t *key, size_t nkey,
|
|
Error **errp);
|
|
|
|
/**
|
|
* qcrypto_ivgen_calculate:
|
|
* @ivgen: the IV generator object
|
|
* @sector: the 64-bit sector number
|
|
* @iv: a pre-allocated buffer to hold the generated IV
|
|
* @niv: the number of bytes in @iv
|
|
* @errp: pointer to a NULL-initialized error object
|
|
*
|
|
* Calculate a new initialiation vector for the data
|
|
* to be stored in sector @sector. The IV will be
|
|
* written into the buffer @iv of size @niv.
|
|
*
|
|
* Returns: 0 on success, -1 on error
|
|
*/
|
|
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
|
|
uint64_t sector,
|
|
uint8_t *iv, size_t niv,
|
|
Error **errp);
|
|
|
|
|
|
/**
|
|
* qcrypto_ivgen_get_algorithm:
|
|
* @ivgen: the IV generator object
|
|
*
|
|
* Get the algorithm used by this IV generator
|
|
*
|
|
* Returns: the IV generator algorithm
|
|
*/
|
|
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
|
|
|
|
|
|
/**
|
|
* qcrypto_ivgen_get_cipher:
|
|
* @ivgen: the IV generator object
|
|
*
|
|
* Get the cipher algorithm used by this IV generator (if
|
|
* applicable)
|
|
*
|
|
* Returns: the cipher algorithm
|
|
*/
|
|
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
|
|
|
|
|
|
/**
|
|
* qcrypto_ivgen_get_hash:
|
|
* @ivgen: the IV generator object
|
|
*
|
|
* Get the hash algorithm used by this IV generator (if
|
|
* applicable)
|
|
*
|
|
* Returns: the hash algorithm
|
|
*/
|
|
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
|
|
|
|
|
|
/**
|
|
* qcrypto_ivgen_free:
|
|
* @ivgen: the IV generator object
|
|
*
|
|
* Release all resources associated with @ivgen, or a no-op
|
|
* if @ivgen is NULL
|
|
*/
|
|
void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
|
|
|
|
#endif /* QCRYPTO_IVGEN_H__ */
|