From f47b2ea4350339f31111ecdf9418aa1417bb94d9 Mon Sep 17 00:00:00 2001 From: lare96 Date: Wed, 26 Sep 2018 23:49:14 -0400 Subject: [PATCH] Initial commit. --- .gitignore | 3 + README.md | 1 + src/io/luna/net/rsa/RSAKeyGen.java | 38 ++++++++++ src/io/luna/net/rsa/RSAKeyGenMain.java | 33 +++++++++ src/io/luna/net/rsa/RSAKeyPair.java | 94 +++++++++++++++++++++++++ src/io/luna/net/rsa/TerminalReader.java | 42 +++++++++++ 6 files changed, 211 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/io/luna/net/rsa/RSAKeyGen.java create mode 100644 src/io/luna/net/rsa/RSAKeyGenMain.java create mode 100644 src/io/luna/net/rsa/RSAKeyPair.java create mode 100644 src/io/luna/net/rsa/TerminalReader.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2f549d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +out/ +rsakeygen.iml diff --git a/README.md b/README.md new file mode 100644 index 0000000..ebdaf18 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +rsakeygen \ No newline at end of file diff --git a/src/io/luna/net/rsa/RSAKeyGen.java b/src/io/luna/net/rsa/RSAKeyGen.java new file mode 100644 index 0000000..6bb93aa --- /dev/null +++ b/src/io/luna/net/rsa/RSAKeyGen.java @@ -0,0 +1,38 @@ +package io.luna.net.rsa; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.function.Consumer; + +/** + * A {@link Consumer} implementation that will generate new RSA keys and store them in the local file system. + * + * @author lare96 + */ +final class RSAKeyGen implements Consumer { + + /** + * The private RSA key file. + */ + private final Path privateFile = Paths.get("rsapriv.toml"); + + /** + * The public RSA key file. + */ + private final Path publicFile = Paths.get("rsapub.toml"); + + @Override + public void accept(String s) { + try { + RSAKeyPair keyPair = RSAKeyPair.newKeyPair(); + keyPair.writeToFile(privateFile, publicFile); + } catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) { + e.printStackTrace(); + } finally { + RSAKeyGenMain.exit(); + } + } +} \ No newline at end of file diff --git a/src/io/luna/net/rsa/RSAKeyGenMain.java b/src/io/luna/net/rsa/RSAKeyGenMain.java new file mode 100644 index 0000000..66318a8 --- /dev/null +++ b/src/io/luna/net/rsa/RSAKeyGenMain.java @@ -0,0 +1,33 @@ +package io.luna.net.rsa; + +/** + * The main class that will launch the terminal. + * + * @author lare96 + */ +public final class RSAKeyGenMain { + + /** + * The main method, the point of initialization. + */ + public static void main(String[] args) { + System.out.println("RSAKeyGen v1.0"); + System.out.println("Type (y) to generate new keys."); + System.out.println("Keep in mind that doing this will overwrite existing keys."); + + TerminalReader terminal = new TerminalReader(); + terminal.awaitNextInputMatching("y", new RSAKeyGen()); + } + + /** + * Causes the application to gracefully exit. + */ + static void exit() { + System.out.println("The application will now exit."); + try { + Thread.sleep(3000); + } catch (InterruptedException ignored) { + } + System.exit(0); + } +} \ No newline at end of file diff --git a/src/io/luna/net/rsa/RSAKeyPair.java b/src/io/luna/net/rsa/RSAKeyPair.java new file mode 100644 index 0000000..d0905e0 --- /dev/null +++ b/src/io/luna/net/rsa/RSAKeyPair.java @@ -0,0 +1,94 @@ +package io.luna.net.rsa; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; + +/** + * A model representing a newly generated RSA public and private key pair. + * + * @author lare96 + */ +final class RSAKeyPair { + + /** + * Generates a new RSA key pair. + * + * @return The newly generated RSA key pair. + * @throws NoSuchAlgorithmException If the RSA algorithm is unavailable. + * @throws InvalidKeySpecException If the key specification is invalid. + */ + static RSAKeyPair newKeyPair() throws NoSuchAlgorithmException, InvalidKeySpecException { + + // Initialize RSA key generator. + KeyPairGenerator rsaKeyGen = KeyPairGenerator.getInstance("RSA"); + rsaKeyGen.initialize(1024); + + // Retrieve modulus and exponent values for each key. + KeyPair keypair = rsaKeyGen.genKeyPair(); + KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA"); + RSAPrivateKeySpec privSpec = rsaKeyFactory.getKeySpec(keypair.getPrivate(), RSAPrivateKeySpec.class); + RSAPublicKeySpec pubSpec = rsaKeyFactory.getKeySpec(keypair.getPublic(), RSAPublicKeySpec.class); + + // Store them! + return new RSAKeyPair(privSpec, pubSpec); + } + + /** + * The private key. + */ + private final RSAPrivateKeySpec privateKey; + + /** + * The public key. + */ + private final RSAPublicKeySpec publicKey; + + /** + * Creates a new {@link RSAKeyPair}. + * + * @param privateKey The private key. + * @param publicKey The public key. + */ + private RSAKeyPair(RSAPrivateKeySpec privateKey, RSAPublicKeySpec publicKey) { + this.privateKey = privateKey; + this.publicKey = publicKey; + } + + /** + * Writes the generated keys to the designated files. + * + * @param privateFile The file to store the private key. + * @param publicFile The file to store the public key. + * @throws IOException If any I/O errors occur while writing to the files. + */ + void writeToFile(Path privateFile, Path publicFile) throws IOException { + byte[] privateBytes = getBytes(privateKey.getModulus(), privateKey.getPrivateExponent()); + byte[] publicBytes = getBytes(publicKey.getModulus(), publicKey.getPublicExponent()); + Files.write(privateFile, privateBytes); + Files.write(publicFile, publicBytes); + + System.out.println("RSA private and public keys successfully generated."); + } + + /** + * Returns the bytes detailing the text to write to files. + * + * @param mod The modulus to write. + * @param exp The exponent to write. + * @return The private bytes. + */ + private byte[] getBytes(BigInteger mod, BigInteger exp) { + String writeString = "[key]\n" + "modulus = " + '"' + mod + '"' + '\n' + + "exponent = " + '"' + exp + '"'; + return writeString.getBytes(); + } +} \ No newline at end of file diff --git a/src/io/luna/net/rsa/TerminalReader.java b/src/io/luna/net/rsa/TerminalReader.java new file mode 100644 index 0000000..60ac8c6 --- /dev/null +++ b/src/io/luna/net/rsa/TerminalReader.java @@ -0,0 +1,42 @@ +package io.luna.net.rsa; + +import java.util.Scanner; +import java.util.function.Consumer; + +/** + * A model internally backed by a {@link Scanner} that will read input from the terminal. + * + * @author lare96 + */ +final class TerminalReader { + + /** + * The scanner for reading input. + */ + private final Scanner scanner = new Scanner(System.in); + + /** + * Awaits the next input. Will block indefinitely. + * + * @return The input. + */ + private String awaitNextInput() { + return scanner.next(); + } + + /** + * Awaits the next input matching {@code expected}, then executes {@code onMatching} once the input + * matches. Will block indefinitely. + * + * @param expected The input to await. + * @param onMatching The action to execute when matching. + */ + void awaitNextInputMatching(String expected, Consumer onMatching) { + for (; ; ) { + if (awaitNextInput().equals(expected)) { + onMatching.accept(expected); + break; + } + } + } +} \ No newline at end of file