Skip to content

Commit 1838c6b

Browse files
Implemented ECDSA public/private keys and tests.
1 parent 6328a54 commit 1838c6b

17 files changed

+1865
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2020 ONIXLabs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Security.Cryptography;
16+
using Xunit;
17+
18+
namespace OnixLabs.Security.Cryptography.UnitTests;
19+
20+
public sealed class EcdsaKeyTests
21+
{
22+
[Fact(DisplayName = "ECDSA sign and verify with two identical keys should succeed")]
23+
public void EcdsaSignAndVerifyWithTwoIdenticalKeysShouldSucceed()
24+
{
25+
// Given
26+
byte[] data = Salt.CreateNonZero(2048).ToByteArray();
27+
HashAlgorithm algorithm = SHA256.Create();
28+
IEcdsaPrivateKey privateKey1 = EcdsaPrivateKey.Create();
29+
IEcdsaPrivateKey privateKey2 = new EcdsaPrivateKey(privateKey1.ToByteArray());
30+
IEcdsaPublicKey publicKey1 = privateKey1.GetPublicKey();
31+
IEcdsaPublicKey publicKey2 = privateKey2.GetPublicKey();
32+
33+
// When
34+
DigitalSignature signature1 = new(privateKey1.SignData(data, algorithm));
35+
DigitalSignature signature2 = new(privateKey2.SignData(data, algorithm));
36+
37+
// Then
38+
Assert.True(publicKey1.IsDataValid(signature1, data, algorithm));
39+
Assert.True(publicKey1.IsDataValid(signature2, data, algorithm));
40+
Assert.True(publicKey2.IsDataValid(signature1, data, algorithm));
41+
Assert.True(publicKey2.IsDataValid(signature2, data, algorithm));
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2020 ONIXLabs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Security.Cryptography;
16+
17+
namespace OnixLabs.Security.Cryptography;
18+
19+
public sealed partial class EcdsaPrivateKey
20+
{
21+
/// <summary>
22+
/// Creates a new ECDSA cryptographic private key.
23+
/// </summary>
24+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance.</returns>
25+
public static EcdsaPrivateKey Create()
26+
{
27+
using ECDsa key = ECDsa.Create();
28+
byte[] keyData = key.ExportECPrivateKey();
29+
return new EcdsaPrivateKey(keyData);
30+
}
31+
32+
/// <summary>
33+
/// Creates a new ECDSA cryptographic private key.
34+
/// </summary>
35+
/// <param name="curve">The elliptic curve from which to create a new ECDSA cryptographic private key.</param>
36+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance.</returns>
37+
public static EcdsaPrivateKey Create(ECCurve curve)
38+
{
39+
using ECDsa key = ECDsa.Create(curve);
40+
byte[] keyData = key.ExportECPrivateKey();
41+
return new EcdsaPrivateKey(keyData);
42+
}
43+
44+
/// <summary>
45+
/// Creates a new ECDSA cryptographic private key.
46+
/// </summary>
47+
/// <param name="parameters">The elliptic curve parameters from which to create a new ECDSA cryptographic private key.</param>
48+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance.</returns>
49+
public static EcdsaPrivateKey Create(ECParameters parameters)
50+
{
51+
using ECDsa key = ECDsa.Create(parameters);
52+
byte[] keyData = key.ExportECPrivateKey();
53+
return new EcdsaPrivateKey(keyData);
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2020 ONIXLabs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Security.Cryptography;
17+
18+
namespace OnixLabs.Security.Cryptography;
19+
20+
public sealed partial class EcdsaPrivateKey
21+
{
22+
/// <summary>
23+
/// Exports the ECDSA cryptographic private key data in PKCS #8 format.
24+
/// </summary>
25+
/// <returns>Returns a new <see cref="T:Byte[]"/> instance containing the ECDSA cryptographic private key data in PKCS #8 format.</returns>
26+
public override byte[] ExportPkcs8PrivateKey()
27+
{
28+
using ECDsa key = ImportKeyData();
29+
return key.ExportPkcs8PrivateKey();
30+
}
31+
32+
/// <summary>
33+
/// Exports the ECDSA cryptographic private key data in encrypted PKCS #8 format.
34+
/// </summary>
35+
/// <param name="password">The password to use for encryption.</param>
36+
/// <param name="parameters">The parameters required for password based encryption.</param>
37+
/// <returns>Returns a new <see cref="T:Byte[]"/> instance containing the ECDSA cryptographic private key data in PKCS #8 format.</returns>
38+
public override byte[] ExportPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters parameters)
39+
{
40+
using ECDsa key = ImportKeyData();
41+
return key.ExportEncryptedPkcs8PrivateKey(password, parameters);
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2020 ONIXLabs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Security.Cryptography;
16+
17+
namespace OnixLabs.Security.Cryptography;
18+
19+
public sealed partial class EcdsaPrivateKey
20+
{
21+
/// <summary>
22+
/// Gets the ECDSA cryptographic public key component from the current ECDSA cryptographic private key.
23+
/// </summary>
24+
/// <returns>Returns a new <see cref="EcdsaPublicKey"/> instance containing the ECDSA cryptographic public key component from the current ECDSA cryptographic private key.</returns>
25+
public override EcdsaPublicKey GetPublicKey()
26+
{
27+
using ECDsa key = ImportKeyData();
28+
byte[] keyData = key.ExportSubjectPublicKeyInfo();
29+
return new EcdsaPublicKey(keyData);
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2020 ONIXLabs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Security.Cryptography;
17+
18+
namespace OnixLabs.Security.Cryptography;
19+
20+
public sealed partial class EcdsaPrivateKey
21+
{
22+
/// <summary>
23+
/// Imports the ECDSA cryptographic private key data in PKCS #8 format.
24+
/// </summary>
25+
/// <param name="data">The cryptographic private key data to import.</param>
26+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance from the imported cryptographic private key data.</returns>
27+
public static EcdsaPrivateKey ImportPkcs8PrivateKey(ReadOnlySpan<byte> data)
28+
{
29+
return ImportPkcs8PrivateKey(data, out int _);
30+
}
31+
32+
/// <summary>
33+
/// Imports the ECDSA cryptographic private key data in PKCS #8 format.
34+
/// </summary>
35+
/// <param name="data">The cryptographic private key data to import.</param>
36+
/// <param name="bytesRead">The number of bytes read from the input data.</param>
37+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance from the imported cryptographic private key data.</returns>
38+
public static EcdsaPrivateKey ImportPkcs8PrivateKey(ReadOnlySpan<byte> data, out int bytesRead)
39+
{
40+
using ECDsa key = ECDsa.Create();
41+
key.ImportPkcs8PrivateKey(data, out bytesRead);
42+
byte[] keyData = key.ExportECPrivateKey();
43+
return new EcdsaPrivateKey(keyData);
44+
}
45+
46+
/// <summary>
47+
/// Imports the ECDSA cryptographic private key data in encrypted PKCS #8 format.
48+
/// </summary>
49+
/// <param name="data">The cryptographic private key data to import.</param>
50+
/// <param name="password">The password required for password based decryption.</param>
51+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance from the imported cryptographic private key data.</returns>
52+
public static EcdsaPrivateKey ImportPkcs8PrivateKey(ReadOnlySpan<byte> data, ReadOnlySpan<char> password)
53+
{
54+
return ImportPkcs8PrivateKey(data, password, out int _);
55+
}
56+
57+
/// <summary>
58+
/// Imports the ECDSA cryptographic private key data in encrypted PKCS #8 format.
59+
/// </summary>
60+
/// <param name="data">The cryptographic private key data to import.</param>
61+
/// <param name="password">The password required for password based decryption.</param>
62+
/// <param name="bytesRead">The number of bytes read from the input data.</param>
63+
/// <returns>Returns a new <see cref="EcdsaPrivateKey"/> instance from the imported cryptographic private key data.</returns>
64+
public static EcdsaPrivateKey ImportPkcs8PrivateKey(ReadOnlySpan<byte> data, ReadOnlySpan<char> password, out int bytesRead)
65+
{
66+
using ECDsa key = ECDsa.Create();
67+
key.ImportEncryptedPkcs8PrivateKey(password, data, out bytesRead);
68+
byte[] keyData = key.ExportECPrivateKey();
69+
return new EcdsaPrivateKey(keyData);
70+
}
71+
72+
/// <summary>
73+
/// Imports the key data into a new <see cref="ECDsa"/> instance.
74+
/// </summary>
75+
/// <returns>Returns a new <see cref="ECDsa"/> instance containing the imported key data.</returns>
76+
private ECDsa ImportKeyData()
77+
{
78+
ECDsa algorithm = ECDsa.Create();
79+
algorithm.ImportECPrivateKey(KeyData, out int _);
80+
return algorithm;
81+
}
82+
}

0 commit comments

Comments
 (0)