The fingerprint of your application is a unique value that can be obtained programmatically. This value only exists in the developer's own PC (to sign APKs) or at the runtime in the app.
You can use that value as an encryption key; to get it:
public String getCertificateSHA1Fingerprint(Context context) {
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
int flags = PackageManager.GET_SIGNATURES;
PackageInfo packageInfo = null;
try {
packageInfo = pm.getPackageInfo(packageName, flags);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Signature[] signatures = packageInfo.signatures;
byte[] cert = signatures[0].toByteArray();
InputStream input = new ByteArrayInputStream(cert);
CertificateFactory cf = null;
try {
cf = CertificateFactory.getInstance("X509");
} catch (CertificateException e) {
e.printStackTrace();
}
X509Certificate c = null;
try {
c = (X509Certificate) cf.generateCertificate(input);
} catch (CertificateException e) {
e.printStackTrace();
}
String hexString = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] publicKey = md.digest(c.getEncoded());
hexString = byte2HexFormatted(publicKey);
} catch (NoSuchAlgorithmException | CertificateEncodingException e1) {
e1.printStackTrace();
}
return hexString;
}
private String byte2HexFormatted(byte[] arr) {
StringBuilder str = new StringBuilder(arr.length * 2);
for (int i = 0; i < arr.length; i++) {
String h = Integer.toHexString(arr[i]);
int l = h.length();
if (l == 1) h = "0" + h;
if (l > 2) h = h.substring(l - 2, l);
str.append(h.toUpperCase());
if (i < (arr.length - 1)) str.append(':');
}
return str.toString();
}
With the fingerprint of your app:
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class AES {
public static SecretKey generateKey(String key) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] passphrase = null;
try {
passphrase = digest.digest(key.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
passphrase = Arrays.copyOf(passphrase, 16);
return new SecretKeySpec(passphrase, "AES");
}
public static String encrypt(String message, String key) throws Exception {
byte[] data = message.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, generateKey(key));
byte[] encryptData = cipher.doFinal(data);
return byteArrayToHexString(encryptData);
}
public static String decrypt(String v, String key) throws Exception {
byte[] tmp = hexStringToByteArray(v);
SecretKeySpec spec = new SecretKeySpec(generateKey(key).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, spec);
String result;
try {
result = new String(cipher.doFinal(tmp), StandardCharsets.UTF_8);
} catch (IllegalBlockSizeException e) {
result = v;
}
return result;
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
final protected static char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
public static String byteArrayToHexString(byte[] bytes) {
char[] hexChars = new char[bytes.length*2];
int v;
for(int j=0; j < bytes.length; j++) {
v = bytes[j] & 0xFF;
hexChars[j*2] = hexArray[v>>>4];
hexChars[j*2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
To save the text, you can do it as a preference:
public String getSecret() {
SharedPreferences prefs = getSharedPreferences("com.example.test", Context.MODE_PRIVATE);
String val = prefs.getString("secret", null);
return val;
}
public void setSecret(String secret) {
SharedPreferences.Editor editor = getSharedPreferences("com.example.test", Context.MODE_PRIVATE).edit();
editor.putString("secret", secret).apply();
}
Summary:
String sha1 = getCertificateSHA1Fingerprint(this); // obtenemos huella digital
String message = "hello_world";
String encrypted = AES.encrypt(message, sha1); // encripta texto
setSecret(encrypted);
String secret = getSecret();
Log.e("TEST", secret);
String decrypted = AES.decrypt(secret, sha1);
Log.e("TEST", decrypted);
This code is used in the AndroidStringObfuscator library, which automates this task.