Skip to content

Commit 792a5b8

Browse files
committed
improved documentation, minor refactorings,
1 parent 6375336 commit 792a5b8

14 files changed

+216
-113
lines changed

Yubico.Core/src/Yubico/Core/Tlv/TlvObject.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class TlvObject
3131
public int Tag { get; }
3232

3333
/// <summary>
34-
/// Returns the value.
34+
/// Returns a copy of the value.
3535
/// </summary>
3636
public Memory<byte> Value => _bytes.Skip(_offset).Take(Length).ToArray();
3737

Yubico.YubiKey/src/Yubico/YubiKey/Cryptography/Curve25519PrivateKeyParameters.cs

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,61 @@ namespace Yubico.YubiKey.Cryptography;
2020

2121
public class Curve25519PrivateKeyParameters : IPrivateKeyParameters
2222
{
23-
private KeyDefinition _keyDefinition { get; }
2423
private readonly Memory<byte> _privateKey;
24+
25+
public KeyDefinition KeyDefinition { get; }
26+
public KeyType KeyType => KeyDefinition.KeyType;
27+
public ReadOnlyMemory<byte> PrivateKey => _privateKey;
28+
2529
private Curve25519PrivateKeyParameters(
2630
ReadOnlyMemory<byte> privateKey,
27-
KeyDefinition keyDefinition)
31+
KeyType keyType)
2832
{
33+
var keyDefinition = keyType.GetKeyDefinition();
2934
if (keyDefinition.AlgorithmOid == KeyDefinitions.CryptoOids.X25519)
3035
{
3136
AsnUtilities.VerifyX25519PrivateKey(privateKey.Span);
3237
}
3338

3439
_privateKey = new byte[privateKey.Length];
35-
_keyDefinition = keyDefinition;
40+
KeyDefinition = keyDefinition;
3641

3742
privateKey.CopyTo(_privateKey);
3843
}
3944

45+
/// <summary>
46+
/// Exports the private key in PKCS#8 DER encoded format.
47+
/// </summary>
48+
/// <returns>The DER encoded private key.</returns>
4049
public byte[] ExportPkcs8PrivateKey() => AsnPrivateKeyWriter.EncodeToPkcs8(_privateKey, KeyType);
41-
public KeyDefinition KeyDefinition => _keyDefinition;
42-
public KeyType KeyType => _keyDefinition.KeyType;
43-
public ReadOnlyMemory<byte> PrivateKey => _privateKey;
50+
51+
/// <summary>
52+
/// Clears the private key.
53+
/// </summary>
54+
/// <remarks>
55+
/// This method securely zeroes out the private key data.
56+
/// </remarks>
4457
public void Clear() => CryptographicOperations.ZeroMemory(_privateKey.Span);
4558

