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.
- If they suddenly decide to change from AES-128 to AES-256
- or change the length of the salt
- or suddenly decide to completely switch to GCM in CTR mode encryption with the addition of a Carter-Wegman MAC set in a Galois field
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:
oops, next version
oops, next version
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)