MrSpudtastic
MrSpudtastic

Reputation: 215

How do I create a public-key/private-key pair and safely store them into a key container?

I have been trying to do some simple cryptography practice, but I am stumped. I have thus far been able to generate a pair of public and private keys, but I haven't figured out how to safely store them or make them persist beyond a single session. In my research, I've heard of this thing called a "key container" that allows these keys to (safely) persist beyond a single session and be retrieved at a later time.

Unfortunately, cryptography is complicated, so every time I think I've figured something out, it gives me five more questions that have to be answered before I can understand what I'm doing. By this point, my head is swimming with all this information, and I'm having quite a bit of trouble making sense of it all. So...

I would like to see a code example that creates a public-key/private-key pair, saves them in a key container, and then retrieves them. If possible, I would also like to see some code that retrieves a public key and a private key from a key container that is assumed to already exist. For constraints, assume that Visual Studios C# is being used in a .NET framework, on a Windows 10 OS.

I'd prefer to see this with RSA encryption, unless there is a safer way to do this.

I am almost certain that this is more or less a duplicate question, but if so, then I haven't found the original yet.

Upvotes: 2

Views: 1982

Answers (1)

bartonjs
bartonjs

Reputation: 33098

Borrowed from a corefx test (and other code in the same file):

// Ideally you use a name that won't ever be used by someone else.
// Certificate import names its keys GUIDs, but then has to remember what they were.
const string KeyName = "SomePersistedKey";
const int Size = 2048; // Or whatever.

CNG:

CngKey key = null;

try
{
    key = CngKey.Open(KeyName);
}
catch (CryptographicException)
{
    // This is only in the catch block to avoid a scrollbar.
    CngKeyCreationParameters creationParameters = new CngKeyCreationParameters()
    {
        ExportPolicy = CngExportPolicies.None, // Or whatever.
        Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
        KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
        Parameters =
        {
            new CngProperty("Length", BitConverter.GetBytes(Size), CngPropertyOptions.None),
        }
    };

    cngKey = CngKey.Create(CngAlgorithm.Rsa, KeyName, creationParameters);
}

using (cngKey)
using (RSA rsa = new RSACng(cngKey))
{
    // Tada.
}

Or, if you need to stick with CAPI (hopefully not):

const int PROV_RSA_AES = 24;

CspParameters cspParameters = new CspParameters(PROV_RSA_AES)
{
    KeyNumber = (int)KeyNumber.Exchange,
    KeyContainerName = KeyName,
    Flags = CspProviderFlags.UseNonExportableKey, // Or whatever.
};

// This constructor is open-or-create since flags didn't asset ExistingOnly.
using (RSA rsa = new RSACryptoServiceProvider(Size, cspParameters))
{
    // tada.  Use CNG instead, if you can.
}

Upvotes: 1

Related Questions