Add managed TLS interoperability and persisted credentials
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
using System.Security.Cryptography;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace VoiceCat.Crypto;
|
||||
|
||||
public sealed class ServerIdentity : IDisposable
|
||||
{
|
||||
private readonly byte[] seed;
|
||||
private readonly byte[] publicKey;
|
||||
private bool disposed;
|
||||
|
||||
private ServerIdentity(byte[] seed)
|
||||
{
|
||||
this.seed = seed;
|
||||
publicKey = new Ed25519PrivateKeyParameters(seed, 0).GeneratePublicKey().GetEncoded();
|
||||
}
|
||||
|
||||
public byte[] PublicKey => (byte[])publicKey.Clone();
|
||||
public string Fingerprint => Convert.ToHexString(SHA256.HashData(publicKey));
|
||||
|
||||
public static ServerIdentity Generate() => new(RandomNumberGenerator.GetBytes(32));
|
||||
|
||||
public static ServerIdentity Load(string path)
|
||||
{
|
||||
byte[] data = File.ReadAllBytes(path);
|
||||
try
|
||||
{
|
||||
if (data.Length != 96) throw new InvalidDataException("Server identity must contain 96 bytes.");
|
||||
var identity = new ServerIdentity(data.AsSpan(32, 32).ToArray());
|
||||
if (!CryptographicOperations.FixedTimeEquals(identity.publicKey, data.AsSpan(0, 32)) ||
|
||||
!CryptographicOperations.FixedTimeEquals(identity.publicKey, data.AsSpan(64, 32)))
|
||||
{
|
||||
identity.Dispose();
|
||||
throw new InvalidDataException("Server identity public key does not match its seed.");
|
||||
}
|
||||
return identity;
|
||||
}
|
||||
finally { CryptographicOperations.ZeroMemory(data); }
|
||||
}
|
||||
|
||||
public void Save(string path)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(disposed, this);
|
||||
byte[] data = new byte[96];
|
||||
publicKey.CopyTo(data, 0);
|
||||
seed.CopyTo(data, 32);
|
||||
publicKey.CopyTo(data, 64);
|
||||
try { PrivateFiles.Write(path, data); }
|
||||
finally { CryptographicOperations.ZeroMemory(data); }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
CryptographicOperations.ZeroMemory(seed);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user