package me.guard.car;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.json.JSONObject;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.HashMap;
import java.util.Map;

public class EncryptedJSONObject extends JSONObject {
  private final Cipher cipher;

  public EncryptedJSONObject() {
    this(new HashMap());
  }

  public EncryptedJSONObject(Map copyFrom) {
    super(copyFrom);

    try {
      cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    } catch (NoSuchAlgorithmException e) {
      throw fail(e);
    } catch (NoSuchPaddingException e) {
      throw fail(e);
    }
  }

  @Override
  public String toString() {
    final String salt = random(32);
    final String iv = random(16);
    final String unencryptedData = super.toString();
    HashMap<String, Object> encryptedData = new HashMap<String, Object>() {{
      put("salt", salt);
      put("iv", iv);
      put("data", encrypt(salt, iv, "fooobaar", unencryptedData));
    }};

    return new JSONObject(encryptedData).toString();
  }

  private String encrypt(String salt, String iv, String passPhrase, String plainText) {
    try {
      SecretKey key = generateKey(salt, passPhrase);
      byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, iv, plainText.getBytes("UTF-8"));
      return base64(encrypted);
    } catch (UnsupportedEncodingException e) {
      throw fail(e);
    }
  }

  public String decrypt(String salt, String iv, String passPhrase, String cipherText) {
    try {
      SecretKey key = generateKey(salt, passPhrase);
      byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(cipherText));
      return new String(decrypted, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw fail(e);
    }
  }

  private byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {
    try {
      cipher.init(encryptMode, key, new IvParameterSpec(hex(iv)));
      return cipher.doFinal(bytes);
    } catch (InvalidKeyException e) {
      throw fail(e);
    } catch (InvalidAlgorithmParameterException e) {
      throw fail(e);
    } catch (IllegalBlockSizeException e) {
      throw fail(e);
    } catch (BadPaddingException e) {
      throw fail(e);
    }
  }

  private SecretKey generateKey(String salt, String passphrase) {
    try {
      SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
      KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), 10000, 128);
      return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    } catch (NoSuchAlgorithmException e) {
      throw fail(e);
    } catch (InvalidKeySpecException e) {
      throw fail(e);
    }
  }

  public static String random(int length) {
    byte[] salt = new byte[length];
    new SecureRandom().nextBytes(salt);
    return hex(salt);
  }

  public static String base64(byte[] bytes) {
    return new String(Base64.encodeBase64(bytes));
  }

  public static byte[] base64(String str) {
    return Base64.decodeBase64(str.getBytes());
  }

  public static String hex(byte[] bytes) {
    return new String(Hex.encodeHex(bytes));
  }

  public static byte[] hex(String str) {
    try {
      return Hex.decodeHex(str.toCharArray());
    } catch (DecoderException e) {
      throw new IllegalStateException(e);
    }
  }

  private IllegalStateException fail(Exception e) {
    return new IllegalStateException(e);
  }
}

@@ -779,71 +779,8 @@
 r;%0A%0A
-  public EncryptedJSONObject() %7B%0A    this(new HashMap());%0A  %7D%0A%0A
   pu
@@ -816,24 +816,24 @@
 copyFrom) %7B%0A
+
     super(co
@@ -1828,367 +1828,8 @@
  %7D%0A%0A
-  public String decrypt(String salt, String iv, String passPhrase, String cipherText) %7B%0A    try %7B%0A      SecretKey key = generateKey(salt, passPhrase);%0A      byte%5B%5D decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(cipherText));%0A      return new String(decrypted, %22UTF-8%22);%0A    %7D catch (UnsupportedEncodingException e) %7B%0A      throw fail(e);%0A    %7D%0A  %7D%0A%0A
   pr
@@ -2941,32 +2941,32 @@
 byte%5B%5D bytes) %7B%0A
+
     return new S
@@ -3009,105 +3009,8 @@
  %7D%0A%0A
-  public static byte%5B%5D base64(String str) %7B%0A    return Base64.decodeBase64(str.getBytes());%0A  %7D%0A%0A
   pu

Remove unused methods.