Простое шифрование AES с использованием WinAPI
Мне нужно сделать простое одноблочное шифрование / дешифрование AES в моем приложении Qt / C++. Это реализация "держите честных людей честными", поэтому просто encrypt(key, data)
необходимо - меня не волнуют векторы инициализации и т. д. Мой ввод и ключ всегда будут точно 16 байтов.
Я действительно хотел бы избежать другой зависимости при компиляции / связывании / доставке с моим приложением, поэтому я пытаюсь использовать то, что доступно на каждой платформе. На Mac это была одна строка CCCrypt
, В Windows я заблудился в API от WinCrypt.h
, Их пример шифрования файла составляет почти 600 строк. Шутки в сторону?
Я смотрю на CryptEncrypt
, но я падаю в кроличью нору зависимостей, которые вы должны создать, прежде чем сможете это назвать.
Может ли кто-нибудь привести простой пример выполнения шифрования AES с помощью Windows API? Конечно, есть способ сделать это в одну или две строки. Предположим, у вас уже есть 128-битный ключ и 128-битные данные для шифрования.
1 ответ
Вот лучшее, что я смог придумать. Предложения по улучшению приветствуются!
static void encrypt(const QByteArray &data,
const QByteArray &key,
QByteArray *encrypted) {
// Create the crypto provider context.
HCRYPTPROV hProvider = NULL;
if (!CryptAcquireContext(&hProvider,
NULL, // pszContainer = no named container
NULL, // pszProvider = default provider
PROV_RSA_AES,
CRYPT_VERIFYCONTEXT)) {
throw std::runtime_error("Unable to create crypto provider context.");
}
// Construct the blob necessary for the key generation.
AesBlob128 aes_blob;
aes_blob.header.bType = PLAINTEXTKEYBLOB;
aes_blob.header.bVersion = CUR_BLOB_VERSION;
aes_blob.header.reserved = 0;
aes_blob.header.aiKeyAlg = CALG_AES_128;
aes_blob.key_length = kAesBytes128;
memcpy(aes_blob.key_bytes, key.constData(), kAesBytes128);
// Create the crypto key struct that Windows needs.
HCRYPTKEY hKey = NULL;
if (!CryptImportKey(hProvider,
reinterpret_cast<BYTE*>(&aes_blob),
sizeof(AesBlob128),
NULL, // hPubKey = not encrypted
0, // dwFlags
&hKey)) {
throw std::runtime_error("Unable to create crypto key.");
}
// The CryptEncrypt method uses the *same* buffer for both the input and
// output (!), so we copy the data to be encrypted into the output array.
// Also, for some reason, the AES-128 block cipher on Windows requires twice
// the block size in the output buffer. So we resize it to that length and
// then chop off the excess after we are done.
encrypted->clear();
encrypted->append(data);
encrypted->resize(kAesBytes128 * 2);
// This acts as both the length of bytes to be encoded (on input) and the
// number of bytes used in the resulting encrypted data (on output).
DWORD length = kAesBytes128;
if (!CryptEncrypt(hKey,
NULL, // hHash = no hash
true, // Final
0, // dwFlags
reinterpret_cast<BYTE*>(encrypted->data()),
&length,
encrypted->length())) {
throw std::runtime_error("Encryption failed");
}
// See comment above.
encrypted->chop(length - kAesBytes128);
CryptDestroyKey(hKey);
CryptReleaseContext(hProvider, 0);
}