1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-12-14 18:00:26 +00:00
This commit is contained in:
JKorf 2025-12-09 21:13:01 +01:00
parent 90abcb78aa
commit 8dd93e2929
4 changed files with 74 additions and 1 deletions

View File

@ -1,4 +1,6 @@
using System; using System;
using System.IO;
using System.Threading.Tasks;
namespace CryptoExchange.Net.Authentication namespace CryptoExchange.Net.Authentication
{ {
@ -45,6 +47,16 @@ namespace CryptoExchange.Net.Authentication
Pass = pass; Pass = pass;
} }
/// <summary>
/// Load a private key from a file path
/// </summary>
public async Task<string> LoadPrivateKey(string path)
{
using var filestream = File.OpenRead(path);
using var streamReader = new StreamReader(filestream);
return await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
/// <summary> /// <summary>
/// Copy the credentials /// Copy the credentials
/// </summary> /// </summary>

View File

@ -16,6 +16,10 @@
/// <summary> /// <summary>
/// Rsa keys credentials in pem/base64 format. Only available for .NetStandard 2.1 and up, use xml format for lower. /// Rsa keys credentials in pem/base64 format. Only available for .NetStandard 2.1 and up, use xml format for lower.
/// </summary> /// </summary>
RsaPem RsaPem,
/// <summary>
/// Ed25519 keys credentials
/// </summary>
Ed25519
} }
} }

View File

@ -2,8 +2,12 @@
using CryptoExchange.Net.Converters.SystemTextJson; using CryptoExchange.Net.Converters.SystemTextJson;
using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
#if NET8_0_OR_GREATER
using NSec.Cryptography;
#endif
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Globalization; using System.Globalization;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
@ -17,6 +21,11 @@ namespace CryptoExchange.Net.Authentication
{ {
internal IAuthTimeProvider TimeProvider { get; set; } = new AuthTimeProvider(); internal IAuthTimeProvider TimeProvider { get; set; } = new AuthTimeProvider();
/// <summary>
/// The supported credential types
/// </summary>
public abstract ApiCredentialsType[] SupportedCredentialTypes { get; }
/// <summary> /// <summary>
/// Provided credentials /// Provided credentials
/// </summary> /// </summary>
@ -27,6 +36,13 @@ namespace CryptoExchange.Net.Authentication
/// </summary> /// </summary>
protected byte[] _sBytes; protected byte[] _sBytes;
#if NET8_0_OR_GREATER
/// <summary>
/// The Ed25519 private key
/// </summary>
protected Key? Ed25519Key;
#endif
/// <summary> /// <summary>
/// Get the API key of the current credentials /// Get the API key of the current credentials
/// </summary> /// </summary>
@ -45,6 +61,16 @@ namespace CryptoExchange.Net.Authentication
if (credentials.Key == null || credentials.Secret == null) if (credentials.Key == null || credentials.Secret == null)
throw new ArgumentException("ApiKey/Secret needed"); throw new ArgumentException("ApiKey/Secret needed");
if (!SupportedCredentialTypes.Any(x => x == credentials.CredentialType))
throw new ArgumentException($"Credential type {credentials.CredentialType} not supported");
if (credentials.CredentialType == ApiCredentialsType.Ed25519)
{
#if !NET8_0_OR_GREATER
throw new ArgumentException($"Credential type Ed25519 only supported on Net8.0 or newer");
#endif
}
_credentials = credentials; _credentials = credentials;
_sBytes = Encoding.UTF8.GetBytes(credentials.Secret); _sBytes = Encoding.UTF8.GetBytes(credentials.Secret);
} }
@ -348,6 +374,36 @@ namespace CryptoExchange.Net.Authentication
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes); return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
} }
/// <summary>
/// Ed25519 sign the data
/// </summary>
public string SignEd25519(string data, SignOutputType? outputType = null)
=> SignEd25519(Encoding.ASCII.GetBytes(data), outputType);
/// <summary>
/// Ed25519 sign the data
/// </summary>
public string SignEd25519(byte[] data, SignOutputType? outputType = null)
{
#if NET8_0_OR_GREATER
if (Ed25519Key == null)
{
var key = _credentials.Secret!
.Replace("\n", "")
.Replace("-----BEGIN PRIVATE KEY-----", "")
.Replace("-----END PRIVATE KEY-----", "")
.Trim();
var keyBytes = Convert.FromBase64String(key);
Ed25519Key = Key.Import(SignatureAlgorithm.Ed25519, keyBytes, KeyBlobFormat.PkixPrivateKey);
}
var resultBytes = SignatureAlgorithm.Ed25519.Sign(Ed25519Key, data);
return outputType == SignOutputType.Base64 ? BytesToBase64String(resultBytes) : BytesToHexString(resultBytes);
#else
throw new InvalidOperationException();
#endif
}
private RSA CreateRSA() private RSA CreateRSA()
{ {
var rsa = RSA.Create(); var rsa = RSA.Create();

View File

@ -53,6 +53,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.0" />
<PackageReference Include="System.Text.Json" Version="10.0.0" /> <PackageReference Include="System.Text.Json" Version="10.0.0" />
<PackageReference Include="NSec.Cryptography" Version="25.4.0" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Transitive Client Packages"> <ItemGroup Label="Transitive Client Packages">
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.0" />