chore: initial project import
This commit is contained in:
commit
26620707a0
347 files changed
+56172
No files matched your search
@@ -0,0 +1,81 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Fleet.Identity;
|
||||
|
||||
/// <summary>签名用途前缀:同一份签名不能在不同场景下复用。产品可以追加自己的用途,但不能占用 fleet 保留的这些。</summary>
|
||||
public static class SignaturePurpose
|
||||
{
|
||||
public const string Auth = "auth";
|
||||
public const string Peer = "peer";
|
||||
public const string Enroll = "enroll";
|
||||
}
|
||||
|
||||
public static class SignatureString
|
||||
{
|
||||
public static string Build(string purpose, params string[] fields) =>
|
||||
"fleet|v1|" + purpose + "|" + string.Join('|', fields);
|
||||
}
|
||||
|
||||
/// <summary>节点身份:ECDSA P-256 密钥对。服务端只保存公钥(SPKI)。</summary>
|
||||
public sealed class NodeIdentity : IDisposable
|
||||
{
|
||||
private readonly ECDsa _key;
|
||||
|
||||
private NodeIdentity(ECDsa key)
|
||||
{
|
||||
_key = key;
|
||||
PublicKeySpki = key.ExportSubjectPublicKeyInfo();
|
||||
}
|
||||
|
||||
public byte[] PublicKeySpki { get; }
|
||||
|
||||
public static NodeIdentity Generate() => new(ECDsa.Create(ECCurve.NamedCurves.nistP256));
|
||||
|
||||
public static NodeIdentity FromPkcs8(ReadOnlySpan<byte> pkcs8)
|
||||
{
|
||||
ECDsa key = ECDsa.Create();
|
||||
key.ImportPkcs8PrivateKey(pkcs8, out _);
|
||||
return new NodeIdentity(key);
|
||||
}
|
||||
|
||||
public byte[] ExportPkcs8() => _key.ExportPkcs8PrivateKey();
|
||||
|
||||
public byte[] Sign(string purpose, params string[] fields) =>
|
||||
_key.SignData(Encoding.UTF8.GetBytes(SignatureString.Build(purpose, fields)), HashAlgorithmName.SHA256,
|
||||
DSASignatureFormat.IeeeP1363FixedFieldConcatenation);
|
||||
|
||||
/// <summary>验证签名;公钥或签名格式不合法时返回 false,不抛异常。</summary>
|
||||
public static bool Verify(ReadOnlySpan<byte> publicKeySpki, ReadOnlySpan<byte> signature, string purpose, params string[] fields)
|
||||
{
|
||||
try
|
||||
{
|
||||
using ECDsa key = ECDsa.Create();
|
||||
key.ImportSubjectPublicKeyInfo(publicKeySpki, out _);
|
||||
return key.VerifyData(Encoding.UTF8.GetBytes(SignatureString.Build(purpose, fields)), signature,
|
||||
HashAlgorithmName.SHA256, DSASignatureFormat.IeeeP1363FixedFieldConcatenation);
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsValidPublicKey(ReadOnlySpan<byte> publicKeySpki)
|
||||
{
|
||||
try
|
||||
{
|
||||
using ECDsa key = ECDsa.Create();
|
||||
key.ImportSubjectPublicKeyInfo(publicKeySpki, out _);
|
||||
return key.KeySize == 256;
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Fingerprint(ReadOnlySpan<byte> spki) => SHA256.HashData(spki);
|
||||
|
||||
public void Dispose() => _key.Dispose();
|
||||
}
|
||||
Reference in new issue
Block a user