Skip to content

Commit f5486b5

Browse files
committed
Update KeyExchangeMLKem768X25519Sha256 and KeyExchangeSNtruP761X25519Sha512
1 parent f6e2486 commit f5486b5

File tree

4 files changed

+73
-38
lines changed

4 files changed

+73
-38
lines changed

src/Renci.SshNet/Security/KeyExchangeECCurve25519.BouncyCastleImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Renci.SshNet.Security
88
{
99
internal partial class KeyExchangeECCurve25519
1010
{
11-
private sealed class BouncyCastleImpl : Impl
11+
protected internal sealed class BouncyCastleImpl : Impl
1212
{
1313
private X25519Agreement _keyAgreement;
1414

src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Renci.SshNet.Security
66
{
7-
internal sealed partial class KeyExchangeECCurve25519 : KeyExchangeEC
7+
internal partial class KeyExchangeECCurve25519 : KeyExchangeEC
88
{
99
#if NET
1010
private Impl _impl;

src/Renci.SshNet/Security/KeyExchangeMLKem768X25519Sha256.cs

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Globalization;
22
using System.Linq;
33

4-
using Org.BouncyCastle.Crypto.Agreement;
54
using Org.BouncyCastle.Crypto.Generators;
65
using Org.BouncyCastle.Crypto.Kems;
76
using Org.BouncyCastle.Crypto.Parameters;
@@ -12,10 +11,14 @@
1211

1312
namespace Renci.SshNet.Security
1413
{
15-
internal sealed class KeyExchangeMLKem768X25519Sha256 : KeyExchangeEC
14+
internal sealed class KeyExchangeMLKem768X25519Sha256 : KeyExchangeECCurve25519
1615
{
1716
private MLKemDecapsulator _mlkemDecapsulator;
18-
private X25519Agreement _x25519Agreement;
17+
#if NET
18+
private Impl _impl;
19+
#else
20+
private BouncyCastleImpl _impl;
21+
#endif
1922

2023
/// <summary>
2124
/// Gets algorithm name.
@@ -52,15 +55,20 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
5255
_mlkemDecapsulator = new MLKemDecapsulator(MLKemParameters.ml_kem_768);
5356
_mlkemDecapsulator.Init(mlkem768KeyPair.Private);
5457

55-
var x25519KeyPairGenerator = new X25519KeyPairGenerator();
56-
x25519KeyPairGenerator.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));
57-
var x25519KeyPair = x25519KeyPairGenerator.GenerateKeyPair();
58-
59-
_x25519Agreement = new X25519Agreement();
60-
_x25519Agreement.Init(x25519KeyPair.Private);
61-
6258
var mlkem768PublicKey = ((MLKemPublicKeyParameters)mlkem768KeyPair.Public).GetEncoded();
63-
var x25519PublicKey = ((X25519PublicKeyParameters)x25519KeyPair.Public).GetEncoded();
59+
#if NET
60+
if (System.OperatingSystem.IsWindowsVersionAtLeast(10))
61+
{
62+
var curve = System.Security.Cryptography.ECCurve.CreateFromFriendlyName("Curve25519");
63+
_impl = new BclImpl(curve);
64+
}
65+
else
66+
#endif
67+
{
68+
_impl = new BouncyCastleImpl();
69+
}
70+
71+
var x25519PublicKey = _impl.GenerateClientECPoint();
6472

6573
_clientExchangeValue = mlkem768PublicKey.Concat(x25519PublicKey);
6674

@@ -114,21 +122,31 @@ private void HandleServerHybridReply(byte[] hostKey, byte[] serverExchangeValue,
114122
_hostKey = hostKey;
115123
_signature = signature;
116124

117-
if (serverExchangeValue.Length != _mlkemDecapsulator.EncapsulationLength + _x25519Agreement.AgreementSize)
125+
if (serverExchangeValue.Length != _mlkemDecapsulator.EncapsulationLength + X25519PublicKeyParameters.KeySize)
118126
{
119127
throw new SshConnectionException(
120128
string.Format(CultureInfo.CurrentCulture, "Bad S_Reply length: {0}.", serverExchangeValue.Length),
121129
DisconnectReason.KeyExchangeFailed);
122130
}
123131

124-
var secret = new byte[_mlkemDecapsulator.SecretLength + _x25519Agreement.AgreementSize];
132+
var mlkemSecret = new byte[_mlkemDecapsulator.SecretLength];
125133

126-
_mlkemDecapsulator.Decapsulate(serverExchangeValue, 0, _mlkemDecapsulator.EncapsulationLength, secret, 0, _mlkemDecapsulator.SecretLength);
134+
_mlkemDecapsulator.Decapsulate(serverExchangeValue, 0, _mlkemDecapsulator.EncapsulationLength, mlkemSecret, 0, _mlkemDecapsulator.SecretLength);
127135

128-
var x25519PublicKey = new X25519PublicKeyParameters(serverExchangeValue, _mlkemDecapsulator.EncapsulationLength);
129-
_x25519Agreement.CalculateAgreement(x25519PublicKey, secret, _mlkemDecapsulator.SecretLength);
136+
var x25519Agreement = _impl.CalculateAgreement(serverExchangeValue.Take(_mlkemDecapsulator.EncapsulationLength, X25519PublicKeyParameters.KeySize));
130137

131-
SharedKey = CryptoAbstraction.HashSHA256(secret);
138+
SharedKey = mlkemSecret.Concat(x25519Agreement);
139+
}
140+
141+
/// <inheritdoc/>
142+
protected override void Dispose(bool disposing)
143+
{
144+
base.Dispose(disposing);
145+
146+
if (disposing)
147+
{
148+
_impl?.Dispose();
149+
}
132150
}
133151
}
134152
}

src/Renci.SshNet/Security/KeyExchangeSNtruP761X25519Sha512.cs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
using System;
2-
using System.Globalization;
1+
using System.Globalization;
32
using System.Linq;
43

5-
using Org.BouncyCastle.Crypto.Agreement;
6-
using Org.BouncyCastle.Crypto.Generators;
74
using Org.BouncyCastle.Crypto.Parameters;
85
using Org.BouncyCastle.Pqc.Crypto.NtruPrime;
96

@@ -13,10 +10,14 @@
1310

1411
namespace Renci.SshNet.Security
1512
{
16-
internal sealed class KeyExchangeSNtruP761X25519Sha512 : KeyExchangeEC
13+
internal sealed class KeyExchangeSNtruP761X25519Sha512 : KeyExchangeECCurve25519
1714
{
1815
private SNtruPrimeKemExtractor _sntrup761Extractor;
19-
private X25519Agreement _x25519Agreement;
16+
#if NET
17+
private Impl _impl;
18+
#else
19+
private BouncyCastleImpl _impl;
20+
#endif
2021

2122
/// <summary>
2223
/// Gets algorithm name.
@@ -52,15 +53,22 @@ public override void Start(Session session, KeyExchangeInitMessage message, bool
5253

5354
_sntrup761Extractor = new SNtruPrimeKemExtractor((SNtruPrimePrivateKeyParameters)sntrup761KeyPair.Private);
5455

55-
var x25519KeyPairGenerator = new X25519KeyPairGenerator();
56-
x25519KeyPairGenerator.Init(new X25519KeyGenerationParameters(CryptoAbstraction.SecureRandom));
57-
var x25519KeyPair = x25519KeyPairGenerator.GenerateKeyPair();
56+
var sntrup761PublicKey = ((SNtruPrimePublicKeyParameters)sntrup761KeyPair.Public).GetEncoded();
57+
#if NET
58+
if (System.OperatingSystem.IsWindowsVersionAtLeast(10))
59+
{
60+
var curve = System.Security.Cryptography.ECCurve.CreateFromFriendlyName("Curve25519");
61+
_impl = new BclImpl(curve);
62+
}
63+
else
64+
#endif
65+
{
66+
_impl = new BouncyCastleImpl();
67+
}
5868

59-
_x25519Agreement = new X25519Agreement();
60-
_x25519Agreement.Init(x25519KeyPair.Private);
69+
var x25519PublicKey = _impl.GenerateClientECPoint();
6170

62-
var sntrup761PublicKey = ((SNtruPrimePublicKeyParameters)sntrup761KeyPair.Public).GetEncoded();
63-
var x25519PublicKey = ((X25519PublicKeyParameters)x25519KeyPair.Public).GetEncoded();
71+
_clientExchangeValue = sntrup761PublicKey.Concat(x25519PublicKey);
6472

6573
_clientExchangeValue = sntrup761PublicKey.Concat(x25519PublicKey);
6674

@@ -122,14 +130,23 @@ private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, b
122130
}
123131

124132
var sntrup761CipherText = serverExchangeValue.Take(_sntrup761Extractor.EncapsulationLength);
125-
var secret = _sntrup761Extractor.ExtractSecret(sntrup761CipherText);
126-
var sntrup761SecretLength = secret.Length;
127133

128-
var x25519PublicKey = new X25519PublicKeyParameters(serverExchangeValue, _sntrup761Extractor.EncapsulationLength);
129-
Array.Resize(ref secret, sntrup761SecretLength + _x25519Agreement.AgreementSize);
130-
_x25519Agreement.CalculateAgreement(x25519PublicKey, secret, sntrup761SecretLength);
134+
var sntrup761Secret = _sntrup761Extractor.ExtractSecret(sntrup761CipherText);
135+
136+
var x25519Agreement = _impl.CalculateAgreement(serverExchangeValue.Take(_sntrup761Extractor.EncapsulationLength, X25519PublicKeyParameters.KeySize));
131137

132-
SharedKey = CryptoAbstraction.HashSHA512(secret);
138+
SharedKey = CryptoAbstraction.HashSHA512(sntrup761Secret.Concat(x25519Agreement));
139+
}
140+
141+
/// <inheritdoc/>
142+
protected override void Dispose(bool disposing)
143+
{
144+
base.Dispose(disposing);
145+
146+
if (disposing)
147+
{
148+
_impl?.Dispose();
149+
}
133150
}
134151
}
135152
}

0 commit comments

Comments
 (0)