From bde4061b8a194528f1574a915115e6e7d957aad3 Mon Sep 17 00:00:00 2001 From: Cube Date: Fri, 4 Mar 2016 18:47:29 +0200 Subject: [PATCH] Store RSA in a PEM file instead of xml - RsaKeyGenerator automatically saves the RSA keys in a PEM file - Corrects key bit size suggestion --- .gitignore | 2 +- data/rsa.xml.dist | 5 -- .../main/org/apollo/net/NetworkConstants.java | 33 ++++++----- pom.xml | 7 +++ util/pom.xml | 8 +++ .../apollo/util/tools/RsaKeyGenerator.java | 55 ++++++++++++------- 6 files changed, 71 insertions(+), 39 deletions(-) delete mode 100644 data/rsa.xml.dist diff --git a/.gitignore b/.gitignore index 993de82c..ff7341dc 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ *.iml /data/fs -/data/rsa.xml +/data/rsa.pem /data/savedGames /lib/ */target/ diff --git a/data/rsa.xml.dist b/data/rsa.xml.dist deleted file mode 100644 index 22506b24..00000000 --- a/data/rsa.xml.dist +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/net/src/main/org/apollo/net/NetworkConstants.java b/net/src/main/org/apollo/net/NetworkConstants.java index e16345f7..3de056ab 100644 --- a/net/src/main/org/apollo/net/NetworkConstants.java +++ b/net/src/main/org/apollo/net/NetworkConstants.java @@ -1,14 +1,21 @@ package org.apollo.net; import java.io.FileInputStream; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; - -import org.apollo.util.xml.XmlNode; -import org.apollo.util.xml.XmlParser; +import java.security.KeyFactory; +import java.security.Security; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; import com.google.common.base.Preconditions; +import org.apollo.util.xml.XmlNode; +import org.apollo.util.xml.XmlParser; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; /** * Holds various network-related constants such as port numbers. @@ -68,20 +75,18 @@ public final class NetworkConstants { throw new ExceptionInInitializerError(new IOException("Error parsing net.xml.", exception)); } - try (InputStream is = new FileInputStream("data/rsa.xml")) { - XmlNode rsa = new XmlParser().parse(is); - if (!rsa.getName().equals("rsa")) { - throw new IOException("Root node name is not 'rsa'."); - } + try (PemReader pemReader = new PemReader(new FileReader("data/rsa.pem"))) { + PemObject pem = pemReader.readPemObject(); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pem.getContent()); - XmlNode modulus = rsa.getChild("modulus"), exponent = rsa.getChild("private-exponent"); - Preconditions.checkState(modulus != null && exponent != null, "Rsa node must have two children: 'modulus' and 'private-exponent'."); + Security.addProvider(new BouncyCastleProvider()); + KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); - Preconditions.checkState(modulus.getValue() != null && exponent.getValue() != null, "Value missing for 'modulus' or 'private-exponent'"); - RSA_MODULUS = new BigInteger(modulus.getValue()); - RSA_EXPONENT = new BigInteger(exponent.getValue()); + RSAPrivateKey privateKey = (RSAPrivateKey) factory.generatePrivate(keySpec); + RSA_MODULUS = privateKey.getModulus(); + RSA_EXPONENT = privateKey.getPrivateExponent(); } catch (Exception exception) { - throw new ExceptionInInitializerError(new IOException("Error parsing rsa.xml", exception)); + throw new ExceptionInInitializerError(new IOException("Error parsing id_rsa", exception)); } } diff --git a/pom.xml b/pom.xml index 4e28c1c5..3e768ffc 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,12 @@ 0.9.5.2 + + org.bouncycastle + bcprov-jdk15on + 1.54 + + junit junit @@ -101,6 +107,7 @@ 1.6.4 test + \ No newline at end of file diff --git a/util/pom.xml b/util/pom.xml index 2b15f1a9..f7cfefe1 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -22,4 +22,12 @@ src/main src/test + + + + org.bouncycastle + bcprov-jdk15on + + + \ No newline at end of file diff --git a/util/src/main/org/apollo/util/tools/RsaKeyGenerator.java b/util/src/main/org/apollo/util/tools/RsaKeyGenerator.java index 0f0285f2..5bfc37a4 100644 --- a/util/src/main/org/apollo/util/tools/RsaKeyGenerator.java +++ b/util/src/main/org/apollo/util/tools/RsaKeyGenerator.java @@ -1,45 +1,62 @@ package org.apollo.util.tools; -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Random; +import java.io.FileWriter; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; /** * An RSA key generator. * * @author Graham * @author Major + * @author Cube */ public final class RsaKeyGenerator { /** - * The bit count. Strongly recommended to be at least 2,048. + * The bit count. + * Note: 2048 bits and above are not compatible with the client without modifications */ - private static final int BIT_COUNT = 2_048; + private static final int BIT_COUNT = 1024; + + /** + * The path to the private key file. + */ + private static final String PRIVATE_KEY_FILE = "data/rsa.pem"; /** * The entry point of the RsaKeyGenerator. * * @param args The application arguments. */ - public static void main(String[] args) { - Random random = new SecureRandom(); + public static void main(String[] args) throws Exception { + Security.addProvider(new BouncyCastleProvider()); - BigInteger publicKey = BigInteger.valueOf(65_537); - BigInteger p, q, phi, modulus, privateKey; + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC"); + keyPairGenerator.initialize(BIT_COUNT); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); - do { - p = BigInteger.probablePrime(BIT_COUNT / 2, random); - q = BigInteger.probablePrime(BIT_COUNT / 2, random); - phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE)); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); - modulus = p.multiply(q); - privateKey = publicKey.modInverse(phi); - } while (modulus.bitLength() != BIT_COUNT || privateKey.bitLength() != BIT_COUNT || !phi.gcd(publicKey).equals(BigInteger.ONE)); + System.out.println("Place these keys in the client:"); + System.out.println("--------------------"); + System.out.println("public key: " + publicKey.getPublicExponent()); + System.out.println("modulus: " + publicKey.getModulus()); - System.out.println("modulus: " + modulus); - System.out.println("public key: " + publicKey); - System.out.println("private key: " + privateKey); + try (PemWriter writer = new PemWriter(new FileWriter(PRIVATE_KEY_FILE))) { + writer.writeObject(new PemObject("RSA PRIVATE KEY", privateKey.getEncoded())); + } catch (Exception e) { + System.err.println("Failed to write private key to " + PRIVATE_KEY_FILE); + e.printStackTrace(); + } } } \ No newline at end of file