1

Does Windows provide a high-level, tested, supported, function to perform authenticated encryption using a symmetric key?

Of course AEAD (Authenticated Encryption with Additional Data) would be better. But this question is only asking AE (Authenticated Encryption).

Background

Windows provides a (relatively) simple API to encrypt a blob using the CryptProtectData API, which we can wrap in an easy to use function:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //...
}

The details of ProtectBytes are less important than the idea that you can use it quite easily:

  • here are the bytes I want encrypted by a secret key held in the System
  • give me back the encrypted blob

The returned blob is an undocumented documentation structure that contains everything needed (i.e. hash algorithm, cipher algorithm, salt, HMAC signature, etc) to decrypt and return the original data .

For completeness, here's the sample pseudocode implementation of ProtectBytes that uses the Crypt API to protect bytes:

public Byte[] ProtectBytes(Byte[] plaintext)
{
   //Setup our n-byte plaintext blob
   DATA_BLOB dataIn;
   dataIn.cbData = plaintext.Length;
   dataIn.pbData = Addr(plaintext[0]);

   DATA_BLOB dataOut;

   //dataOut = EncryptedFormOf(dataIn)
   BOOL bRes = CryptProtectData(
         dataIn,
         null,     //data description (optional PWideChar)
         null,     //optional entropy (PDATA_BLOB)
         null,     //reserved
         null,     //prompt struct
         CRYPTPROTECT_UI_FORBIDDEN || CRYPTPROTECT_LOCAL_MACHINE,
         ref dataOut);
   if (!bRes) then
   {
      DWORD le = GetLastError();
      throw new Win32Error(le, "Error calling CryptProtectData");
   }

   //Copy ciphertext from dataOut blob into an actual array
   bytes[] result;
   SetLength(result, dataOut.cbData);
   CopyMemory(dataOut.pbData, Addr(result[0]), dataOut.cbData);

   //When you have finished using the DATA_BLOB structure, free its pbData member by calling the LocalFree function
   LocalFree(HANDLE(dataOut.pbData)); //LocalFree takes a handle, not a pointer. But that's what the SDK says.
}

An important point in all this is that CryptProtectData can operate in one of two modes:

  • the data can only be decrypted by you (because it's, essentially, encrypted with your Windows password)
  • the data can be decrypted by anyone running on the same local machine (because it is encrypted, essentially, with the password of the local security subsystem)

CryptProtectDataWithPassword?

How to do the same with an explicit password?

The downside of CryptProtectData is that the decryption is tied to either:

  • me
  • my machine

This means that the encrypted data cannot be passed to anyone else. I need something more portable between different people. (e.g. people on other computers, people not on the same domain, people not on a domain)

Crypto API Next Gen on Windows 8 also doesn't support it

There is the bcrypt (aka BestCrypt, aka Cng, aka CryptoNG, aka Crypto NextGen, aka Cryptography Next Generation API) which provides an updated version of the Windows 2000-era CryptProtectData called ProtectSecret.

This function allows you to specify who on the domain can decrypt the secret - either through an SID, e.g.:

  • "SID=S-1-1-0": Everyone group
  • "SID=S-1-5-32-544": BUILTIN\Administrators group
  • "SID=S-1-5-32-545": BUILTIN\Users group

Or through a certificate in your private store:

  • "CERTIFICATE=HashId:87b8808ecb233e0736b84b60670065b36ca615f1": CN=youporn.com

The downside of this newer function is that:

  • it requires Windows 8 or newer
  • it only works on the domain
  • or with a certificate

I need it something that works with a password (i.e. a secret).

I don't want to roll my own

Does Windows have an existing high-level function to perform encryption with a password? One major virtue of Windows supporting it, is that they will return an opaque blob that supports versioning.

Everything is packaged into a versioned structure that contains everything needed to do the decryption, authentication. They can change the algorithm and old encrypted blobs still work, while new blobs will also work.

Plus, i don't want to roll my own. We all know how to roll your own encryption. It's pretty easy to not screw up encryption:

enter image description here

oops, next version

enter image description here

oops, next version

enter image description here

So rather than me rolling my own, i would love:

  • something that comes with Windows
  • returns an opaque blob
  • is vetted and tested by people with more time and knowledge than myself

The reason i don't use a libsodium is because it's not available for the language i'm using. (also it wasn't the question)

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • Man, this post is way too long... To answer the question, *"Does Windows provide a high-level, tested, supported, function to perform authenticated encryption using a symmetric key?"* - Yes. Use AES/GCM. It may also include CCM mode, too. Also see [How to chain BCryptEncrypt and BCryptDecrypt calls using AES in GCM mode?](https://stackoverflow.com/q/30720414/608639) and [`BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO`](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_authenticated_cipher_mode_info) in the docs. – jww Aug 19 '19 at 10:04
  • @jww The entire point of the question was to **not** do what is in the answer. I'm perfectly capable of rolling my own with the pieces provided by Windows. Assembling well-tested pieces isn't the hard-part of security. And in the end i **did** end up rolling my own with the bcrypt api. Of course we also avoid GCM, because of the nonce problem (which the other answer doesn't address). – Ian Boyd Aug 19 '19 at 19:54

0 Answers0