#c #winapi #encryption #aes
#c #winapi #шифрование #aes
Вопрос:
Мне нужно выполнить простое одноблочное шифрование / дешифрование AES в моем приложении Qt / C . Это реализация «держите честных людей честными», поэтому необходимо только базовое encrypt(key, data)
— я не беспокоюсь о векторах инициализации и т. Д. Мои входные данные и ключ всегда будут составлять ровно 16 байт.
Мне бы очень хотелось избежать другой зависимости для компиляции / связывания / отправки с моим приложением, поэтому я пытаюсь использовать то, что доступно на каждой платформе. На Mac это было однострочным CCCrypt
. В Windows я теряюсь в API из WinCrypt.h
. Их пример шифрования файла имеет длину почти 600 строк. Серьезно?
Я смотрю CryptEncrypt
, но я проваливаюсь в кроличью нору зависимостей, которые вы должны создать, прежде чем сможете это вызвать.
Кто-нибудь может привести простой пример выполнения шифрования AES с использованием Windows API? Конечно, есть способ сделать это в одной или двух строках. Предположим, у вас уже есть 128-битный ключ и 128-битные данные для шифрования.
Комментарии:
1. Я не могу предоставить простой пример WinAPI (потому что он может не существовать, как вы отметили), но вы заглянули в OpenSSL? Я использовал его в нескольких проектах, и это довольно просто. Я знаю, что вы не хотите добавлять другую зависимость, но это может оказаться более простым решением.
Ответ №1:
Вот лучшее, что я смог придумать. Предложения по улучшению приветствуются!
static void encrypt(const QByteArray amp;data,
const QByteArray amp;key,
QByteArray *encrypted) {
// Create the crypto provider context.
HCRYPTPROV hProvider = NULL;
if (!CryptAcquireContext(amp;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*>(amp;aes_blob),
sizeof(AesBlob128),
NULL, // hPubKey = not encrypted
0, // dwFlags
amp;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()),
amp;length,
encrypted->length())) {
throw std::runtime_error("Encryption failed");
}
// See comment above.
encrypted->chop(length - kAesBytes128);
CryptDestroyKey(hKey);
CryptReleaseContext(hProvider, 0);
}