Простое шифрование AES с использованием WinAPI

#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);
}