1.13.0 - April 2025 Release #215
Replies: 1 comment 5 replies
-
Edit, 2025-05-26: This post has been updated to correct an erroneous claim that the new key classes only supported newer YubiKeys, this is not the case. The new classes support all YubiKey firmware versions Cryptography Key Classes in Yubico .NET SDKThe Yubico .NET SDK has introduced a new key hierarchy to enhance key management, improve type safety, and support additional key types including standard RSA, EC, and Curve25519 keys. This guide provides comprehensive information on using these new classes with the PIV application. Overview of ChangesThe SDK is transitioning from the legacy
Key Type HierarchyAll keys implement either the
Available Key TypesThe SDK supports the following key types, accessible via the
Factory Methods for Key CreationRSA Public Keys// Create from PKCS#8 SubjectPublicKeyInfo format
byte[] encodedKey = /* your SubjectPublicKeyInfo bytes */;
IPublicKey rsaPublicKey = RSAPublicKey.CreateFromSubjectPublicKeyInfo(encodedKey);
// Create from parameters
RSAParameters parameters = /* your RSA parameters */;
RSAPublicKey rsaPublicKey = RSAPublicKey.CreateFromParameters(parameters); RSA Private Keys// Create from PKCS#8 PrivateKeyInfo format
byte[] encodedKey = /* your PKCS#8 PrivateKeyInfo bytes */;
RSAPrivateKey rsaPrivateKey = RSAPrivateKey.CreateFromPkcs8(encodedKey);
// Create from parameters
RSAParameters parameters = /* your RSA parameters */;
RSAPrivateKey rsaPrivateKey = RSAPrivateKey.CreateFromParameters(parameters); EC Public Keys// Create from PKCS#8 SubjectPublicKeyInfo format
byte[] encodedKey = /* your SubjectPublicKeyInfo bytes */;
IPublicKey ecPublicKey = ECPublicKey.CreateFromSubjectPublicKeyInfo(encodedKey);
// Create from EC parameters
ECParameters parameters = /* your EC parameters */;
ECPublicKey ecPublicKey = ECPublicKey.CreateFromParameters(parameters);
// Create from public point (0x04 || X-coordinate || Y-coordinate)
ReadOnlyMemory<byte> publicPoint = /* uncompressed EC point with 0x04 prefix */;
IPublicKey ecPublicKey = ECPublicKey.CreateFromValue(publicPoint, KeyType.ECP256); EC Private Keys// Create from PKCS#8 PrivateKeyInfo format
byte[] encodedKey = /* your PKCS#8 PrivateKeyInfo bytes */;
ECPrivateKey ecPrivateKey = ECPrivateKey.CreateFromPkcs8(encodedKey);
// Create from EC parameters
ECParameters parameters = /* your EC parameters with D value */;
ECPrivateKey ecPrivateKey = ECPrivateKey.CreateFromParameters(parameters);
// Create from private scalar value
ReadOnlyMemory<byte> privateValue = /* your private scalar value */;
ECPrivateKey ecPrivateKey = ECPrivateKey.CreateFromValue(privateValue, KeyType.ECP256); Curve25519 Public Keys// Create from PKCS#8 SubjectPublicKeyInfo format
byte[] encodedKey = /* your SubjectPublicKeyInfo bytes */;
Curve25519PublicKey curve25519PublicKey = Curve25519PublicKey.CreateFromSubjectPublicKeyInfo(encodedKey);
// Create from public point bytes
ReadOnlyMemory<byte> publicPoint = /* your public point bytes */;
Curve25519PublicKey curve25519PublicKey = Curve25519PublicKey.CreateFromValue(publicPoint, KeyType.Ed25519);
// Or for X25519
Curve25519PublicKey x25519PublicKey = Curve25519PublicKey.CreateFromValue(publicPoint, KeyType.X25519); Curve25519 Private Keys// Create from PKCS#8 PrivateKeyInfo format
byte[] encodedKey = /* your PKCS#8 PrivateKeyInfo bytes */;
Curve25519PrivateKey curve25519PrivateKey = Curve25519PrivateKey.CreateFromPkcs8(encodedKey);
// Create from private scalar value
ReadOnlyMemory<byte> privateKey = /* your private key bytes */;
Curve25519PrivateKey ed25519PrivateKey = Curve25519PrivateKey.CreateFromValue(privateKey, KeyType.Ed25519);
// Or for X25519
Curve25519PrivateKey x25519PrivateKey = Curve25519PrivateKey.CreateFromValue(privateKey, KeyType.X25519); Using with PIV SessionGenerating Key PairsThe using Yubico.YubiKey;
using Yubico.YubiKey.Piv;
using Yubico.YubiKey.Cryptography;
using var pivSession = new PivSession(yubiKey)
// Setup key collector
pivSession.KeyCollector = yourKeyCollector;
// Authenticate with management key
pivSession.AuthenticateManagementKey();
// Generate an Ed25519 key pair
IPublicKey publicKey = pivSession.GenerateKeyPair(
PivSlot.Authentication,
KeyType.Ed25519,
PivPinPolicy.Once,
PivTouchPolicy.Never);
// Check the returned key type
if (publicKey is Curve25519PublicKey ed25519PublicKey)
{
// Access the public point
ReadOnlyMemory<byte> publicPoint = ed25519PublicKey.PublicPoint;
// Export the key in SubjectPublicKeyInfo format
byte[] exportedKey = ed25519PublicKey.ExportSubjectPublicKeyInfo();
} Importing Private KeysImport private keys with the // Create a private key to import
byte[] pkcs8EncodedKey = /* Load PKCS#8 private key */;
IPrivateKey privateKey = Curve25519PrivateKey.CreateFromPkcs8(pkcs8EncodedKey);
// Import into the YubiKey
using var pivSession = new PivSession(yubiKey)
pivSession.KeyCollector = yourKeyCollector;
pivSession.AuthenticateManagementKey();
pivSession.ImportPrivateKey(
PivSlot.KeyManagement,
privateKey,
PivPinPolicy.Once,
PivTouchPolicy.Never); Key Agreement with X25519Perform key agreement operations with X25519 keys: // Generate or import an X25519 key
using var pivSession = new PivSession(yubiKey)
// Setup and authenticate
pivSession.KeyCollector = yourKeyCollector;
pivSession.VerifyPin(); // Required for cryptographic operations
// Get other party's public key
byte[] otherPartyPublicKeyBytes = /* Other party's X25519 public key */;
// Create a key agreement object (details depend on your implementation)
// This is a simplified example
Memory<byte> sharedSecret = new byte[32];
pivSession.KeyAgree(
PivSlot.KeyManagement, // Slot containing your private key
otherPartyPublicKeyBytes,
sharedSecret);
// Use the shared secret for key derivation or encryption Exporting KeysExport keys in standard formats: // Export public key in SubjectPublicKeyInfo format
byte[] spki = ecPublicKey.ExportSubjectPublicKeyInfo();
// Export private key in PKCS#8 PrivateKeyInfo format
byte[] pkcs8 = ecPrivateKey.ExportPkcs8PrivateKey(); Handling Key Data SecurelyAll private key classes implement secure cleanup methods: // Using disposable pattern to ensure sensitive data is cleared
using (ECPrivateKey privateKey = ECPrivateKey.CreateFromPkcs8(encodedKey))
{
// Use the private key
}
// The private key data is securely cleared from memory after disposal // Using try-finally and clearing explicityly
try
{
ECPrivateKey privateKey = ECPrivateKey.CreateFromPkcs8(encodedKey);
// Use the private key
}
finally
{
// Ensure sensitive data is cleared
privateKey.Clear();
} Migration GuideThe old PIV key types will still function, but are deprecated. The new classes are designed to be more usable and they support the new key types. Most users will find the new keys and their factory methods easy to use.
These new key classes provide a more robust, type-safe approach to cryptographic operations with YubiKeys, while supporting modern key types like Ed25519 and X25519. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Release date: April 9th, 2025
Features:
Curve25519 support has been added for PIV #210:
Keys can now be imported or generated using the Ed25519 and X25519 algorithms.
The key agreement operation can be performed with an X25519 key.
Digital signatures can now be created with a Ed25519 key.
New related unit tests have been added.
Unit tests have been added for RSA-3072 and RSA-4096 keys #197.
Support for large APDUs has been improved #208:
When sending large APDU commands to a YubiKey via the smartcard connection, the CommandChainingTransform will now throw an exception when the cumulative APDU data (sent in chunks of up to 255 bytes) exceeds the max APDU size for the given YubiKey (varies based on firmware version; see SmartCardMaxApduSizes).
Support for Ed25519 and P384 credentials has been added for FIDO #186.
Ubuntu runners have been upgraded from version 20.04 to 22.04 to support the compilation of Yubico.NativeShims #188.
Bug Fixes:
The default logger now only writes output for the "Error" log level unless another level is specified #185. Previously, the logger wrote output for all log levels, which could become overly long and difficult to evaluate.
Miscellaneous:
The License was updated to remove the information for the AesCmac.cs file from the Bouncy Castle library #196.
What's changed
New Contributors
Full Changelog: 1.12.1...1.13.0
This discussion was created from the release 1.13.0.
Beta Was this translation helpful? Give feedback.
All reactions