package org.ripple.power.wallet; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.util.Scanner; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import org.ripple.power.config.LSystem; public class WalletCryptos { public static final String AES = "AES"; private final File _file; public WalletCryptos(File file) { super(); this._file = file; } public String encrypt(String value) throws Exception { return encrypt(value, _file); } public String decrypt(String message) throws Exception { return decrypt(message, _file); } public static class DecryptException extends Exception { /** * */ private static final long serialVersionUID = 1L; public DecryptException(Throwable trowable) { super(trowable); } public DecryptException() { super(); } } public static class EncryptException extends Exception { /** * */ private static final long serialVersionUID = 1L; public EncryptException(Throwable trowable) { super(trowable); } public EncryptException() { super(); } } public static String encrypt(String value, File keyFile) throws GeneralSecurityException, IOException { if (!keyFile.exists()) { KeyGenerator keyGen = KeyGenerator.getInstance(AES); keyGen.init(128); SecretKey sk = keyGen.generateKey(); FileWriter fw = new FileWriter(keyFile); fw.write(byteArrayToHexString(sk.getEncoded())); fw.flush(); fw.close(); } SecretKeySpec sks = getSecretKeySpec(keyFile); Cipher cipher = Cipher.getInstance(AES); cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters()); byte[] encrypted = cipher.doFinal(value.getBytes()); return byteArrayToHexString(encrypted); } public static String decrypt(String message, File keyFile) throws GeneralSecurityException, IOException { SecretKeySpec sks = getSecretKeySpec(keyFile); Cipher cipher = Cipher.getInstance(AES); cipher.init(Cipher.DECRYPT_MODE, sks); byte[] decrypted = cipher.doFinal(hexStringToByteArray(message)); return new String(decrypted); } private static SecretKeySpec getSecretKeySpec(File keyFile) throws NoSuchAlgorithmException, IOException { byte[] key = readKeyFile(keyFile); SecretKeySpec sks = new SecretKeySpec(key, AES); return sks; } private static byte[] readKeyFile(File keyFile) throws FileNotFoundException { Scanner scanner = null; String keyValue; try { scanner = new Scanner(keyFile).useDelimiter("\\Z"); keyValue = scanner.next(); } finally { if (scanner != null) { scanner.close(); } } return hexStringToByteArray(keyValue); } private static String byteArrayToHexString(byte[] b) { StringBuffer sb = new StringBuffer(b.length * 2); for (int i = 0; i < b.length; i++) { int v = b[i] & 0xff; if (v < 16) { sb.append('0'); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(); } private static byte[] hexStringToByteArray(String s) { byte[] b = new byte[s.length() / 2]; for (int i = 0; i < b.length; i++) { int index = i * 2; int v = Integer.parseInt(s.substring(index, index + 2), 16); b[i] = (byte) v; } return b; } public static byte[] encrypt(String passphrase, byte[] plaintext) throws EncryptException { try { SecretKeySpec key = getKey(passphrase); return encrypt(key, plaintext); } catch (NoSuchAlgorithmException t) { throw new EncryptException(t); } catch (InvalidKeySpecException t) { throw new EncryptException(t); } catch (InvalidKeyException t) { throw new EncryptException(t); } catch (NoSuchPaddingException t) { throw new EncryptException(t); } catch (IllegalBlockSizeException t) { throw new EncryptException(t); } catch (BadPaddingException t) { throw new EncryptException(t); } catch (UnsupportedEncodingException t) { throw new EncryptException(t); } } public static byte[] decrypt(String passphrase, byte[] ciphertext) throws DecryptException { try { SecretKeySpec key = getKey(passphrase); return decrypt(key, ciphertext); } catch (Exception t) { throw new DecryptException(t); } } private static SecretKeySpec getKey(String passphrase) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException { byte[] salt = makeSHA1Hash( passphrase + "my name cping is very cool !RE%$%$67opop00943% " + passphrase + " ").getBytes(LSystem.encoding); int iterations = 10000; SecretKeyFactory factory = SecretKeyFactory .getInstance("PBKDF2WithHmacSHA1"); SecretKey tmp = factory.generateSecret(new PBEKeySpec(passphrase .toCharArray(), salt, iterations, 128)); return new SecretKeySpec(tmp.getEncoded(), AES); } private static byte[] encrypt(SecretKeySpec key, byte[] plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); aes.init(Cipher.ENCRYPT_MODE, key); return aes.doFinal(plaintext); } private static byte[] decrypt(SecretKeySpec key, byte[] ciphertext) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException { Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); aes.init(Cipher.DECRYPT_MODE, key); return aes.doFinal(ciphertext); } public static String makeSHA1Hash(String input) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md = MessageDigest.getInstance("SHA1"); md.reset(); byte[] buffer = input.getBytes(LSystem.encoding); md.update(buffer); byte[] digest = md.digest(); String hexStr = ""; for (int i = 0; i < digest.length; i++) { hexStr += Integer.toString((digest[i] & 0xff) + 0x100, 16) .substring(1); } return hexStr; } }