Project: AndroidBillingLibrary
/*
 * Copyright (C) 2010 The Android Open Source Project 
 * 
 * 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 net.robotmedia.billing.utils; 
 
import java.io.UnsupportedEncodingException; 
import java.security.GeneralSecurityException; 
import java.security.spec.KeySpec; 
 
import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
 
/**
 * An obfuscator that uses AES to encrypt data. 
 */
 
public class AESObfuscator { 
    private static final String UTF8 = "UTF-8"
    private static final String KEYGEN_ALGORITHM = "PBEWITHSHAAND256BITAES-CBC-BC"
    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding"
    private static final byte[] IV = 
        { 167471, -8032101, -4772117, -140, -297065, -1274 }; 
    private static final String header = "net.robotmedia.billing.utils.AESObfuscator-1|"
 
    private Cipher mEncryptor; 
    private Cipher mDecryptor; 
 
    public AESObfuscator(byte[] salt, String password) { 
        try { 
            SecretKeyFactory factory = SecretKeyFactory.getInstance(KEYGEN_ALGORITHM); 
            KeySpec keySpec = 
                new PBEKeySpec(password.toCharArray(), salt, 1024256); 
            SecretKey tmp = factory.generateSecret(keySpec); 
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); 
            mEncryptor = Cipher.getInstance(CIPHER_ALGORITHM); 
            mEncryptor.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(IV)); 
            mDecryptor = Cipher.getInstance(CIPHER_ALGORITHM); 
            mDecryptor.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(IV)); 
        } catch (GeneralSecurityException e) { 
            // This can't happen on a compatible Android device. 
            throw new RuntimeException("Invalid environment", e); 
        } 
    } 
 
    public String obfuscate(String original) { 
        if (original == null) { 
            return null
        } 
        try { 
            // Header is appended as an integrity check 
            return Base64.encode(mEncryptor.doFinal((header + original).getBytes(UTF8))); 
        } catch (UnsupportedEncodingException e) { 
            throw new RuntimeException("Invalid environment", e); 
        } catch (GeneralSecurityException e) { 
            throw new RuntimeException("Invalid environment", e); 
        } 
    } 
 
    public String unobfuscate(String obfuscated) throws ValidationException { 
        if (obfuscated == null) { 
            return null
        } 
        try { 
            String result = new String(mDecryptor.doFinal(Base64.decode(obfuscated)), UTF8); 
            // Check for presence of header. This serves as a final integrity check, for cases 
            // where the block size is correct during decryption. 
            int headerIndex = result.indexOf(header); 
            if (headerIndex != 0) { 
                throw new ValidationException("Header not found (invalid data or key)" + ":" + 
                        obfuscated); 
            } 
            return result.substring(header.length(), result.length()); 
        } catch (Base64DecoderException e) { 
            throw new ValidationException(e.getMessage() + ":" + obfuscated); 
        } catch (IllegalBlockSizeException e) { 
            throw new ValidationException(e.getMessage() + ":" + obfuscated); 
        } catch (BadPaddingException e) { 
            throw new ValidationException(e.getMessage() + ":" + obfuscated); 
        } catch (UnsupportedEncodingException e) { 
            throw new RuntimeException("Invalid environment", e); 
        } 
    } 
     
    public class ValidationException extends Exception { 
        public ValidationException() { 
          super(); 
        } 
 
        public ValidationException(String s) { 
          super(s); 
        } 
 
        private static final long serialVersionUID = 1L
    } 
     
}