From 1da5637997e7971cbde77dbf642ea734fbb2f4cc Mon Sep 17 00:00:00 2001 From: Lena Date: Wed, 1 Jul 2026 00:00:00 +0000 Subject: keys: never write the plaintext private key to disk rsh -keygen printed the pubkey but wrote the key pair into a directory, so generating a key briefly left the plaintext private key on flash, contradicting the documented invariant that it only ever exists in memory. -keygen now emits the private key PEM on stdout and nothing else; the app encrypts it immediately and derives the public key via -pubkey, reusing the validated import path. Keygen failures now surface as an error dialog instead of crashing the app from a bare thread. --- app/src/main/java/invalid/lena/rsend/Keys.kt | 13 ++++++------- .../main/java/invalid/lena/rsend/MainActivity.kt | 21 +++++++++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/invalid/lena/rsend/Keys.kt b/app/src/main/java/invalid/lena/rsend/Keys.kt index 0a5384d..fa233f7 100644 --- a/app/src/main/java/invalid/lena/rsend/Keys.kt +++ b/app/src/main/java/invalid/lena/rsend/Keys.kt @@ -15,14 +15,13 @@ object Keys { fun exists(ctx: Context): Boolean = keyEnc(ctx).exists() - // generate creates the key pair, stores the private key encrypted, and - // returns the public key in authorized_keys format. + // generate creates a key pair via rsh -keygen (the plaintext key never + // touches disk), stores it encrypted, and returns the public key in + // authorized_keys format. Storage and validation reuse importKey. fun generate(ctx: Context): String { - val tmp = File(ctx.cacheDir, "keygen").apply { mkdirs() } - Native.run(Native.rsh(ctx), listOf("-keygen", tmp.absolutePath)) - keyEnc(ctx).writeBytes(KeyVault.encrypt(File(tmp, "id_ed25519").readBytes())) - File(tmp, "id_ed25519.pub").copyTo(publicKey(ctx), overwrite = true) - tmp.deleteRecursively() + val r = Native.run(Native.rsh(ctx), listOf("-keygen")) + if (r.code != 0) throw IllegalStateException(r.output.trim().ifEmpty { "keygen failed" }) + importKey(ctx, r.output.toByteArray()) return publicKeyText(ctx) } diff --git a/app/src/main/java/invalid/lena/rsend/MainActivity.kt b/app/src/main/java/invalid/lena/rsend/MainActivity.kt index 6b51252..ce65c2e 100644 --- a/app/src/main/java/invalid/lena/rsend/MainActivity.kt +++ b/app/src/main/java/invalid/lena/rsend/MainActivity.kt @@ -295,11 +295,24 @@ class MainActivity : AppCompatActivity() { .setMessage(msg) .setPositiveButton("Generate") { _, _ -> thread { - Keys.generate(this) + val error = try { + Keys.generate(this) + null + } catch (e: Exception) { + e.message ?: "keygen failed" + } runOnUiThread { - refresh() - Toast.makeText(this, "New key generated.", Toast.LENGTH_SHORT).show() - showKey() + if (error == null) { + refresh() + Toast.makeText(this, "New key generated.", Toast.LENGTH_SHORT).show() + showKey() + } else { + AlertDialog.Builder(this) + .setTitle("Keygen failed") + .setMessage(error) + .setPositiveButton("OK", null) + .show() + } } } } -- cgit v1.2.3