Triky s Windows CNG API

Máj 2021

V tomto krátkom bloku popisujem dva triky, ktoré idú spraviť vo Windowsovom CNG Api (Cryptohraphy Next Generation) na C# kóde.

Použitie TPM

TPM (Trusted platform module) čip sa nachádza na stále viac notebookuoch a počítačoch, je to čip na ktorý sa dajú ukladať šifrovacie a prihlasovacie kľúče (napríklad Windows ich využíva na FIDO2 autentifikáciu). Pomocou Microsoft Platform Crypto Provider je možné vytvoriť kľúčový pár a k nemu certifikát, chránený pomocou TPM čipu.

using CngKey key = CngKey.Create(CngAlgorithm.Rsa,
      "KeyProtectedUsingTpm",
      new CngKeyCreationParameters()
      {
          ExportPolicy = CngExportPolicies.None,
          KeyCreationOptions = CngKeyCreationOptions.None,
          KeyUsage = CngKeyUsages.AllUsages,
          Provider = new CngProvider("Microsoft Platform Crypto Provider"),
          UIPolicy = new CngUIPolicy(CngUIProtectionLevels.ProtectKey)
      });

var cng = new RSACng(key);

CertificateRequest certificateRequest = new CertificateRequest("CN=ProtectedUsingTpm Example",
    cng,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1);
X509Certificate2 certificate = certificateRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(365));

using X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);

Kód vytvorí kľúčový pár chránený TPM čipom a používateľskou akciou, vytvorí k nemu self-signed certifikát a uloží ho do Windows certificate storu používateľa.

Zadanie PINu ku čipovej karte

Pomocou CNG API je možné programovo zadať PIN k čipovej karte, ktorý by si inak CSP provider pýtal pomocou dialógu.

CmartCard PIN dialog

string thumbprint = "B6A2EC31AC1B48F7569BD5AF91CEBD2622F462E3";
string pin = "123456789";

using X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
X509Certificate2 cert = collection[0];

using RSA rsa = cert.GetRSAPrivateKey();
RSACng rsaCng = rsa as RSACng;

byte[] propertyBytes = Encoding.Unicode.GetBytes($"{pin}\0");
const string PIN_PROPERTY = "SmartCardPin";
CngProperty pinProperty = new CngProperty(
   PIN_PROPERTY,
   propertyBytes,
   CngPropertyOptions.None);
rsaCng.Key.SetProperty(pinProperty);

byte[] data = Encoding.UTF8.GetBytes("Hello World!");
byte[] signature = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);

Console.WriteLine("Signature {0}", Convert.ToBase64String(signature));

Kód si zo storu certifikátov vytiahne príslušný certifikát podla thumbprintu. Jeho privátnemu kľúču nastaví PIN a podpíše ním dáta.