package com.mobilesorcery.sdk.internal; import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.security.spec.KeySpec; import java.util.HashMap; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import com.mobilesorcery.sdk.core.IPropertyOwner; import com.mobilesorcery.sdk.core.Util; /** * A property that is encrypted. * * @author Mattias Bybro TODO: Maybe extract this into IProperty? */ public class SecureProperty { private String NULL_VALUE = "__NULL__"; public String CIPHER = "PBEWithMD5AndDES"; //$NON-NLS-1$ public String KEY_FACTORY = "PBEWithMD5AndDES"; //$NON-NLS-1$ private KeySpec password; private IPropertyOwner delegate; private String cachedValue; private String key; public SecureProperty(IPropertyOwner delegate, String key, PBEKeySpec password) { this.password = password; this.key = key; this.delegate = delegate; } private Cipher createCipher(int mode) { SecretKeyFactory keyFactory; try { keyFactory = SecretKeyFactory.getInstance(KEY_FACTORY); SecretKey key = keyFactory.generateSecret(password); byte[] salt = new byte[8]; SecureRandom random = new SecureRandom(); random.nextBytes(salt); PBEParameterSpec entropy = new PBEParameterSpec(salt, 12); Cipher cipher = Cipher.getInstance(CIPHER); cipher.init(mode, key, entropy); return cipher; } catch (Exception e) { return null; } } String encrypt(String value) throws GeneralSecurityException { if (value == null) { return null; } Cipher c = createCipher(Cipher.ENCRYPT_MODE); byte[] result = c.doFinal(value.getBytes(Charset.forName("UTF8"))); return Util.toBase16(result); } String decrypt(String value) throws GeneralSecurityException { if (value == null) { return null; } byte[] toDecrypt = Util.fromBase16(value); Cipher c = createCipher(Cipher.DECRYPT_MODE); byte[] result; result = c.doFinal(toDecrypt); return new String(result, Charset.forName("UTF8")); } public void set(String value) throws GeneralSecurityException { cachedValue = value == null ? NULL_VALUE : value; String encrypted = value == null ? null : encrypt(value); delegate.setProperty(key, encrypted); } public String get() throws GeneralSecurityException { if (cachedValue == null) { cachedValue = decryptValue(); } else if (cachedValue == NULL_VALUE) { return null; } return cachedValue; } private String decryptValue() throws GeneralSecurityException { String encrypted = delegate.getProperty(key); if (encrypted == null) { return NULL_VALUE; } return decrypt(encrypted); } }