53 lines
2.3 KiB
C#
53 lines
2.3 KiB
C#
namespace RelayClient.Crypto;
|
|
|
|
/// <summary>
|
|
/// Per-user RSA keypair persistence. Keys live as base64-encoded files in
|
|
/// {AppData}/keys/{username}.{public|private}.key
|
|
///
|
|
/// Plaintext on disk. For now this is fine because the only attack model is "someone else
|
|
/// has access to your filesystem" — at which point everything is compromised. A future
|
|
/// enhancement could encrypt the private key with a passphrase derived from the user's
|
|
/// password, similar to how SSH/PGP do it.
|
|
/// </summary>
|
|
public static class KeyStorage
|
|
{
|
|
/// <summary>Returns (and creates if needed) the per-app keys directory.</summary>
|
|
private static string GetKeyFolder()
|
|
{
|
|
var folder = Path.Combine(FileSystem.AppDataDirectory, "keys");
|
|
Directory.CreateDirectory(folder);
|
|
return folder;
|
|
}
|
|
|
|
/// <summary>Writes the base64 RSA private key to disk. Used at first-launch after GenerateRsaKeyPair.</summary>
|
|
public static void SavePrivateKey(string username, string privateKey)
|
|
{
|
|
File.WriteAllText(Path.Combine(GetKeyFolder(), $"{username}.private.key"), privateKey);
|
|
}
|
|
|
|
/// <summary>Writes the base64 RSA public key to disk. Sent to the server via WsAction.RegisterKey.</summary>
|
|
public static void SavePublicKey(string username, string publicKey)
|
|
{
|
|
File.WriteAllText(Path.Combine(GetKeyFolder(), $"{username}.public.key"), publicKey);
|
|
}
|
|
|
|
/// <summary>Reads the user's RSA private key. Used by TryDecryptAndParseContent on every inbound message.</summary>
|
|
public static string LoadPrivateKey(string username)
|
|
{
|
|
return File.ReadAllText(Path.Combine(GetKeyFolder(), $"{username}.private.key"));
|
|
}
|
|
|
|
/// <summary>Reads the user's RSA public key. Used during the boot handshake to send to the server.</summary>
|
|
public static string LoadPublicKey(string username)
|
|
{
|
|
return File.ReadAllText(Path.Combine(GetKeyFolder(), $"{username}.public.key"));
|
|
}
|
|
|
|
/// <summary>True if BOTH halves of the user's keypair already exist on disk. False means we need to generate.</summary>
|
|
public static bool HasKeys(string username)
|
|
{
|
|
return File.Exists(Path.Combine(GetKeyFolder(), $"{username}.private.key")) &&
|
|
File.Exists(Path.Combine(GetKeyFolder(), $"{username}.public.key"));
|
|
}
|
|
}
|