/*
 * Copyright 2011 Uwe Trottmann
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

package com.battlelancer.seriesguide.util;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import com.battlelancer.seriesguide.ui.SeriesGuidePreferences;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * Usage:
 * 
 * <pre>
 * String crypto = SimpleCrypto.encrypt(cleartext)
 * ...
 * String cleartext = SimpleCrypto.decrypt(crypto)
 * </pre>
 * 
 * @author ferenc.hechler, modified by Uwe Trottmann for SeriesGuide
 */
public class SimpleCrypto {

    public static String encrypt(String cleartext, Context context) throws Exception {
        byte[] rawKey = getRawKey(context);
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
    }

    public static String decrypt(String encrypted, Context context) throws Exception {
        byte[] rawKey = getRawKey(context);
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
    }

    private static byte[] getRawKey(Context context) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context
                .getApplicationContext());
        String seed = prefs.getString(SeriesGuidePreferences.KEY_SECURE, null);
        byte[] seedBytes;
        if (seed == null) {
            seedBytes = sr.generateSeed(16);
            seed = toHex(seedBytes);
            prefs.edit().putString(SeriesGuidePreferences.KEY_SECURE, seed).commit();
        } else {
            seedBytes = toByte(seed);
        }
        sr.setSeed(seedBytes);

        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }

    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }

    public static String toHex(String txt) {
        return toHex(txt.getBytes());
    }

    public static String fromHex(String hex) {
        return new String(toByte(hex));
    }

    public static byte[] toByte(String hexString) {
        int len = hexString.length() / 2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
        return result;
    }

    public static String toHex(byte[] b) {
        String result = "";
        for (int i = 0; i < b.length; i++) {
            result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
        }
        return result;
    }

}

@@ -957,285 +957,152 @@
 ey;%0A
-import javax.crypto.spec.SecretKeySpec;%0A%0A/**%0A * Usage:%0A * %0A * %3Cpre%3E%0A * String crypto = SimpleCrypto.encrypt(cleartext)%0A * ...%0A * String cleartext = SimpleCrypto.decrypt(crypto)%0A * %3C/pre%3E%0A * %0A * @author ferenc.hechler, modified by Uwe Trottmann for SeriesGuide%0A */%0Apublic class 
+%0A/**%0A * Symmetrically encrypts and decrypts strings using a seeded key.%0A */%0Apublic class SimpleCrypto %7B%0A%0A    private static final String TAG = %22
 Simp
@@ -1105,26 +1105,26 @@
 SimpleCrypto
- %7B
+%22;
 %0A%0A    public
@@ -1208,35 +1208,111 @@
         
-byte%5B%5D rawK
+// TODO: use better handling than throwing around random exceptions%0A        SecretKey k
 ey = get
 RawKey(c
@@ -1295,35 +1295,32 @@
 retKey key = get
-Raw
 Key(context);%0A  
@@ -1345,28 +1345,25 @@
 t = encrypt(
-rawK
+k
 ey, cleartex
@@ -1513,27 +1513,103 @@
     
-byte%5B%5D rawK
+// TODO: use better handling than throwing around random exceptions%0A        SecretKey k
 ey = get
 RawK
@@ -1600,27 +1600,24 @@
 ey key = get
-Raw
 Key(context)
@@ -1694,12 +1694,9 @@
 ypt(
-rawK
+k
 ey, 
@@ -1766,21 +1766,21 @@
 tic 
-byte%5B%5D
+SecretKey
  get
-Raw
 Key(
@@ -1837,17 +1837,19 @@
 erator k
-g
+eyG
 en = Key
@@ -2482,17 +2482,19 @@
        k
-g
+eyG
 en.init(
@@ -2566,17 +2566,18 @@
 Key 
-s
 key = k
-g
+eyG
 en.g
@@ -2594,48 +2594,8 @@
 ();%0A
-        byte%5B%5D raw = skey.getEncoded();%0A
     
@@ -2605,19 +2605,19 @@
  return 
-raw
+key
 ;%0A    %7D%0A
@@ -2647,34 +2647,37 @@
 e%5B%5D encrypt(
-byte%5B%5D raw
+SecretKey key
 , byte%5B%5D cle
@@ -2703,72 +2703,8 @@
 n %7B%0A
-        SecretKeySpec skeySpec = new SecretKeySpec(raw, %22AES%22);%0A
     
@@ -2787,32 +2787,27 @@
 CRYPT_MODE, 
-s
 key
-Spec
 );%0A        b
@@ -2918,18 +2918,21 @@
 ypt(
-byte%5B%5D raw
+SecretKey key
 , by
@@ -2970,72 +2970,8 @@
 n %7B%0A
-        SecretKeySpec skeySpec = new SecretKeySpec(raw, %22AES%22);%0A
     
@@ -3062,16 +3062,11 @@
 DE, 
-s
 key
-Spec
 );%0A 

Clean up SimpleCrypto a bit.