Create or open an RSA CNG key without an implicit overwrite policy
Illustrative code, not executed.
Original English publication date: 2022-05-24T08:43:00.005+03:00. Original English article
Illustration unavailable: Cryptography illustration from the original article (original image source).
CNG key names identify persistent objects within a provider and user-or-machine scope. Creation and opening should be separate operations with an explicit lifecycle policy. A check with Exists followed by Create is not atomic, and an existing name does not prove that the key belongs to the intended application. The archived example also grants AllUsages and defaults to machine scope, which is broader than a signing-only example needs. [1][2]
The following Windows-only functions are illustrative and were never called. Creating a named key changes persistent security state and requires a separately authorized deployment plan. The sample deliberately uses current-user scope, Signing only and no export permission. The provider and name must be supplied by that plan; do not silently substitute the software provider if a requested TPM provider is unavailable. [1][3]
using System;
using System.Security.Cryptography;
public static class CngKeyExample
{
// Illustrative methods only: do not invoke as part of reviewing this article.
public static CngKey CreateNew(string approvedName, CngProvider approvedProvider, int bits)
{
if (!OperatingSystem.IsWindows()) throw new PlatformNotSupportedException();
if (string.IsNullOrWhiteSpace(approvedName)) throw new ArgumentException("Name required.");
if (approvedProvider == null) throw new ArgumentNullException(nameof(approvedProvider));
if (bits != 2048 && bits != 3072 && bits != 4096)
throw new ArgumentOutOfRangeException(nameof(bits));
var options = new CngKeyCreationParameters {
Provider = approvedProvider,
KeyCreationOptions = CngKeyCreationOptions.None, // Current user; no overwrite.
KeyUsage = CngKeyUsages.Signing,
ExportPolicy = CngExportPolicies.None
};
options.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(bits), CngPropertyOptions.None));
// A duplicate-name/provider failure is surfaced, not reinterpreted as approval to replace.
return CngKey.Create(CngAlgorithm.Rsa, approvedName, options);
}
public static CngKey OpenExisting(string approvedName, CngProvider approvedProvider, int expectedBits)
{
if (!OperatingSystem.IsWindows()) throw new PlatformNotSupportedException();
if (string.IsNullOrWhiteSpace(approvedName)) throw new ArgumentException("Name required.");
if (approvedProvider == null) throw new ArgumentNullException(nameof(approvedProvider));
CngKey key = CngKey.Open(approvedName, approvedProvider, CngKeyOpenOptions.None);
try
{
if (key.AlgorithmGroup != CngAlgorithmGroup.Rsa || key.IsMachineKey ||
key.KeySize != expectedBits || key.KeyUsage != CngKeyUsages.Signing ||
key.ExportPolicy != CngExportPolicies.None)
throw new CryptographicException("Existing key does not meet this example's policy.");
return key; // Caller must dispose it; this does not delete the persisted key.
}
catch { key.Dispose(); throw; }
}
}The caller must dispose both the returned CngKey and any RSACng wrapper when finished. Disposal releases handles; it is not key deletion. Metadata checks are useful but do not establish the key’s provenance: bind a known public-key identifier to the application and verify the provider, permissions and intended identity. Do not export a private key merely to compare it. [2]
Microsoft Platform Crypto Provider is the TPM-oriented provider named in the archive. Supported key lengths, algorithms, UI behavior and permissions are provider- and device-dependent; the example’s accepted sizes are not a claim that every TPM supports all of them. Machine-wide keys require an intentional machine-scope design and access controls. Treat permission, provider and duplicate-name failures as distinct deployment issues, not reasons to retry with weaker settings. [1][3][4]
Use the documented property contract
For CngProperty, consult the Windows key-storage property identifiers and each provider’s documentation rather than treating internal reference-source constants as a complete public contract. Length is a bit count; Key Usage and Export Policy are policy flags; some properties are read-only or provider-specific. A property name’s existence does not mean it can be set during creation or has the same meaning on every provider. The archived reference-source link remains below for historical context, not as the authoritative property specification. [3]
Primary references
- Microsoft CngKey.Create
- Microsoft CngKey
- Microsoft key-storage property identifiers
- Microsoft key storage and retrieval
Original links in historical context
Original links are retained for attribution. They do not endorse the old code; current availability was not verified.