Skip to content

Use System.Numerics.BigInteger #1469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,956 changes: 0 additions & 4,956 deletions src/Renci.SshNet/Common/BigInteger.cs

This file was deleted.

7 changes: 6 additions & 1 deletion src/Renci.SshNet/Common/DerData.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Numerics;

namespace Renci.SshNet.Common
{
Expand Down Expand Up @@ -96,7 +97,11 @@ public BigInteger ReadBigInteger()

var data = ReadBytes(length);

#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
return new BigInteger(data, isBigEndian: true);
#else
return new BigInteger(data.Reverse());
#endif
}

/// <summary>
Expand Down Expand Up @@ -213,7 +218,7 @@ public void Write(uint data)
/// <param name="data">BigInteger data to write.</param>
public void Write(BigInteger data)
{
var bytes = data.ToByteArray().Reverse();
var bytes = data.ToByteArray(isBigEndian: true);
_data.Add(Integer);
var length = GetLength(bytes.Length);
WriteBytes(length);
Expand Down
23 changes: 21 additions & 2 deletions src/Renci.SshNet/Common/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Text;

using Renci.SshNet.Abstractions;
Expand All @@ -14,7 +15,7 @@ namespace Renci.SshNet.Common
/// <summary>
/// Collection of different extension methods.
/// </summary>
internal static partial class Extensions
internal static class Extensions
{
internal static byte[] ToArray(this ServiceName serviceName)
{
Expand Down Expand Up @@ -45,26 +46,35 @@ internal static ServiceName ToServiceName(this byte[] data)

internal static BigInteger ToBigInteger(this byte[] data)
{
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
return new BigInteger(data, isBigEndian: true);
#else
var reversed = new byte[data.Length];
Buffer.BlockCopy(data, 0, reversed, 0, data.Length);
return new BigInteger(reversed.Reverse());
#endif
}

/// <summary>
/// Initializes a new instance of the <see cref="BigInteger"/> structure using the SSH BigNum2 Format.
/// </summary>
public static BigInteger ToBigInteger2(this byte[] data)
{
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
return new BigInteger(data, isBigEndian: true, isUnsigned: true);
#else
if ((data[0] & (1 << 7)) != 0)
{
var buf = new byte[data.Length + 1];
Buffer.BlockCopy(data, 0, buf, 1, data.Length);
data = buf;
return new BigInteger(buf.Reverse());
}

return data.ToBigInteger();
#endif
}

#if NETFRAMEWORK || NETSTANDARD2_0
public static byte[] ToByteArray(this BigInteger bigInt, bool isUnsigned = false, bool isBigEndian = false)
{
var data = bigInt.ToByteArray();
Expand All @@ -81,6 +91,15 @@ public static byte[] ToByteArray(this BigInteger bigInt, bool isUnsigned = false

return data;
}
#endif

#if !NET6_0_OR_GREATER
public static long GetBitLength(this BigInteger bigint)
{
// Taken from https://github.com/dotnet/runtime/issues/31308
return (long)Math.Ceiling(BigInteger.Log(bigint.Sign < 0 ? -bigint : bigint + 1, 2));
}
#endif

// See https://github.com/dotnet/runtime/blob/9b57a265c7efd3732b035bade005561a04767128/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs#L51
public static byte[] ExportKeyParameter(this BigInteger value, int length)
Expand Down
1 change: 1 addition & 0 deletions src/Renci.SshNet/Common/SshData.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Text;

namespace Renci.SshNet.Common
Expand Down
12 changes: 9 additions & 3 deletions src/Renci.SshNet/Common/SshDataStream.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Numerics;
using System.Text;

namespace Renci.SshNet.Common
Expand Down Expand Up @@ -110,7 +111,8 @@ public void Write(ulong value)
/// <param name="data">The <see cref="BigInteger" /> to write.</param>
public void Write(BigInteger data)
{
var bytes = data.ToByteArray().Reverse();
var bytes = data.ToByteArray(isBigEndian: true);

WriteBinary(bytes, 0, bytes.Length);
}

Expand Down Expand Up @@ -211,9 +213,13 @@ public void WriteBinary(byte[] buffer, int offset, int count)
/// </returns>
public BigInteger ReadBigInt()
{
var length = ReadUInt32();
var data = ReadBytes((int)length);
var data = ReadBinary();

#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
return new BigInteger(data, isBigEndian: true);
#else
return new BigInteger(data.Reverse());
#endif
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Renci.SshNet.Common;
using System.Numerics;

using Renci.SshNet.Common;

namespace Renci.SshNet.Messages.Transport
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;

using Renci.SshNet.Common;

namespace Renci.SshNet.Messages.Transport
{
/// <summary>
Expand Down Expand Up @@ -57,21 +55,6 @@ public KeyExchangeEcdhInitMessage(byte[] q)
QC = q;
}

/// <summary>
/// Initializes a new instance of the <see cref="KeyExchangeEcdhInitMessage"/> class.
/// </summary>
public KeyExchangeEcdhInitMessage(BigInteger d, BigInteger q)
{
var dBytes = d.ToByteArray().Reverse();
var qBytes = q.ToByteArray().Reverse();

var data = new byte[dBytes.Length + qBytes.Length + 1];
data[0] = 0x04;
Buffer.BlockCopy(dBytes, 0, data, 1, dBytes.Length);
Buffer.BlockCopy(qBytes, 0, data, dBytes.Length + 1, qBytes.Length);
QC = data;
}

/// <summary>
/// Called when type specific data need to be loaded.
/// </summary>
Expand Down
12 changes: 4 additions & 8 deletions src/Renci.SshNet/PrivateKeyFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -713,22 +714,17 @@ public BigInteger ReadBigIntWithBits()

length = (length + 7) / 8;

var data = base.ReadBytes(length);
var bytesArray = new byte[data.Length + 1];
Buffer.BlockCopy(data, 0, bytesArray, 1, data.Length);

return new BigInteger(bytesArray.Reverse());
return base.ReadBytes(length).ToBigInteger2();
}

public BigInteger ReadBignum()
{
return new BigInteger(ReadBignum2().Reverse());
return DataStream.ReadBigInt();
}

public byte[] ReadBignum2()
{
var length = (int)base.ReadUInt32();
return base.ReadBytes(length);
return ReadBinary();
}

protected override void LoadData()
Expand Down
3 changes: 2 additions & 1 deletion src/Renci.SshNet/Security/Cryptography/DsaKey.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#nullable enable
using System;
using System.Numerics;
using System.Security.Cryptography;

using Renci.SshNet.Common;
Expand Down Expand Up @@ -46,7 +47,7 @@ public override int KeyLength
{
get
{
return P.BitLength;
return (int)P.GetBitLength();
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/Renci.SshNet/Security/Cryptography/ED25519Key.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Numerics;

using Org.BouncyCastle.Math.EC.Rfc8032;

Expand Down Expand Up @@ -87,7 +88,8 @@ public ED25519Key(SshKeyData publicKeyData)
throw new ArgumentException($"Invalid Ed25519 public key data ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
}

PublicKey = publicKeyData.Keys[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySize);
PublicKey = publicKeyData.Keys[0].ToByteArray(isBigEndian: true).TrimLeadingZeros().Pad(Ed25519.PublicKeySize);
PrivateKey = new byte[Ed25519.SecretKeySize];
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ public byte[] Signature
{
var signed_r = new byte[_signature_size / 2];
Buffer.BlockCopy(value, 0, signed_r, 0, signed_r.Length);
_signature_r = signed_r.ToBigInteger2().ToByteArray().Reverse();
_signature_r = signed_r.ToBigInteger2().ToByteArray(isBigEndian: true);

var signed_s = new byte[_signature_size / 2];
Buffer.BlockCopy(value, signed_r.Length, signed_s, 0, signed_s.Length);
_signature_s = signed_s.ToBigInteger2().ToByteArray().Reverse();
_signature_s = signed_s.ToBigInteger2().ToByteArray(isBigEndian: true);
}
}

Expand All @@ -122,8 +122,8 @@ protected override void LoadData()

protected override void SaveData()
{
WriteBinaryString(_signature_r.ToBigInteger2().ToByteArray().Reverse());
WriteBinaryString(_signature_s.ToBigInteger2().ToByteArray().Reverse());
WriteBinaryString(_signature_r.ToBigInteger2().ToByteArray(isBigEndian: true));
WriteBinaryString(_signature_s.ToBigInteger2().ToByteArray(isBigEndian: true));
}

protected override int BufferCapacity
Expand Down
11 changes: 8 additions & 3 deletions src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
#nullable enable
using System;
using System.Diagnostics;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;

Expand Down Expand Up @@ -145,7 +146,11 @@ public override BigInteger[] Public
Buffer.BlockCopy(qy, 0, q, qx.Length + 1, qy.Length);

// returns Curve-Name and x/y as ECPoint
#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
return new[] { curve, new BigInteger(q, isBigEndian: true) };
#else
return new[] { curve, new BigInteger(q.Reverse()) };
#endif
}
}

Expand Down Expand Up @@ -191,10 +196,10 @@ public EcdsaKey(SshKeyData publicKeyData)
throw new ArgumentException($"Invalid ECDSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
}

var curve_s = Encoding.ASCII.GetString(publicKeyData.Keys[0].ToByteArray().Reverse());
var curve_s = Encoding.ASCII.GetString(publicKeyData.Keys[0].ToByteArray(isBigEndian: true));
var curve_oid = GetCurveOid(curve_s);

var publickey = publicKeyData.Keys[1].ToByteArray().Reverse();
var publickey = publicKeyData.Keys[1].ToByteArray(isBigEndian: true);
_impl = Import(curve_oid, publickey, privatekey: null);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Renci.SshNet/Security/Cryptography/Key.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Renci.SshNet.Common;
using System.Numerics;

using Renci.SshNet.Security.Cryptography;

namespace Renci.SshNet.Security
Expand Down
3 changes: 2 additions & 1 deletion src/Renci.SshNet/Security/Cryptography/RsaKey.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#nullable enable
using System;
using System.Numerics;
using System.Security.Cryptography;

using Renci.SshNet.Common;
Expand Down Expand Up @@ -96,7 +97,7 @@ public override int KeyLength
{
get
{
return Modulus.BitLength;
return (int)Modulus.GetBitLength();
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/Renci.SshNet/Security/GroupExchangeHashData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Numerics;

using Renci.SshNet.Common;

Expand Down Expand Up @@ -38,13 +39,13 @@ public string ClientVersion
public BigInteger Prime
{
private get { return _prime.ToBigInteger(); }
set { _prime = value.ToByteArray().Reverse(); }
set { _prime = value.ToByteArray(isBigEndian: true); }
}

public BigInteger SubGroup
{
private get { return _subGroup.ToBigInteger(); }
set { _subGroup = value.ToByteArray().Reverse(); }
set { _subGroup = value.ToByteArray(isBigEndian: true); }
}

public byte[] ClientExchangeValue { get; set; }
Expand Down
20 changes: 17 additions & 3 deletions src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Numerics;

using Renci.SshNet.Abstractions;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Transport;

Expand Down Expand Up @@ -109,14 +111,26 @@ protected void PopulateClientExchangeValue()
do
{
// Create private component
_privateExponent = BigInteger.Random(privateExponentSize);
_privateExponent = RandomBigInt(privateExponentSize);

// Generate public component
clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime);
}
while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1));

_clientExchangeValue = clientExchangeValue.ToByteArray().Reverse();
_clientExchangeValue = clientExchangeValue.ToByteArray(isBigEndian: true);
}

/// <summary>
/// Generates a new, random <see cref="BigInteger"/> of the specified length.
/// </summary>
/// <param name="bitLength">The number of bits for the new number.</param>
/// <returns>A random number of the specified length.</returns>
private static BigInteger RandomBigInt(int bitLength)
{
var bytesArray = CryptoAbstraction.GenerateRandom((bitLength / 8) + (((bitLength % 8) > 0) ? 1 : 0));
bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value
return new BigInteger(bytesArray);
}

/// <summary>
Expand All @@ -129,7 +143,7 @@ protected virtual void HandleServerDhReply(byte[] hostKey, byte[] serverExchange
{
_serverExchangeValue = serverExchangeValue;
_hostKey = hostKey;
SharedKey = BigInteger.ModPow(serverExchangeValue.ToBigInteger(), _privateExponent, _prime).ToByteArray().Reverse();
SharedKey = BigInteger.ModPow(serverExchangeValue.ToBigInteger(), _privateExponent, _prime).ToByteArray(isBigEndian: true);
_signature = signature;
}
}
Expand Down
Loading