Простое шифрование 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);
}
Другие вопросы по тегам