package org.geometerplus.expansion.crypto; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; public class Encryptor { private static final String TAG = Encryptor.class.getSimpleName(); private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC"; private EncryptorSetting mEncryptorSetting; public Encryptor(EncryptorSetting setting){ mEncryptorSetting = setting; } public EncryptorSetting getEncryptorSetting() { return mEncryptorSetting; } public String encrypt(String plainText, String deviceID) throws IOException { return processText(plainText, deviceID, Cipher.ENCRYPT_MODE); } public String decrypt(String encryptedText, String deviceID) throws IOException { return processText(encryptedText, deviceID, Cipher.DECRYPT_MODE); } public InputStream encrypt(InputStream plainText, String deviceID) throws IOException { return processText(plainText, deviceID, Cipher.ENCRYPT_MODE); } public InputStream decrypt(InputStream encryptedText, String password) throws IOException { return processText(encryptedText, password, Cipher.DECRYPT_MODE); } private String processText(String inData, String password, int opmode) throws IOException { InputStream inStreamData = null; try { inStreamData = new ByteArrayInputStream(inData.getBytes("UTF8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } InputStream outStreamData = processText(inStreamData, password, opmode); if (outStreamData == null) { return null; } try { return new String(EncryptorUtils.toByteArray(outStreamData), "UTF8"); } catch (IOException e) { System.out.println(TAG + e.getMessage()); } return null; } private InputStream processText(InputStream inData, String password, int opmode) throws IOException { byte[] outData; try { Cipher cipher = createChipher(opmode, password); byte[] inDataArray = EncryptorUtils.toByteArray(inData); outData = cipher.doFinal(inDataArray); } catch (GeneralSecurityException e) { throw new DecryptionError(e); } catch (Exception e) { System.out.println(TAG + e.getMessage()); return inData; } return new ByteArrayInputStream(outData); } public Cipher createChipher(int opmode, String seed) throws GeneralSecurityException, IOException { byte[] rawKey = EncryptorUtils.hmacDigest(seed, mEncryptorSetting.getSalt(), mEncryptorSetting.getHMacAlgorithm()).getBytes("UTF8"); SecretKeySpec skeySpec = new SecretKeySpec(rawKey, mEncryptorSetting.getAlgorithm()); Cipher cipher = Cipher.getInstance(mEncryptorSetting.getCipherAlgorithm()); IvParameterSpec ivSpec = new IvParameterSpec(mEncryptorSetting.getIV()); cipher.init(opmode, skeySpec, ivSpec); return cipher; } public byte[] getRawKeyPBE(char[] seed) throws GeneralSecurityException { PBEKeySpec pbeKeySpec = new PBEKeySpec(seed); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(PBE_ALGORITHM); SecretKey tempKey = keyFactory.generateSecret(pbeKeySpec); SecretKey secretKey = new SecretKeySpec(tempKey.getEncoded(), mEncryptorSetting.getAlgorithm()); byte[] raw = secretKey.getEncoded(); return raw; } public String getEncryptedFilePrefix(){ return mEncryptorSetting.getEncryptedFilePrefix(); } public static class EncryptorSetting { private byte[] mIV = new byte[16]; private String mSalt = ""; private String mAlgorithm = "AES"; private String mHMacAlgorithm = "HmacMD5"; private String mCipherAlgorithm = "AES/CBC/PKCS5Padding"; private String mEncryptedFilePrefix = "okadabook_encrypted_file"; public byte[] getIV() { return mIV; } public void setIV(byte[] IV) { mIV = IV; } public String getSalt() { return mSalt; } public void setSalt(String salt) { mSalt = salt; } public String getAlgorithm() { return mAlgorithm; } public void setAlgorithm(String algorithm) { mAlgorithm = algorithm; } public String getHMacAlgorithm() { return mHMacAlgorithm; } public void setHMacAlgorithm(String HMacAlgorithm) { mHMacAlgorithm = HMacAlgorithm; } public String getCipherAlgorithm() { return mCipherAlgorithm; } public void setCipherAlgorithm(String cipherAlgorithm) { mCipherAlgorithm = cipherAlgorithm; } public String getEncryptedFilePrefix() { return mEncryptedFilePrefix; } public void setEncryptedFilePrefix(String encryptedFilePrefix) { mEncryptedFilePrefix = encryptedFilePrefix; } } }