1

I need to securely persist AES key(s) to be used by the .NET AesCng algorithm. The idea is to use the CngKey class to persist the key(s) and leverage its export/import functionality to maintain the same key(s) across multiple servers.

I can create the persisted AES key

public static bool CreateContainer(string name)
{
    if (CngKey.Exists(name))
    {
        return false;
    }

    CngKeyCreationParameters keyCreationParameters = new CngKeyCreationParameters()
    {
        ExportPolicy = CngExportPolicies.AllowPlaintextExport,
        KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey
    };
    CngKey cngKey = CngKey.Create(new CngAlgorithm("AES"), name, keyCreationParameters);
    cngKey.Dispose();
    return true;
}

and then use it to encrypt/decrypt

    public static byte[] Encrypt(string keyContainerName, byte[] clearText, byte[] iv)
    {
        AesCng aesCng = null;
        ICryptoTransform crypto = null;
        byte[] cipher = null;
        try
        {
            aesCng = new AesCng(keyContainerName);
            aesCng.IV = (iv == null ? new byte[aesCng.IV.Length] : iv);
            crypto = aesCng.CreateEncryptor();
            cipher = crypto.TransformFinalBlock(clearText, 0, clearText.Length);
        }
        finally
        {
            if (crypto != null)
            {
                crypto.Dispose();
            }
            if (aesCng != null)
            {
                aesCng.Clear();
                aesCng.Dispose();
            }
        }
        return cipher;
    }

    public static byte[] Decrypt(string keyContainerName, byte[] cipher, byte[] iv)
    {
        AesCng aesCng = null;
        ICryptoTransform crypto = null;
        byte[] clearText = null;
        try
        {
            aesCng = new AesCng(keyContainerName);
            aesCng.IV = (iv == null ? new byte[aesCng.IV.Length] : iv);
            crypto = aesCng.CreateDecryptor();
            clearText = crypto.TransformFinalBlock(cipher, 0, cipher.Length);
        }
        finally
        {
            if (crypto != null)
            {
                crypto.Dispose();
            }
            if (aesCng != null)
            {
                aesCng.Clear();
                aesCng.Dispose();
            }
        }
        return clearText;
    }

I am able to export the key

    public static bool ExportKey(string name, out byte[] blob)
    {
        blob = null;
        if (!CngKey.Exists(name))
        {
            return false;
        }

        CngKey cngKey = CngKey.Open(name);
        blob = cngKey.Export(CngKeyBlobFormat.OpaqueTransportBlob);
        cngKey.Dispose();
        return true;
    }

However, when I try to import the blob, I get a CryptographicException: The supplied handle is invalid.

    public static void ImportKey(string name, byte[] blob)
    {
        CngKey cngKey = CngKey.Import(blob, CngKeyBlobFormat.OpaqueTransportBlob);
        cngKey.Dispose();
    }

I am at a loss to explain why the failure. Can anyone shed some light on this?

Thanks.

L_E_R
  • 11
  • 1
  • Are you using any specific providers or are you using a generic software provider for the AES functionality? – Maarten Bodewes Feb 21 '18 at 21:34
  • I am using the default provider, that is, CngProvider.MicrosoftSoftwareKeyStorageProvider. Since then I have discovered the following: if you swallow the exception, everything works as advertised, that is, I encrypt some text, export the blob, save it to a file on disk, delete the container, read the blob from the file on disk, create a new container and then successfully decrypt the cipher. I would like to report this to Microsoft - do you know how to get in touch with them for this? – L_E_R Feb 21 '18 at 22:22
  • "Export a symmetric key in a format that is specific to a single cryptographic service provider (CSP). Opaque BLOBs are not transferable and must be imported by using the same CSP that generated the BLOB. Opaque BLOBs are only intended to be used **for interprocess transfer of keys** and are not suitable to be persisted and read across versions of a provider." – Maarten Bodewes Feb 21 '18 at 22:26
  • You might want to *wrap* the AES key instead, e.g. using an RSA public key and decrypt that on the server, or a similar method of *secure key distribution*. – Maarten Bodewes Feb 21 '18 at 22:27

0 Answers0