59+
/// <summary>
60+
/// Creates an instance of <see cref="Curve25519PrivateKeyParameters"/> from a PKCS#8
61+
/// DER-encoded private key.
62+
/// </summary>
63+
/// <param name="encodedKey">
64+
/// The DER-encoded private key.
65+
/// </param>
66+
/// <returns>
67+
/// A new instance of <see cref="Curve25519PrivateKeyParameters"/>.
68+
/// </returns>
69+
/// <exception cref="ArgumentException">
70+
/// Thrown if the algorithm OID is not X25519 or Ed25519.
71+
/// </exception>
72+
/// <exception cref="CryptographicException">
73+
/// Thrown if the private key is invalid.
74+
/// </exception>
4675
public static Curve25519PrivateKeyParameters CreateFromPkcs8(ReadOnlyMemory<byte> encodedKey)
4776
{
4877
var reader = new AsnReader(encodedKey, AsnEncodingRules.DER);
49-
5078
var seqPrivateKeyInfo = reader.ReadSequence();
5179
var version = seqPrivateKeyInfo.ReadInteger();
5280
if (version != 0)
@@ -55,16 +83,17 @@ public static Curve25519PrivateKeyParameters CreateFromPkcs8(ReadOnlyMemory<byte
5583
}
5684

5785
var seqAlgorithmIdentifier = seqPrivateKeyInfo.ReadSequence();
58-
string oidAlgorithm = seqAlgorithmIdentifier.ReadObjectIdentifier();
59-
if (oidAlgorithm != KeyDefinitions.CryptoOids.X25519 &&
60-
oidAlgorithm != KeyDefinitions.CryptoOids.Ed25519)
86+
string algorithmOid = seqAlgorithmIdentifier.ReadObjectIdentifier();
87+
if (algorithmOid != KeyDefinitions.CryptoOids.X25519 &&
88+
algorithmOid != KeyDefinitions.CryptoOids.Ed25519)
6189
{
6290
throw new ArgumentException(
6391
"Invalid curve OID. Must be: " + KeyDefinitions.CryptoOids.X25519 + " or " +
6492
KeyDefinitions.CryptoOids.Ed25519);
6593
}
6694

67-
var seqPrivateKey = new AsnReader(seqPrivateKeyInfo.ReadOctetString(), AsnEncodingRules.DER);
95+
using var privateKeyDataHandle = new ZeroingMemoryHandle(seqPrivateKeyInfo.ReadOctetString());
96+
var seqPrivateKey = new AsnReader(privateKeyDataHandle.Data, AsnEncodingRules.DER);
6897
var tag = seqPrivateKey.PeekTag();
6998
if (tag.TagValue != 4 || tag.TagClass != TagClass.Universal)
7099
{
@@ -78,13 +107,17 @@ public static Curve25519PrivateKeyParameters CreateFromPkcs8(ReadOnlyMemory<byte
78107
throw new CryptographicException("Invalid Curve25519 private key: incorrect length");
79108
}
80109

81-
var keyDefinition = KeyDefinitions.GetByOid(oidAlgorithm);
82-
return new Curve25519PrivateKeyParameters(privateKeyHandle.Data, keyDefinition);
110+
var keyDefinition = KeyDefinitions.GetByOid(algorithmOid);
111+
return new Curve25519PrivateKeyParameters(privateKeyHandle.Data, keyDefinition.KeyType);
83112

84113
}
85-
public static Curve25519PrivateKeyParameters CreateFromValue(ReadOnlyMemory<byte> privateKey, KeyType keyType)
86-
{
87-
var keyDefinition = KeyDefinitions.GetByKeyType(keyType);
88-
return new Curve25519PrivateKeyParameters(privateKey, keyDefinition);
89-
}
114+
115+
/// <summary>
116+
/// Creates an instance of <see cref="Curve25519PrivateKeyParameters"/> from the given
117+
/// <paramref name="privateKey"/> and <paramref name="keyType"/>.
118+
/// </summary>
119+
/// <param name="privateKey">The raw private key data.</param>
120+
/// <param name="keyType">The type of key this is.</param>
121+
/// <returns>An instance of <see cref="Curve25519PrivateKeyParameters"/>.</returns>
122+
public static Curve25519PrivateKeyParameters CreateFromValue(ReadOnlyMemory<byte> privateKey, KeyType keyType) => new(privateKey, keyType);
90123
}

Yubico.YubiKey/src/Yubico/YubiKey/Cryptography/Curve25519PublicKeyParameters.cs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,43 @@ namespace Yubico.YubiKey.Cryptography;
2121

