From 0eb8a6e7e6a045fbf83defd82eb0e424f8d6706f Mon Sep 17 00:00:00 2001 From: Cube Date: Fri, 4 Mar 2016 14:55:04 +0200 Subject: [PATCH 1/3] Move RSA keys to their own file RSA keys are sensitive information that should not be stored in git repositories. This commit moves them to their own file, adds it to .gitignore and provides a template file. --- .gitignore | 1 + data/net.xml | 5 ---- data/rsa.xml.dist | 5 ++++ .../main/org/apollo/net/NetworkConstants.java | 25 ++++++++++++------- 4 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 data/rsa.xml.dist diff --git a/.gitignore b/.gitignore index 4e737abd..993de82c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.iml /data/fs +/data/rsa.xml /data/savedGames /lib/ */target/ diff --git a/data/net.xml b/data/net.xml index 663d2811..8bd75431 100644 --- a/data/net.xml +++ b/data/net.xml @@ -1,9 +1,4 @@ - - 143690958001225849100503496893758066948984921380482659564113596152800934352119496873386875214251264258425208995167316497331786595942754290983849878549630226741961610780416197036711585670124061149988186026407785250364328460839202438651793652051153157765358767514800252431284681765433239888090564804146588087023 - 124425314960550024206991065332877157931472210939505789558012215720454903710618146200843877022273818555405810618059191162604008259757866640421952188957253368398733319663236323097864278319463888334484786055755767881706264786840339899269810859874287402892848784247637729987603089254067178011764721326471352835473 - - 80 43594 diff --git a/data/rsa.xml.dist b/data/rsa.xml.dist new file mode 100644 index 00000000..22506b24 --- /dev/null +++ b/data/rsa.xml.dist @@ -0,0 +1,5 @@ + + + + + \ 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 2be775f3..e16345f7 100644 --- a/net/src/main/org/apollo/net/NetworkConstants.java +++ b/net/src/main/org/apollo/net/NetworkConstants.java @@ -55,15 +55,6 @@ public final class NetworkConstants { throw new IOException("Root node name is not 'net'."); } - XmlNode rsa = net.getChild("rsa"); - Preconditions.checkState(rsa != null, "Root node must have a child named 'rsa'."); - - 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'."); - - RSA_MODULUS = new BigInteger(modulus.getValue()); - RSA_EXPONENT = new BigInteger(exponent.getValue()); - XmlNode ports = net.getChild("ports"); Preconditions.checkState(ports != null, "Root node must have a child named 'ports'."); @@ -76,6 +67,22 @@ public final class NetworkConstants { } catch (Exception exception) { 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'."); + } + + 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'."); + + 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()); + } catch (Exception exception) { + throw new ExceptionInInitializerError(new IOException("Error parsing rsa.xml", exception)); + } } /** From bde4061b8a194528f1574a915115e6e7d957aad3 Mon Sep 17 00:00:00 2001 From: Cube Date: Fri, 4 Mar 2016 18:47:29 +0200 Subject: [PATCH 2/3] 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 From d45b8ef84660464669c995f71e22e53297f611b1 Mon Sep 17 00:00:00 2001 From: Cube Date: Fri, 4 Mar 2016 18:59:02 +0200 Subject: [PATCH 3/3] Remove bouncycastle dependency from util --- net/src/main/org/apollo/net/NetworkConstants.java | 2 +- util/pom.xml | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/net/src/main/org/apollo/net/NetworkConstants.java b/net/src/main/org/apollo/net/NetworkConstants.java index 3de056ab..d91029f0 100644 --- a/net/src/main/org/apollo/net/NetworkConstants.java +++ b/net/src/main/org/apollo/net/NetworkConstants.java @@ -86,7 +86,7 @@ public final class NetworkConstants { RSA_MODULUS = privateKey.getModulus(); RSA_EXPONENT = privateKey.getPrivateExponent(); } catch (Exception exception) { - throw new ExceptionInInitializerError(new IOException("Error parsing id_rsa", exception)); + throw new ExceptionInInitializerError(new IOException("Error parsing rsa.pem", exception)); } } diff --git a/util/pom.xml b/util/pom.xml index f7cfefe1..b66034f5 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -23,11 +23,4 @@ src/test - - - org.bouncycastle - bcprov-jdk15on - - - \ No newline at end of file