mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Ref System.Formats.Asn1 nuget package (#1490)
* Ref System.Formats.Asn1 nuget package * Ref System.Formats.Asn1 only for net462, netstandard2.0 and netstandard2.1 Delete ObjectIdentifier.cs * Consolidate package reference * 100x improvement --------- Co-authored-by: Rob Hague <rob.hague00@gmail.com>
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.7.70-alpha" />
|
||||
<PackageVersion Include="SonarAnalyzer.CSharp" Version="9.19.0.84025" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<PackageVersion Include="System.Memory" Version="4.5.5" />
|
||||
<PackageVersion Include="System.Formats.Asn1" Version="8.0.1" />
|
||||
<PackageVersion Include="Testcontainers" Version="3.9.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,439 +0,0 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Renci.SshNet.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for DER encoded data.
|
||||
/// </summary>
|
||||
public class DerData
|
||||
{
|
||||
private const byte Constructed = 0x20;
|
||||
|
||||
private const byte Boolean = 0x01;
|
||||
private const byte Integer = 0x02;
|
||||
private const byte BITSTRING = 0x03;
|
||||
private const byte Octetstring = 0x04;
|
||||
private const byte Null = 0x05;
|
||||
private const byte Objectidentifier = 0x06;
|
||||
private const byte Sequence = 0x10;
|
||||
|
||||
private readonly List<byte> _data;
|
||||
private readonly int _lastIndex;
|
||||
private int _readerIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether end of data is reached.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true"/> if end of data is reached; otherwise, <see langword="false"/>.
|
||||
/// </value>
|
||||
public bool IsEndOfData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _readerIndex >= _lastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DerData"/> class.
|
||||
/// </summary>
|
||||
public DerData()
|
||||
{
|
||||
_data = new List<byte>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DerData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded data.</param>
|
||||
/// <param name="construct">its a construct.</param>
|
||||
public DerData(byte[] data, bool construct = false)
|
||||
{
|
||||
_data = new List<byte>(data);
|
||||
if (construct)
|
||||
{
|
||||
_lastIndex = _readerIndex + data.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = ReadByte(); // skip dataType
|
||||
var length = ReadLength();
|
||||
_lastIndex = _readerIndex + length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes written data as DER byte array.
|
||||
/// </summary>
|
||||
/// <returns>DER Encoded array.</returns>
|
||||
public byte[] Encode()
|
||||
{
|
||||
var length = _data.Count;
|
||||
var lengthBytes = GetLength(length);
|
||||
|
||||
_data.InsertRange(0, lengthBytes);
|
||||
_data.Insert(0, Constructed | Sequence);
|
||||
|
||||
return _data.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads next mpint data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>mpint read.</returns>
|
||||
public BigInteger ReadBigInteger()
|
||||
{
|
||||
var type = ReadByte();
|
||||
if (type != Integer)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, but was {0}", type.ToString("X2")));
|
||||
}
|
||||
|
||||
var length = ReadLength();
|
||||
|
||||
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>
|
||||
/// Reads next int data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>int read.</returns>
|
||||
public int ReadInteger()
|
||||
{
|
||||
var type = ReadByte();
|
||||
if (type != Integer)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, but was {0}", type.ToString("X2")));
|
||||
}
|
||||
|
||||
var length = ReadLength();
|
||||
|
||||
var data = ReadBytes(length);
|
||||
|
||||
if (length > 4)
|
||||
{
|
||||
throw new InvalidOperationException("Integer type cannot occupy more then 4 bytes");
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
var shift = (length - 1) * 8;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
result |= data[i] << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads next octetstring data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>data read.</returns>
|
||||
public byte[] ReadOctetString()
|
||||
{
|
||||
var type = ReadByte();
|
||||
if (type != Octetstring)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Invalid data type, OCTETSTRING(04) is expected, but was {0}", type.ToString("X2")));
|
||||
}
|
||||
|
||||
var length = ReadLength();
|
||||
var data = ReadBytes(length);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads next bitstring data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>data read.</returns>
|
||||
public byte[] ReadBitString()
|
||||
{
|
||||
var type = ReadByte();
|
||||
if (type != BITSTRING)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Invalid data type, BITSTRING(03) is expected, but was {0}", type.ToString("X2")));
|
||||
}
|
||||
|
||||
var length = ReadLength();
|
||||
var data = ReadBytes(length);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads next object data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>data read.</returns>
|
||||
public byte[] ReadObject()
|
||||
{
|
||||
var type = ReadByte();
|
||||
if (type != Objectidentifier)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Invalid data type, OBJECT(06) is expected, but was {0}", type.ToString("X2")));
|
||||
}
|
||||
|
||||
var length = ReadLength();
|
||||
var data = ReadBytes(length);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes BOOLEAN data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">UInt32 data to write.</param>
|
||||
public void Write(bool data)
|
||||
{
|
||||
_data.Add(Boolean);
|
||||
_data.Add(1);
|
||||
_data.Add((byte)(data ? 1 : 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes UInt32 data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">UInt32 data to write.</param>
|
||||
public void Write(uint data)
|
||||
{
|
||||
var bytes = new byte[sizeof(uint)];
|
||||
BinaryPrimitives.WriteUInt32BigEndian(bytes, data);
|
||||
_data.Add(Integer);
|
||||
var length = GetLength(bytes.Length);
|
||||
WriteBytes(length);
|
||||
WriteBytes(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes INTEGER data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">BigInteger data to write.</param>
|
||||
public void Write(BigInteger data)
|
||||
{
|
||||
var bytes = data.ToByteArray(isBigEndian: true);
|
||||
_data.Add(Integer);
|
||||
var length = GetLength(bytes.Length);
|
||||
WriteBytes(length);
|
||||
WriteBytes(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes OCTETSTRING data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void Write(byte[] data)
|
||||
{
|
||||
_data.Add(Octetstring);
|
||||
var length = GetLength(data.Length);
|
||||
WriteBytes(length);
|
||||
WriteBytes(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes OBJECTIDENTIFIER data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier.</param>
|
||||
public void Write(ObjectIdentifier identifier)
|
||||
{
|
||||
var temp = new ulong[identifier.Identifiers.Length - 1];
|
||||
temp[0] = (identifier.Identifiers[0] * 40) + identifier.Identifiers[1];
|
||||
Buffer.BlockCopy(identifier.Identifiers, 2 * sizeof(ulong), temp, 1 * sizeof(ulong), (identifier.Identifiers.Length - 2) * sizeof(ulong));
|
||||
var bytes = new List<byte>();
|
||||
foreach (var subidentifier in temp)
|
||||
{
|
||||
var item = subidentifier;
|
||||
var buffer = new byte[8];
|
||||
var bufferIndex = buffer.Length - 1;
|
||||
|
||||
var current = (byte)(item & 0x7F);
|
||||
do
|
||||
{
|
||||
buffer[bufferIndex] = current;
|
||||
if (bufferIndex < buffer.Length - 1)
|
||||
{
|
||||
buffer[bufferIndex] |= 0x80;
|
||||
}
|
||||
|
||||
item >>= 7;
|
||||
current = (byte)(item & 0x7F);
|
||||
bufferIndex--;
|
||||
}
|
||||
while (current > 0);
|
||||
|
||||
for (var i = bufferIndex + 1; i < buffer.Length; i++)
|
||||
{
|
||||
bytes.Add(buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_data.Add(Objectidentifier);
|
||||
var length = GetLength(bytes.Count);
|
||||
WriteBytes(length);
|
||||
WriteBytes(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes DerData data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">DerData data to write.</param>
|
||||
public void Write(DerData data)
|
||||
{
|
||||
var bytes = data.Encode();
|
||||
_data.AddRange(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes BITSTRING data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void WriteBitstring(byte[] data)
|
||||
{
|
||||
_data.Add(BITSTRING);
|
||||
var length = GetLength(data.Length);
|
||||
WriteBytes(length);
|
||||
WriteBytes(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes OBJECTIDENTIFIER data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The bytes.</param>
|
||||
public void WriteObjectIdentifier(byte[] bytes)
|
||||
{
|
||||
_data.Add(Objectidentifier);
|
||||
var length = GetLength(bytes.Length);
|
||||
WriteBytes(length);
|
||||
WriteBytes(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes NULL data into internal buffer.
|
||||
/// </summary>
|
||||
public void WriteNull()
|
||||
{
|
||||
_data.Add(Null);
|
||||
_data.Add(0);
|
||||
}
|
||||
|
||||
private static byte[] GetLength(int length)
|
||||
{
|
||||
if (length > 127)
|
||||
{
|
||||
var size = 1;
|
||||
var val = length;
|
||||
|
||||
while ((val >>= 8) != 0)
|
||||
{
|
||||
size++;
|
||||
}
|
||||
|
||||
var data = new byte[size];
|
||||
data[0] = (byte)(size | 0x80);
|
||||
|
||||
for (int i = (size - 1) * 8, j = 1; i >= 0; i -= 8, j++)
|
||||
{
|
||||
data[j] = (byte)(length >> i);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return new[] { (byte)length };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets Data Length.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The length.
|
||||
/// </returns>
|
||||
public int ReadLength()
|
||||
{
|
||||
int length = ReadByte();
|
||||
|
||||
if (length == 0x80)
|
||||
{
|
||||
throw new NotSupportedException("Indefinite-length encoding is not supported.");
|
||||
}
|
||||
|
||||
if (length > 127)
|
||||
{
|
||||
var size = length & 0x7f;
|
||||
|
||||
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
|
||||
if (size > 4)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("DER length is '{0}' and cannot be more than 4 bytes.", size));
|
||||
}
|
||||
|
||||
length = 0;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
int next = ReadByte();
|
||||
|
||||
length = (length << 8) + next;
|
||||
}
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
throw new InvalidOperationException("Corrupted data - negative length found");
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write Byte data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to write.</param>
|
||||
public void WriteBytes(IEnumerable<byte> data)
|
||||
{
|
||||
_data.AddRange(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads Byte data into internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The data read.
|
||||
/// </returns>
|
||||
public byte ReadByte()
|
||||
{
|
||||
if (_readerIndex > _data.Count)
|
||||
{
|
||||
throw new InvalidOperationException("Read out of boundaries.");
|
||||
}
|
||||
|
||||
return _data[_readerIndex++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads lengths Bytes data into internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The data read.
|
||||
/// </returns>
|
||||
/// <param name="length">amount of data to read.</param>
|
||||
public byte[] ReadBytes(int length)
|
||||
{
|
||||
if (_readerIndex + length > _data.Count)
|
||||
{
|
||||
throw new InvalidOperationException("Read out of boundaries.");
|
||||
}
|
||||
|
||||
var result = new byte[length];
|
||||
_data.CopyTo(_readerIndex, result, 0, length);
|
||||
_readerIndex += length;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes object identifier for DER encoding.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1815 // Override equals and operator equals on value types
|
||||
public struct ObjectIdentifier
|
||||
#pragma warning restore CA1815 // Override equals and operator equals on value types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the object identifier.
|
||||
/// </summary>
|
||||
public ulong[] Identifiers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ObjectIdentifier"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="identifiers">The identifiers.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="identifiers"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="identifiers"/> has less than two elements.</exception>
|
||||
public ObjectIdentifier(params ulong[] identifiers)
|
||||
{
|
||||
if (identifiers is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(identifiers));
|
||||
}
|
||||
|
||||
if (identifiers.Length < 2)
|
||||
{
|
||||
throw new ArgumentException("Must contain at least two elements.", nameof(identifiers));
|
||||
}
|
||||
|
||||
Identifiers = identifiers;
|
||||
}
|
||||
|
||||
internal static ObjectIdentifier FromHashAlgorithmName(HashAlgorithmName hashAlgorithmName)
|
||||
{
|
||||
var oid = CryptoConfig.MapNameToOID(hashAlgorithmName.Name);
|
||||
|
||||
if (oid is null)
|
||||
{
|
||||
throw new ArgumentException($"Could not map `{hashAlgorithmName}` to OID.", nameof(hashAlgorithmName));
|
||||
}
|
||||
|
||||
var identifiers = oid.Split('.').Select(ulong.Parse).ToArray();
|
||||
|
||||
return new ObjectIdentifier(identifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,18 +33,19 @@
|
||||
<PropertyGroup Condition=" $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0')) ">
|
||||
<IsAotCompatible>true</IsAotCompatible>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" />
|
||||
<PackageReference Include="Nerdbank.GitVersioning" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
|
||||
<PackageReference Include="System.Memory" />
|
||||
<PackageReference Include="System.Formats.Asn1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" />
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1'">
|
||||
<PackageReference Include="System.Formats.Asn1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Formats.Asn1;
|
||||
using System.Numerics;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
@@ -118,19 +119,16 @@ namespace Renci.SshNet.Security
|
||||
throw new ArgumentNullException(nameof(privateKeyData));
|
||||
}
|
||||
|
||||
var der = new DerData(privateKeyData);
|
||||
_ = der.ReadBigInteger(); // skip version
|
||||
var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence();
|
||||
_ = der.ReadInteger(); // skip version
|
||||
|
||||
P = der.ReadBigInteger();
|
||||
Q = der.ReadBigInteger();
|
||||
G = der.ReadBigInteger();
|
||||
Y = der.ReadBigInteger();
|
||||
X = der.ReadBigInteger();
|
||||
P = der.ReadInteger();
|
||||
Q = der.ReadInteger();
|
||||
G = der.ReadInteger();
|
||||
Y = der.ReadInteger();
|
||||
X = der.ReadInteger();
|
||||
|
||||
if (!der.IsEndOfData)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid private key (expected EOF).");
|
||||
}
|
||||
der.ThrowIfNotEmpty();
|
||||
|
||||
DSA = LoadDSA();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Formats.Asn1;
|
||||
using System.Numerics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@@ -220,51 +221,20 @@ namespace Renci.SshNet.Security
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
public EcdsaKey(byte[] data)
|
||||
{
|
||||
var der = new DerData(data);
|
||||
_ = der.ReadBigInteger(); // skip version
|
||||
var der = new AsnReader(data, AsnEncodingRules.DER).ReadSequence();
|
||||
_ = der.ReadInteger(); // skip version
|
||||
|
||||
// PrivateKey
|
||||
var privatekey = der.ReadOctetString().TrimLeadingZeros();
|
||||
|
||||
// Construct
|
||||
var s0 = der.ReadByte();
|
||||
if ((s0 & 0xe0) != 0xa0)
|
||||
{
|
||||
throw new SshException(string.Format("UnexpectedDER: wanted constructed tag (0xa0-0xbf), got: {0:X}", s0));
|
||||
}
|
||||
var s0 = der.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true));
|
||||
var curve = s0.ReadObjectIdentifier();
|
||||
|
||||
var tag = s0 & 0x1f;
|
||||
if (tag != 0)
|
||||
{
|
||||
throw new SshException(string.Format("expected tag 0 in DER privkey, got: {0}", tag));
|
||||
}
|
||||
var s1 = der.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true));
|
||||
var pubkey = s1.ReadBitString(out _);
|
||||
|
||||
var construct = der.ReadBytes(der.ReadLength()); // object length
|
||||
der.ThrowIfNotEmpty();
|
||||
|
||||
// curve OID
|
||||
var curve_der = new DerData(construct, construct: true);
|
||||
var curve = curve_der.ReadObject();
|
||||
|
||||
// Construct
|
||||
s0 = der.ReadByte();
|
||||
if ((s0 & 0xe0) != 0xa0)
|
||||
{
|
||||
throw new SshException(string.Format("UnexpectedDER: wanted constructed tag (0xa0-0xbf), got: {0:X}", s0));
|
||||
}
|
||||
|
||||
tag = s0 & 0x1f;
|
||||
if (tag != 1)
|
||||
{
|
||||
throw new SshException(string.Format("expected tag 1 in DER privkey, got: {0}", tag));
|
||||
}
|
||||
|
||||
construct = der.ReadBytes(der.ReadLength()); // object length
|
||||
|
||||
// PublicKey
|
||||
var pubkey_der = new DerData(construct, construct: true);
|
||||
var pubkey = pubkey_der.ReadBitString().TrimLeadingZeros();
|
||||
|
||||
_impl = Import(OidByteArrayToString(curve), pubkey, privatekey);
|
||||
_impl = Import(curve, pubkey, privatekey);
|
||||
}
|
||||
|
||||
#pragma warning disable CA1859 // Use concrete types when possible for improved performance
|
||||
@@ -319,35 +289,6 @@ namespace Renci.SshNet.Security
|
||||
throw new SshException("Unexpected Curve Name: " + curve_s);
|
||||
}
|
||||
|
||||
private static string OidByteArrayToString(byte[] oid)
|
||||
{
|
||||
var retVal = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < oid.Length; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
var b = oid[0] % 40;
|
||||
var a = (oid[0] - b) / 40;
|
||||
_ = retVal.AppendFormat("{0}.{1}", a, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oid[i] < 128)
|
||||
{
|
||||
_ = retVal.AppendFormat(".{0}", oid[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = retVal.AppendFormat(".{0}", ((oid[i] - 128) * 128) + oid[i + 1]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Formats.Asn1;
|
||||
using System.Numerics;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
@@ -166,22 +167,19 @@ namespace Renci.SshNet.Security
|
||||
throw new ArgumentNullException(nameof(privateKeyData));
|
||||
}
|
||||
|
||||
var der = new DerData(privateKeyData);
|
||||
_ = der.ReadBigInteger(); // skip version
|
||||
var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence();
|
||||
_ = der.ReadInteger(); // skip version
|
||||
|
||||
Modulus = der.ReadBigInteger();
|
||||
Exponent = der.ReadBigInteger();
|
||||
D = der.ReadBigInteger();
|
||||
P = der.ReadBigInteger();
|
||||
Q = der.ReadBigInteger();
|
||||
DP = der.ReadBigInteger();
|
||||
DQ = der.ReadBigInteger();
|
||||
InverseQ = der.ReadBigInteger();
|
||||
Modulus = der.ReadInteger();
|
||||
Exponent = der.ReadInteger();
|
||||
D = der.ReadInteger();
|
||||
P = der.ReadInteger();
|
||||
Q = der.ReadInteger();
|
||||
DP = der.ReadInteger();
|
||||
DQ = der.ReadInteger();
|
||||
InverseQ = der.ReadInteger();
|
||||
|
||||
if (!der.IsEndOfData)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid private key (expected EOF).");
|
||||
}
|
||||
der.ThrowIfNotEmpty();
|
||||
|
||||
RSA = RSA.Create();
|
||||
RSA.ImportParameters(GetRSAParameters());
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Tests.Common;
|
||||
|
||||
namespace Renci.SshNet.Tests.Classes.Common
|
||||
{
|
||||
[TestClass]
|
||||
public class ObjectIdentifierTest : TestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void Constructor_IdentifiersIsNull()
|
||||
{
|
||||
const ulong[] identifiers = null;
|
||||
|
||||
var actualException = Assert.ThrowsException<ArgumentNullException>(() => new ObjectIdentifier(identifiers));
|
||||
|
||||
Assert.AreEqual(typeof(ArgumentNullException), actualException.GetType());
|
||||
Assert.IsNull(actualException.InnerException);
|
||||
Assert.AreEqual(nameof(identifiers), actualException.ParamName);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Constructor_LengthOfIdentifiersIsLessThanTwo()
|
||||
{
|
||||
var identifiers = new[] { 5UL };
|
||||
|
||||
var actualException = Assert.ThrowsException<ArgumentException>(() => new ObjectIdentifier(identifiers));
|
||||
|
||||
Assert.AreEqual(typeof(ArgumentException), actualException.GetType());
|
||||
Assert.IsNull(actualException.InnerException);
|
||||
ArgumentExceptionAssert.MessageEquals("Must contain at least two elements.", actualException);
|
||||
Assert.AreEqual(nameof(identifiers), actualException.ParamName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user