2222
public class Curve25519PublicKeyParameters : IPublicKeyParameters
2323
{
24-
private KeyDefinition _keyDefinition { get; }
2524
private readonly Memory<byte> _publicPoint;
26-
public KeyType KeyType => _keyDefinition.KeyType;
27-
public KeyDefinition KeyDefinition => _keyDefinition;
25+
26+
public KeyDefinition KeyDefinition { get; }
27+
public KeyType KeyType => KeyDefinition.KeyType;
2828
public ReadOnlyMemory<byte> PublicPoint => _publicPoint;
2929

3030
private Curve25519PublicKeyParameters(
3131
ReadOnlyMemory<byte> publicPoint,
3232
KeyDefinition keyDefinition)
3333
{
34-
_keyDefinition = keyDefinition;
34+
KeyDefinition = keyDefinition;
3535
_publicPoint = new byte[publicPoint.Length];
3636

3737
publicPoint.CopyTo(_publicPoint);
3838
}
39-
39+
40+
/// <summary>
41+
/// Converts this public key to an ASN.1 DER encoded format (X.509 SubjectPublicKeyInfo).
42+
/// </summary>
43+
/// <returns>
44+
/// A byte array containing the ASN.1 DER encoded public key.
45+
/// </returns>
4046
public byte[] ExportSubjectPublicKeyInfo() =>
41-
AsnPublicKeyWriter.EncodeToSubjectPublicKeyInfo(_publicPoint, _keyDefinition.KeyType);
47+
AsnPublicKeyWriter.EncodeToSubjectPublicKeyInfo(_publicPoint, KeyDefinition.KeyType);
4248

49+
/// <summary>
50+
/// Creates a new instance of <see cref="Curve25519PublicKeyParameters"/> from a DER-encoded public key.
51+
/// </summary>
52+
/// <param name="encodedKey">
53+
/// The DER-encoded public key.
54+
/// </param>
55+
/// <returns>
56+
/// A new instance of <see cref="Curve25519PublicKeyParameters"/>.
57+
/// </returns>
58+
/// <exception cref="CryptographicException">
59+
/// Thrown if the public key is invalid.
60+
/// </exception>
4361
public static Curve25519PublicKeyParameters CreateFromPkcs8(ReadOnlyMemory<byte> encodedKey)
4462
{
4563
var reader = new AsnReader(encodedKey, AsnEncodingRules.DER);
@@ -57,17 +75,27 @@ public static Curve25519PublicKeyParameters CreateFromPkcs8(ReadOnlyMemory<byte>
5775
return CreateFromValue(subjectPublicKey, keyType);
5876
}
5977

60-
public static Curve25519PublicKeyParameters CreateFromValue(ReadOnlyMemory<byte> publicKey, KeyType keyType)
78+
/// <summary>
79+
/// Creates an instance of <see cref="Curve25519PublicKeyParameters"/> from the given
80+
/// <paramref name="publicPoint"/> and <paramref name="keyType"/>.
81+
/// </summary>
82+
/// <param name="publicPoint">The raw public key data, formatted as an compressed point.</param>
83+
/// <param name="keyType">The type of key this is.</param>
84+
/// <returns>An instance of <see cref="Curve25519PublicKeyParameters"/>.</returns>
85+
/// <exception cref="ArgumentException">
86+
/// Thrown if the public key data length is not valid.
87+
/// </exception>
88+
public static Curve25519PublicKeyParameters CreateFromValue(ReadOnlyMemory<byte> publicPoint, KeyType keyType)
6189
{
6290
var keyDefinition = KeyDefinitions.GetByKeyType(keyType);
63-
if (publicKey.Length != keyDefinition.LengthInBytes)
91+
if (publicPoint.Length != keyDefinition.LengthInBytes)
6492
{
6593
throw new ArgumentException(
6694
string.Format(
6795
CultureInfo.CurrentCulture,
6896
ExceptionMessages.InvalidPublicKeyData));
6997
}
7098

71-
return new Curve25519PublicKeyParameters(publicKey, keyDefinition);
99+
return new Curve25519PublicKeyParameters(publicPoint, keyDefinition);
72100
}
73101
}

Yubico.YubiKey/src/Yubico/YubiKey/Cryptography/ECKeyParameters.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

Yubico.YubiKey/src/Yubico/YubiKey/Cryptography/ECPrivateKeyParameters.cs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,12 @@ namespace Yubico.YubiKey.Cryptography
2424
/// <remarks>
2525
/// This class encapsulates the parameters specific to EC private keys and
2626
/// contains the necessary private key data.
27-
/// It extends the base <see cref="ECKeyParameters"/> class with additional validation for private key components.
2827
/// </remarks>
2928
public class ECPrivateKeyParameters : IPrivateKeyParameters
3029
{
3130
public ECParameters Parameters { get; }
3231
public KeyDefinition KeyDefinition { get; }
3332
public KeyType KeyType => KeyDefinition.KeyType;
34-
public ReadOnlyMemory<byte> PrivateKey => Parameters.D.ToArray();
3533

3634
/// <summary>
3735
/// Initializes a new instance of the <see cref="ECPrivateKeyParameters"/> class.
@@ -49,7 +47,7 @@ public ECPrivateKeyParameters(ECParameters parameters)
4947
{
5048
throw new ArgumentException("Parameters must contain private key data (D value)", nameof(parameters));
5149
}
52-
50+
5351
Parameters = parameters.DeepCopy();
5452
KeyDefinition = KeyDefinitions.GetByOid(parameters.Curve.Oid);
5553
}
@@ -62,7 +60,6 @@ public ECPrivateKeyParameters(ECParameters parameters)
6260
/// </remarks>
6361
/// <param name="ecdsaObject">The ECDsa object.</param>
6462
[Obsolete("Use factory methods instead")]
65-
// TODO The constructor should be private, but not possible to have to constructors with the same signature
6663
public ECPrivateKeyParameters(ECDsa ecdsaObject)
6764
{
6865
if (ecdsaObject == null)
@@ -73,7 +70,7 @@ public ECPrivateKeyParameters(ECDsa ecdsaObject)
7370
Parameters = ecdsaObject.ExportParameters(true);
7471
KeyDefinition = KeyDefinitions.GetByOid(Parameters.Curve.Oid);
7572
}
76-
73+
7774
public byte[] ExportPkcs8PrivateKey() => AsnPrivateKeyWriter.EncodeToPkcs8(Parameters);
7875

7976
public void Clear()
@@ -83,37 +80,62 @@ public void Clear()
8380
CryptographicOperations.ZeroMemory(Parameters.D);
8481
}
8582

