/* Athena/Aegis Encrypted Chat Platform * RSACrypto.java: Provides access to RSA cryptography libraries * * Copyright (C) 2010 OlympuSoft * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import javax.crypto.Cipher; import sun.misc.BASE64Encoder; /** * RSA Cryptography library methods * @author OlympuSoft */ public class RSACrypto { // The public and private keys that are used throughout the program private static RSAPublicKeySpec pub; private static RSAPrivateKeySpec priv; /** * Retrieve the publickeyspec * @return Public key spec */ public static RSAPublicKeySpec getPublicKey() { return pub; } /** * Retrieve the privatekeyspec * @return The private key spec */ public static RSAPrivateKeySpec getPrivateKey() { return priv; } /** * This method will generate the users RSA key files, one public and one private */ public static void generateRSAKeyPair() { try { // Define type of encryption for which these keys are made KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); // Define key size kpg.initialize(2048); // Generate the key pairs KeyPair kp = kpg.genKeyPair(); Key publicKey = kp.getPublic(); Key privateKey = kp.getPrivate(); KeyFactory fact = KeyFactory.getInstance("RSA"); // Define public key pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class); //Define private key priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class); } catch (Exception e) { System.out.println("An error has occured in 'generateRSAKeyPair'"); } } /** * Encrypt a message using a provided public key * @param plainText Plaintext message * @param mod Modulus of the public key * @param exp Exponent of the public key * @return Byte[] of the encrypted message */ public static byte[] rsaEncryptPublic(String plainText, BigInteger mod, BigInteger exp) { try { //Grab the key from this file PublicKey pubKey = makePublicKey(mod, exp); //Define the cipher style //RSA OF COURSE Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); //That's right, cipherData, you wish you knew what the message was. byte[] cipherData = cipher.doFinal(plainText.getBytes()); return cipherData; } catch (Exception e) { System.out.println("An error has occured in 'rsaEncryptPublic'"); } return null; } /** * Decrypt a message using a provided public key * @param cipherText The encrypted message byte[] * @param mod Modulus of the public key * @param exp Exponent of the public key * @return The decrypted message as a string */ public static String rsaDecryptPublic(byte[] cipherText, BigInteger mod, BigInteger exp) { try { //Grab the key from this file PublicKey pubKey = makePublicKey(mod, exp); //Define the cipher style //RSA OF COURSE Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, pubKey); //That's right, cipherData, you wish you knew what the message was. byte[] cipherData = cipher.doFinal(cipherText); String plainText = new String(cipherData); return plainText; } catch (Exception e) { e.printStackTrace(); return "SYSTEM ERROR: There was an issue decrypting the message. Please check that you have the public keyfile for the user."; //System.out.println("An error has occured in 'rsaDecryptPublic'"); }//return null; } /** * Encrypt a message using a provided private key * @param plainText The plaintext message to be encrypted * @param mod The modulus part of the private key * @param exp The exponent part of the private key * @return The encrypted message as a byte[] */ public static byte[] rsaEncryptPrivate(String plainText, BigInteger mod, BigInteger exp) { try { //Grab the key from this file PrivateKey privKey = makePrivateKey(mod, exp); //Define the cipher style //RSA OF COURSE Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privKey); //That's right, cipherData, you wish you knew what the message was. byte[] cipherData = cipher.doFinal(plainText.getBytes()); return cipherData; } catch (Exception e) { //return "SYSTEM ERROR: There was an issue encrypting the message. Please check your private key"; System.out.println("An error has occured in 'rsaEncryptPrivate'"); } return null; } public static void rsaExportPrivate(BigInteger mod, BigInteger exp, String username){ try{ BufferedOutputStream oout = new BufferedOutputStream(new FileOutputStream("users/"+username+"/keys/"+username+"Private.pem")); PrivateKey privKey = makePrivateKey(mod, exp); BASE64Encoder myB64 = new BASE64Encoder(); String b64 = myB64.encode(privKey.getEncoded()); oout.write("-----BEGIN PRIVATE KEY----\r\n-".getBytes()); oout.write(b64.getBytes()); oout.write("\r\n".getBytes()); oout.write("-----END PRIVATE KEY-----\r\n".getBytes()); oout.flush(); oout.close(); }catch (Exception e){} } public static void rsaExportPublic(BigInteger mod, BigInteger exp, String username){ try{ BufferedOutputStream oout = new BufferedOutputStream(new FileOutputStream("users/"+username+"/keys/"+username+"Public.pem")); PrivateKey privKey = makePrivateKey(mod, exp); BASE64Encoder myB64 = new BASE64Encoder(); String b64 = myB64.encode(privKey.getEncoded()); oout.write("-----BEGIN PRIVATE KEY----\r\n-".getBytes()); oout.write(b64.getBytes()); oout.write("\r\n".getBytes()); oout.write("-----END PRIVATE KEY-----\r\n".getBytes()); oout.flush(); oout.close(); }catch (Exception e){} } /** * Decrypt a message using a provided private key * @param cipherText Byte[] of the encrypted message * @param mod Modulus part of the private key * @param exp Exponent part of the private key * @return The decrypted message as a string */ public static String rsaDecryptPrivate(byte[] cipherText, BigInteger mod, BigInteger exp) { try { //Grab the key from this file PrivateKey privKey = makePrivateKey(mod, exp); //Define the cipher style //RSA OF COURSE Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privKey); //That's right, cipherData, you wish you knew what the message was. byte[] cipherData = cipher.doFinal(cipherText); String plainText = new String(cipherData); return plainText; } catch (Exception e) { return "SYSTEM ERROR: There was an issue decrypting the message. Please check your private key"; } } /** * Puts a public key together using a modulus and exponent * @param mod Modulus piece of the public key * @param exp Exponent piece of the public key * @return The public key constructed */ public static PublicKey makePublicKey(BigInteger mod, BigInteger exp) { RSAPublicKeySpec keySpec = new RSAPublicKeySpec(mod, exp); KeyFactory fact = null; PublicKey pubKey = null; try { fact = KeyFactory.getInstance("RSA"); } catch (Exception e) { System.out.println("KeyFactory issue in makePublicKey"); } try { pubKey = fact.generatePublic(keySpec); } catch (Exception e) { System.out.println("KeyFactory issue in makePublicKey"); } return pubKey; } /** * Creates a private key using a modulus and exponent * @param mod The modulus piece of the private key * @param exp The exponent piece of the private key * @return The private key constructed */ public static PrivateKey makePrivateKey(BigInteger mod, BigInteger exp) { RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(mod, exp); KeyFactory fact = null; PrivateKey privKey = null; try { fact = KeyFactory.getInstance("RSA"); } catch (Exception e) { System.out.println("KeyFactory issue in makePublicKey"); } try { privKey = fact.generatePrivate(keySpec); } catch (Exception e) { System.out.println("KeyFactory issue in makePublicKey"); } return privKey; } /** * Load a public key from a file * @param The filename of the public key * @return The public key read in from the file * @throws IOException */ static RSAPublicKeySpec readPubKeyFromFile(String keyFileName) throws IOException { //Define the name of the file //MAKE sure it's the same as the one we're looking for! ObjectInputStream oin = new ObjectInputStream(new FileInputStream(keyFileName)); try { BigInteger m = (BigInteger) oin.readObject(); BigInteger e = (BigInteger) oin.readObject(); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e); return keySpec; } catch (Exception e) { throw new RuntimeException("An error has occured in 'readKeyFromFile'", e); } finally { //Close the file stream oin.close(); } } /** * Load a private key from a file * @param keyFileName Filename * @param descrypto The DESCrypto object to decrypt the keyfile * @return The private key * @throws IOException */ static RSAPrivateKeySpec readPrivKeyFromFile(String keyFileName, DESCrypto descrypto) throws IOException { //This is how we'll get the file ObjectInputStream oin = null; try { //Make sure this selects the correct file! oin = new ObjectInputStream(new FileInputStream(keyFileName)); //Grab the m and e values for the RSA key file process BigInteger m = (BigInteger) oin.readObject(); BigInteger e = (BigInteger) oin.readObject(); byte[] modBytes = new BigInteger(m.toString()).toByteArray(); byte[] expBytes = new BigInteger(e.toString()).toByteArray(); BigInteger modDecrypted = new BigInteger(descrypto.decryptData(modBytes)); BigInteger expDecrypted = new BigInteger(descrypto.decryptData(expBytes)); //Run RSA Private Key input RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modDecrypted, expDecrypted); //Return the private key return keySpec; } catch (Exception e) { e.printStackTrace(); System.out.println("An error has occured in readPrivKeyFromFile"); } finally { oin.close(); } return null; } /** * Save a key to a file * @param fileName File to write to * @param mod Modulus * @param exp Exponent * @throws IOException */ public static void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException { //Define the new file ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName))); try { //Write the files oout.writeObject(mod); oout.writeObject(exp); } catch (Exception e) { throw new IOException("Unexpected error", e); } finally { oout.close(); } } }