Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple AES encryption using WinAPI

I need to do simple single-block AES encryption / decryption in my Qt / C++ application. This is a "keep the honest people honest" implementation, so just a basic encrypt(key, data) is necessary--I'm not worried about initialization vectors, etc. My input and key will always be exactly 16 bytes.

I'd really like to avoid another dependency to compile / link / ship with my application, so I'm trying to use what's available on each platform. On the Mac, this was a one-liner to CCCrypt. On Windows, I'm getting lost in the API from WinCrypt.h. Their example of encrypting a file is almost 600 lines long. Seriously?

I'm looking at CryptEncrypt, but I'm falling down the rabbit hole of dependencies you have to create before you can call that.

Can anyone provide a simple example of doing AES encryption using the Windows API? Surely there's a way to do this in a line or two. Assume you already have a 128-bit key and 128-bits of data to encrypt.

like image 837
Dave Mateer Avatar asked Nov 02 '11 18:11

Dave Mateer


People also ask

Can you Bruteforce AES?

The EE Times points out that even using a supercomputer, a “brute force” attack would take one billion years to crack AES 128-bit encryption.

How do I encrypt AES in OpenSSL?

To encrypt a plaintext using AES with OpenSSL, the enc command is used. The following command will prompt you for a password, encrypt a file called plaintext. txt and Base64 encode the output. The output will be written to standard out (the console).


1 Answers

Here's the best I've been able to come up with. Suggestions for improvement are welcome!

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);
}
like image 60
Dave Mateer Avatar answered Sep 30 '22 13:09

Dave Mateer