83+
/// <summary>
84+
/// Creates a new instance of <see cref="ECPrivateKeyParameters"/> from a DER-encoded private key.
85+
/// </summary>
86+
/// <param name="encodedKey">
87+
/// The DER-encoded private key.
88+
/// </param>
89+
/// <returns>
90+
/// A new instance of <see cref="ECPrivateKeyParameters"/>.
91+
/// </returns>
92+
/// <exception cref="CryptographicException">
93+
/// Thrown if the private key is invalid.
94+
/// </exception>
8695
public static ECPrivateKeyParameters CreateFromPkcs8(ReadOnlyMemory<byte> encodedKey)
8796
{
8897
var parameters = AsnPrivateKeyReader.CreateECParameters(encodedKey);
8998
return CreateFromParameters(parameters);
9099
}
100+
91101
#pragma warning disable CS0618 // Type or member is obsolete.
92102
public static ECPrivateKeyParameters CreateFromParameters(ECParameters parameters) => new(parameters);
93103
#pragma warning restore CS0618 // Type or member is obsolete
104+
105+
/// <summary>
106+
/// Creates a new instance of <see cref="ECPrivateKeyParameters"/> from the given
107+
/// <paramref name="privateValue"/> and <paramref name="keyType"/>.
108+
/// </summary>
109+
/// <remarks>
110+
/// The <paramref name="privateValue"/> is taken as the raw private key data (scalar value).
111+
/// </remarks>
112+
/// <param name="privateValue">The raw private key data.</param>
113+
/// <param name="keyType">The type of key this is.</param>
114+
/// <returns>A new instance of <see cref="ECPrivateKeyParameters"/>.</returns>
115+
/// <exception cref="ArgumentException">
116+
/// Thrown if the key type is not a valid EC key.
117+
/// </exception>
94118
public static ECPrivateKeyParameters CreateFromValue(
95119
ReadOnlyMemory<byte> privateValue,
96120
KeyType keyType)
97121
{
98-
if (keyType != KeyType.P256 &&
99-
keyType != KeyType.P384 &&
100-
keyType != KeyType.P521)
122+
var keyDefinition = keyType.GetKeyDefinition();
123+
if (keyDefinition.AlgorithmOid is not KeyDefinitions.CryptoOids.ECDSA)
101124
{
102-
throw new ArgumentOutOfRangeException(nameof(keyType), keyType, null);
125+
throw new ArgumentException("Only P-256, P-384 and P-521 are supported.", nameof(keyType));
103126
}
104127

105-
var keyDefinition = KeyDefinitions.GetByKeyType(keyType);
106-
string oidValue = keyDefinition.CurveOid ?? throw new ArgumentException("Curve OID is null.");
128+
string curveOid = keyDefinition.CurveOid ??
129+
throw new ArgumentException("The key definition for this key type has no Curve OID is null.");
107130

108-
var curve = ECCurve.CreateFromOid(new Oid(oidValue));
131+
var curve = ECCurve.CreateFromValue(curveOid);
109132
var parameters = new ECParameters
110133
{
111134
Curve = curve,
112135
D = privateValue.ToArray(),
113136
};
114137

115-
var ecdsa = ECDsa.Create(parameters);
116-
return CreateFromParameters(ecdsa.ExportParameters(true));
138+
return CreateFromParameters(parameters);
117139
}
118140
}
119141
}

0 commit comments

Comments
 (0)