Store RSA in a PEM file instead of xml

- RsaKeyGenerator automatically saves the RSA keys in a PEM file
- Corrects key bit size suggestion
This commit is contained in:
Cube
2016-03-04 18:47:29 +02:00
parent 0eb8a6e7e6
commit bde4061b8a
6 changed files with 71 additions and 39 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
*.iml
/data/fs
/data/rsa.xml
/data/rsa.pem
/data/savedGames
/lib/
*/target/
-5
View File
@@ -1,5 +0,0 @@
<rsa>
<!-- Generate keys with RsaKeyGenerator and place them here -->
<modulus></modulus>
<private-exponent></private-exponent>
</rsa>
@@ -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));
}
}
+7
View File
@@ -81,6 +81,12 @@
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.54</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -101,6 +107,7 @@
<version>1.6.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
+8
View File
@@ -22,4 +22,12 @@
<sourceDirectory>src/main</sourceDirectory>
<testSourceDirectory>src/test</testSourceDirectory>
</build>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
</dependencies>
</project>
@@ -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. <strong>Strongly</strong> recommended to be at least 2,048.
* The bit count.
* <strong>Note:</strong> 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();
}
}
}