How to decrypt password in android? - android

i am working on one project which Uses AccessibilityService class of android.
Getting Password through AccessibillityService ( TYPE_VIEW_TEXT_CHANGED ) .
But Password is in form of dots ........... .
How to convert these dots to text string?
or
is there is any possible decryption solution ?
Thanks

Create a Key Object, using the KeyGenerator, for the DESede
algorithm.
Create a Cipher that implements the DESede transformation, with the
getInstance(String algorithm) API method.
Here is code:-
public class Main {
static String algorithm = "DESede";
public static void main(String[] args) throws Exception {
Key symKey = KeyGenerator.getInstance(algorithm).generateKey();
Cipher c = Cipher.getInstance(algorithm);
byte[] encryptionBytes = encryptF("texttoencrypt", symKey, c);
System.out.println("Decrypted: " + decryptF(encryptionBytes, symKey, c));
}
private static byte[] encryptF(String input, Key pkey, Cipher c) throws InvalidKeyException, BadPaddingException,
IllegalBlockSizeException {
c.init(Cipher.ENCRYPT_MODE, pkey);
byte[] inputBytes = input.getBytes();
return c.doFinal(inputBytes);
}
private static String decryptF(byte[] encryptionBytes, Key pkey, Cipher c) throws InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
c.init(Cipher.DECRYPT_MODE, pkey);
byte[] decrypt = c.doFinal(encryptionBytes);
String decrypted = new String(decrypt);
return decrypted;
}
}

Related

How to store multiple variables in AndroidKeystore?

I'm trying to use Biometric and EncryptedSharedPreferences to store multi passwords of a user in the AndroidKeystore (and in the StrongBox).
I'm trying it, but I can't get to store more than one. I explain it below:
We store a string value by passing a keyalias for the keystore and the key-value we want to save. Example:
KEYALIAS: FIRSTKS
KEY: password1
VALUE: 123abc
If we try to read the value, we get it without problem.
If we try to save another value in FIRSTKS, the previously stored value is lost and only the new saved value is found.
KEYALIAS: FIRSTKS
KEY: password2
VALUE: 456def
If I try to read password1, the value is not found.
I can only store new values if I create a different keyalias. Example:
KEYALIAS: FIRSTKS
KEY: password1
VALUE: 123abc
KEYALIAS: SECONDKS
KEY: password2
VALUE: 456def
I don't know if this is a normal behaviour or not.
I guess my biometrics methods to access encrypt and decrypt are OK because if not, I wouldn't be able to read the values. But I leave my cryptographic class to see if you see any errors in the logic.
public class CryptographicUtils {
private static final String TAG = "CrytographicUtils";
/**
* Transforms Byte array into Hexadecimal String.
*
* #param buf Byte array to be transformed.
* #return String.
*/
public static String asHex(byte[] buf) {
StringBuilder strum = new StringBuilder(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strum.append("0");
}
strum.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strum.toString();
}
/**
* Transforms Hexadecimal String into Byte array.
*
* #param string String to be transformed.
* #return Byte array,
*/
public static byte[] fromHexString(String string) {
int len = string.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(string.charAt(i), 16) << 4)
+ Character.digit(string.charAt(i + 1), 16));
}
return data;
}
/**
* Generates the Biometric Key.
*
* #param context Context.
*/
public static void generateBiometricKey(Context context, String keyAlias, boolean userAuthenticationRequired, int validationTimeout) {
try {
KeyGenParameterSpec.Builder spec = new KeyGenParameterSpec.Builder(
keyAlias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
spec.setBlockModes(KeyProperties.BLOCK_MODE_CBC);
spec.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
spec.setKeySize(256);
spec.setUserAuthenticationRequired(userAuthenticationRequired);
spec.setUserAuthenticationValidityDurationSeconds(validationTimeout);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M ) {
spec.setInvalidatedByBiometricEnrollment(userAuthenticationRequired);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
boolean hasStrongBox = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
spec.setDigests(KeyProperties.DIGEST_SHA256);
spec.setIsStrongBoxBacked(hasStrongBox);
}
generateSecretKey(spec.build());
} catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
Toast.makeText(context,
"Authentication error: " + e.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
/**
* Generates the Biometric Secret Key.
*
* #param keyGenParameterSpec Key Generator.
* #throws NoSuchProviderException Exception with Security Provider.
* #throws NoSuchAlgorithmException Exception with cryptographic algorithm.
* #throws InvalidAlgorithmParameterException Exception for invalid or inappropriate algorithm parameters.
*/
private static void generateSecretKey(KeyGenParameterSpec keyGenParameterSpec) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(keyGenParameterSpec);
keyGenerator.generateKey();
}
/**
* Obtains a Secret Key.
*
* #return Secret Key.
* #throws KeyStoreException KeyStore exception.
* #throws CertificateException Exception of certificate problems.
* #throws NoSuchAlgorithmException Exception with cryptographic algorithm.
* #throws IOException I/O exception.
* #throws UnrecoverableKeyException Exception key in the keystore cannot be recovered
*/
public static SecretKey getSecretKey(String keyAlias) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
// Before the keystore can be accessed, it must be loaded.
keyStore.load(null);
return ((SecretKey) keyStore.getKey(keyAlias, null));
}
/**
* Obtains a Cipher.
*
* #return Cipher.
* #throws NoSuchPaddingException Exception padding mechanism is not available in the environment.
* #throws NoSuchAlgorithmException Exception with cryptographic algorithm.
*/
public static Cipher getEncryptCipher(Context context, String keyAlias, boolean userAuthenticationRequired, int validationTimeout) throws NoSuchPaddingException, NoSuchAlgorithmException, KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, InvalidKeyException {
CryptographicUtils.generateBiometricKey(context, keyAlias, userAuthenticationRequired, validationTimeout);
Cipher res = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
SecretKey secretKey = getSecretKey(keyAlias);
res.init(Cipher.ENCRYPT_MODE, secretKey);
return res;
}
/**
* Obtains a Decrypt Cipher.
*
* #throws NoSuchPaddingException Exception padding mechanism is not available in the environment.
* #throws NoSuchAlgorithmException Exception with cryptographic algorithm.
* #throws InvalidAlgorithmParameterException Exception for invalid or inappropriate algorithm parameters.
* #throws InvalidKeyException Exception for invalid Keys.
*/
public static Cipher getDecryptCipher(String keyAlias, String ivString) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, UnrecoverableKeyException, CertificateException, KeyStoreException, IOException {
SecretKey secretKey = CryptographicUtils.getSecretKey(keyAlias);
String algorithm = KeyProperties.KEY_ALGORITHM_AES;
String blockMode = KeyProperties.BLOCK_MODE_CBC;
String padding = KeyProperties.ENCRYPTION_PADDING_PKCS7;
String alg = algorithm + "/" + blockMode + "/" + padding;
Cipher res = Cipher.getInstance(alg);
byte[] iv = fromHexString(ivString);
res.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
return res;
}
/**
* The Cipher created with [getInitializedCipherForEncryption] is used here
*/
public static String encryptData(String plainText, Cipher cipher) throws BadPaddingException, IllegalBlockSizeException {
return asHex(Objects.requireNonNull(Objects.requireNonNull(cipher.doFinal(plainText.getBytes(Charset.defaultCharset())))));
}
public static String getIV(Cipher cipher) {
return asHex(cipher.getIV());
}
/**
* The Cipher created with [getInitializedCipherForDecryption] is used here
*/
public static String decryptData(String ciphertext, Cipher cipher) throws BadPaddingException, IllegalBlockSizeException {
byte [] cipherData = fromHexString(ciphertext);
byte[] passBioByteArray = cipher.doFinal(cipherData);
return new String(passBioByteArray, Charset.defaultCharset());
}
}
I understand that I can store more than one value in the keystore with a particular keyalias, or not?
Thanks for all

AES between Android and Openbsd

I am a new to encryption using AES.I need to encrypt a string on the Android and send it to OpenBSD for decryption.
I am able to encrypt/decrypt on the Openbsd using OpenSSl and whith Android using this code, but the encrypted strings from the Android are not equal to the decrypted string in OpenBSD
Can anyone help me please.
...
public class StringCryptor
{
private static final String CIPHER_ALGORITHM = "AES";
private static final String RANDOM_GENERATOR_ALGORITHM = "SHA1PRNG";
private static final int RANDOM_KEY_SIZE = 128;
// Private key already generated with generatekey()
static String PKEY= "15577737BBD910E794A6B3C250678DAF";
// Convert PKEY to byte[]
static byte[] secretKey = toByte(PKEY);
// Encrypts string and encode in Base64
public static String encrypt( String password, String data ) throws Exception
{
byte[] clear = data.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, CIPHER_ALGORITHM );
Cipher cipher = Cipher.getInstance( CIPHER_ALGORITHM );
cipher.init( Cipher.ENCRYPT_MODE, secretKeySpec );
byte[] encrypted = cipher.doFinal( clear );
String encryptedString = Base64.encodeToString( encrypted, Base64.DEFAULT );
return encryptedString;
}
// Decrypts string encoded in Base64
public static String decrypt( String password, String encryptedData ) throws Exception
{
SecretKeySpec secretKeySpec = new SecretKeySpec( secretKey, CIPHER_ALGORITHM );
Cipher cipher = Cipher.getInstance( CIPHER_ALGORITHM );
cipher.init( Cipher.DECRYPT_MODE, secretKeySpec );
byte[] encrypted = Base64.decode( encryptedData, Base64.DEFAULT );
byte[] decrypted = cipher.doFinal( encrypted );
return new String( decrypted );
}
// Convert String To Hexa
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
// Convert hex To byte
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;
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
//public static byte[] generateKey( byte[] seed ) throws Exception
//{
//KeyGenerator keyGenerator = KeyGenerator.getInstance( CIPHER_ALGORITHM );
//SecureRandom secureRandom = SecureRandom.getInstance( RANDOM_GENERATOR_ALGORITHM );
//secureRandom.setSeed( seed );
//keyGenerator.init( RANDOM_KEY_SIZE, secureRandom );
//SecretKey secretKey = keyGenerator.generateKey();
//return secretKey.getEncoded();
//}
}
...
The encrypted string generated with android
Bonjour >>>>>>> NkrWPLgiY0rt34iaNzhjOg==
In OpenBSD,i'm crypting the string with the private key generated in android
#openssl version
openSSl 0.9.8k 25 Mar 2009
#echo "Bonjour">test.txt
#openssl enc -aes1278 -a -in text.txt -K 15577737BBD910E794A6B3C250678DAF -iv 0
4UwyKgMGJ41xPwTph2qHXQ==
I took the time to test your code and the problem is really simple. If you do echo "Bonjour" > test.txt a "linefeed" is automatically added to Bonjour.
So in Java you encrypt the string "Bonjour" but the text.txt file read by openssl contains the string "Bonjour\n". You can change that by adding the -n flag to echo. Now openssl should print the same as Java:
$ echo -n "Bonjour" > test.txt
$ openssl enc -aes128 -a -in test.txt -K 15577737BBD910E794A6B3C250678DAF -iv 0
NkrWPLgiY0rt34iaNzhjOg==
Obviously my statement that the IV is randomly generated by Java is wrong.

Android 4.2 broke my encrypt/decrypt code and the provided solutions don't work

First of all, I've already seen
Android 4.2 broke my AES encrypt/decrypt code
and
Encryption error on Android 4.2
and the provided solution:
SecureRandom sr = null;
if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
} else {
sr = SecureRandom.getInstance("SHA1PRNG");
}
doesn't work for me, because, when decoding data encrypted in Android<4.2 in Android 4.2, I get:
javax.crypto.BadPaddingException: pad block corrupted
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:709)
My code is quite simple, and was working until Android 4.2:
public static byte[] encrypt(byte[] data, String seed) throws Exception {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
secrand.setSeed(seed.getBytes());
keygen.init(128, secrand);
SecretKey seckey = keygen.generateKey();
byte[] rawKey = seckey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal(data);
}
public static byte[] decrypt(byte[] data, String seed) throws Exception {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
secrand.setSeed(seed.getBytes());
keygen.init(128, secrand);
SecretKey seckey = keygen.generateKey();
byte[] rawKey = seckey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
return cipher.doFinal(data);
}
My guess is that the default provider wasn't the only thing that changed in Android 4.2, otherwise my code would work with the proposed solution.
My code was based on some post I found here at StackOverflow a long time ago; I see that it differs from the mentioned posts as it just crypts and decrypts byte arrays, whereas the others solutions crypt and decrypt Strings (HEX Strings, I think).
Does it have to do with the seed? Does it have a min/max length, restriction of chars, etc?
Any idea / solution?
EDIT:
After a lot of tests, I see that there are 2 problems:
The provider changed in Android 4.2 (API 17) -> This one is easy to fix, just apply the solution I mentioned at top of the post
BouncyCastle changed from 1.34 to 1.45 in Android 2.2 (API 8)->Android2.3 (API 9), so the decryption problem I previously told is the same as described here: BouncyCastle AES error when upgrading to 1.45
So now the question is: is there any way to recover data crypted in BouncyCastle 1.34 in BouncyCastle 1.45+?
First a disclaimer:
DO NOT ever use SecureRandom to derive a key! This is broken and doesn't make sense!
The following block of code from the question tries to deterministically derive a key from a password, called the "seed" as the password is used to "seed" the random number generator.
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
secrand.setSeed(seed.getBytes());
keygen.init(128, secrand);
SecretKey seckey = keygen.generateKey();
However, the "SHA1PRNG" algorithm is not well defined and implementations of "SHA1PRNG" may return different or even fully random keys as a result.
If you're reading an AES key from disk, just store the actual key and don't go through this weird dance. You can get a SecretKey for AES usage from the bytes by doing:
SecretKey key = new SecretKeySpec(keyBytes, "AES");
If you're using a password to derive a key, follow Nelenkov's excellent tutorial with the caveat that a good rule of thumb is the salt size should be the same size as the key output.
The iterationCount (work factor) is of course subject to change and should be changed as CPU power progresses - generally it is recommended not to go lower than 40 to 100K as of 2018. Beware that PBKDF2 only adds a constant time delay to guessing passwords; it is not a replacement for really weak passwords.
It looks like this:
/* User types in their password: */
String password = "password";
/* Store these things on disk used to derive key later: */
int iterationCount = 1000;
int saltLength = 32; // bytes; should be the same size as the output (256 / 8 = 32)
int keyLength = 256; // 256-bits for AES-256, 128-bits for AES-128, etc
byte[] salt; // Should be of saltLength
/* When first creating the key, obtain a salt with this: */
SecureRandom random = new SecureRandom();
byte[] salt = new byte[saltLength];
random.nextBytes(salt);
/* Use this to derive the key from the password: */
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt,
iterationCount, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
SecretKey key = new SecretKeySpec(keyBytes, "AES");
That's it. Anything else you should not use.
private static final int ITERATION_COUNT = 1000;
private static final int KEY_LENGTH = 256;
private static final String PBKDF2_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final int PKCS5_SALT_LENGTH = 32;
private static final String DELIMITER = "]";
private static final SecureRandom random = new SecureRandom();
public static String encrypt(String plaintext, String password) {
byte[] salt = generateSalt();
SecretKey key = deriveKey(password, salt);
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
byte[] iv = generateIv(cipher.getBlockSize());
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
byte[] cipherText = cipher.doFinal(plaintext.getBytes("UTF-8"));
if(salt != null) {
return String.format("%s%s%s%s%s",
toBase64(salt),
DELIMITER,
toBase64(iv),
DELIMITER,
toBase64(cipherText));
}
return String.format("%s%s%s",
toBase64(iv),
DELIMITER,
toBase64(cipherText));
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static String decrypt(String ciphertext, String password) {
String[] fields = ciphertext.split(DELIMITER);
if(fields.length != 3) {
throw new IllegalArgumentException("Invalid encypted text format");
}
byte[] salt = fromBase64(fields[0]);
byte[] iv = fromBase64(fields[1]);
byte[] cipherBytes = fromBase64(fields[2]);
SecretKey key = deriveKey(password, salt);
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
byte[] plaintext = cipher.doFinal(cipherBytes);
return new String(plaintext, "UTF-8");
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private static byte[] generateSalt() {
byte[] b = new byte[PKCS5_SALT_LENGTH];
random.nextBytes(b);
return b;
}
private static byte[] generateIv(int length) {
byte[] b = new byte[length];
random.nextBytes(b);
return b;
}
private static SecretKey deriveKey(String password, byte[] salt) {
try {
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(PBKDF2_DERIVATION_ALGORITHM);
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
return new SecretKeySpec(keyBytes, "AES");
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
private static String toBase64(byte[] bytes) {
return Base64.encodeToString(bytes, Base64.NO_WRAP);
}
private static byte[] fromBase64(String base64) {
return Base64.decode(base64, Base64.NO_WRAP);
}
Source
The problem is that with the new provider, the following snippet of code
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
secrand.setSeed(seed.getBytes());
keygen.init(128, secrand);
SecretKey seckey = keygen.generateKey();
byte[] rawKey = seckey.getEncoded();
generates a different, genuinely random rawKey every time it's executed. So, you're trying to decrypt with a key different from the one used to encrypt data and you get the exception. You won't be able to recover your key or data when it has been generated this way, and only the seed has been saved.
What fixed it for me (as #Giorgio suggested) was just replacing this:
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
with this:
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG", "Crypto");
I am unable to give you answer to your asked question but I'd simply try to work this around >- if you face some problems with bouncycastle across devices/OS version, you should ditch built-in versions completely and instead add bouncycastle as jar to your project, change your import to point to that jar, rebuild and assuming it all works you'd be immune to android built-in version changes from now on.
Because all of this didn't help me to generate an encrypted password which was deterministic on all android devices (>=2.1), I searched for another AES implementation. I found one which works for me on all devices. I'm not a security specialist, I'm not sure if the technique isn't as secure as it could be. I'm only posting the code for people who have run in the same problem that I had face before.
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import android.util.Log;
public class EncodeDecodeAES {
private static final String TAG_DEBUG = "TAG";
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!)
private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!)
public EncodeDecodeAES() {
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (GeneralSecurityException e) {
Log.d(TAG_DEBUG, e.getMessage());
}
}
public byte[] encrypt(String text) throws Exception {
if (text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e) {
Log.d(TAG_DEBUG, e.getMessage());
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception {
if (code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e) {
Log.d(TAG_DEBUG, e.getMessage());
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] data) {
if (data == null) {
return null;
}
int len = data.length;
String str = "";
for (int i = 0; i < len; i++) {
if ((data[i] & 0xFF) < 16)
str = str + "0" + java.lang.Integer.toHexString(data[i] & 0xFF);
else
str = str + java.lang.Integer.toHexString(data[i] & 0xFF);
}
return str;
}
public static byte[] hexToBytes(String str) {
if (str == null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
}
return buffer;
}
}
private static String padString(String source) {
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++) {
source += paddingChar;
}
return source;
}
}
You can use it like:
EncodeDecodeAES aes = new EncodeDecodeAES ();
/* Encrypt */
String encrypted = EncodeDecodeAES.bytesToHex(aes.encrypt("Text to Encrypt"));
/* Decrypt */
String decrypted = new String(aes.decrypt(encrypted));
Source: HERE
It's does have to do with the seed indeed and it's also should use multiple of 8 (like 8, 16, 24 or 32), try complete the seed with A's and B's or 1's and 0s (has to be something like this ABAB..., because AAA.. or BBB.. will not work also.) up to reach a multiple of 8 number. There is an other thing if you are reading and encrypting only bytes, (not converting it to Char64 as I did), then you need an appropriate PKCS5 or PKCS7 Padding, however in your case (due only 128bits and it's has been created with older versions of Android) PKCS5 would be enough, though you also should put it in your SecreteKeySpec something like "AES/CBC/PKCS5Padding" or "AES/ECB/PKCS5Padding" rather than just "AES", because Android 4.2 it's using PKCS7Padding as default and if it's only bytes you really need the same algorithm that was the default before. Try get a device with an Android earlier than 4.2 check the Object tree on your "keygen.init(128, secrand);" if I'm not mistaken it's has the label cipher, than use it.
Give it a try.

incorrect decryption using AES/CBC/PKCS5Padding in Android

I wrote the following code in Android (v2.2 API 8), where a plain text is entered and the code encrypts it using a user password and a random salt and then decrypts it. After running the code I only get part of the plain text correct. For example the user enters "Msg 1.5 to encrypt" and the result from the decryption code is "Msg15toencrypg=="
Here is the code:
private EditText plain_msg;
private EditText pwd;
private TextView result;
byte[] iv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
plain_msg = (EditText)findViewById(R.id.msg2encypt);
pwd = (EditText)findViewById(R.id.password);
result = (TextView)findViewById(R.id.decrypttxt);
}
public void mybuttonHandler(View view){
String S_plain_msg = plain_msg.getText().toString();
String S_pwd = pwd.getText().toString();
setAES(S_plain_msg, S_pwd);
}
private byte[] generateSalt() throws NoSuchAlgorithmException{
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] ransalt = new byte[20];
random.nextBytes(ransalt);
return ransalt;
}
private void setAES(String msg, String pwd){
try {
//Generation of Key
byte[] salt = generateSalt();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec(pwd.toCharArray(),salt,1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
//Encryption process
byte[] btxt = Base64.decode(msg, 0);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(btxt);
String encryptedtext = Base64.encodeToString(ciphertext, 0);
//Decryption process
byte[] bencryptxt = Base64.decode(encryptedtext, 0);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
ciphertext = cipher.doFinal(bencryptxt);
String cipherS = Base64.encodeToString(ciphertext, 0);
result.setText(cipherS);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
}
Can someone knows why is this happening or any advice to be able to get the correct decrypted message?
If you take out the encrypt-decrypt, which should be an identity transformation, what remains is:
Base64.encodeToString(Base64.decode(msg))
"Msg 1.5 to encrypt" isn't a Base64-encoded string, there's no need to try to decode it. If you do, as you do, non-Base64 characters get stripped and you get some bytes which, when encoded back, look like the result you get.

Exception - Illegal Block size during decryption(Android)

I am writing an application which encrypts and decrypts the user notes based on the user set password. i used the following algorithms for encryption/decryption
1. PBEWithSHA256And256BitAES-CBC-BC
2. PBEWithMD5And128BitAES-CBC-OpenSSL
e_Cipher = Cipher.getInstance(PBEWithSHA256And256BitAES-CBC-BC);
d_Cipher = Cipher.getInstance(PBEWithSHA256And256BitAES-CBC-BC);
e_Cipher.init()
d_Cipher.init()
encryption is working well, but when trying to decrypt it gives
Exception - Illegal Block size
after encryption i am converting the cipherText to HEX and storing it in a sqlite database. i am retrieving correct values from the sqlite database during decyption but when calling d_Cipher.dofinal() it throws the Exception.
I thought i missed to specify the padding and tried to check what are the other available cipher algorithms but i was unable to found.
so request you to please give the some knowledge on what are the cipher algorithms and padding that are supported by Android? if the algorithm which i used can be used for padding, how should i specify the padding mechanism?
I am pretty new to Encryption so tried a couple of algorithms which are available in BouncyCastle.java but unsuccessful.
As requested here is the code
public class CryptoHelper {
private static final String TAG = "CryptoHelper";
//private static final String PBEWithSHA256And256BitAES = "PBEWithSHA256And256BitAES-CBC-BC";
//private static final String PBEWithSHA256And256BitAES = "PBEWithMD5And128BitAES-CBC-OpenSSL";
private static final String PBEWithSHA256And256BitAES = "PBEWithMD5And128BitAES-CBC-OpenSSLPBEWITHSHA1AND3-KEYTRIPLEDES-CB";
private static final String randomAlgorithm = "SHA1PRNG";
public static final int SALT_LENGTH = 8;
public static final int SALT_GEN_ITER_COUNT = 20;
private final static String HEX = "0123456789ABCDEF";
private Cipher e_Cipher;
private Cipher d_Cipher;
private SecretKey secretKey;
private byte salt[];
public CryptoHelper(String password) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
char[] cPassword = password.toCharArray();
PBEKeySpec pbeKeySpec = new PBEKeySpec(cPassword);
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, SALT_GEN_ITER_COUNT);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance(PBEWithSHA256And256BitAES);
secretKey = keyFac.generateSecret(pbeKeySpec);
SecureRandom saltGen = SecureRandom.getInstance(randomAlgorithm);
this.salt = new byte[SALT_LENGTH];
saltGen.nextBytes(this.salt);
e_Cipher = Cipher.getInstance(PBEWithSHA256And256BitAES);
d_Cipher = Cipher.getInstance(PBEWithSHA256And256BitAES);
e_Cipher.init(Cipher.ENCRYPT_MODE, secretKey, pbeParamSpec);
d_Cipher.init(Cipher.DECRYPT_MODE, secretKey, pbeParamSpec);
}
public String encrypt(String cleartext) throws IllegalBlockSizeException, BadPaddingException {
byte[] encrypted = e_Cipher.doFinal(cleartext.getBytes());
return convertByteArrayToHex(encrypted);
}
public String decrypt(String cipherString) throws IllegalBlockSizeException {
byte[] plainText = decrypt(convertStringtobyte(cipherString));
return(new String(plainText));
}
public byte[] decrypt(byte[] ciphertext) throws IllegalBlockSizeException {
byte[] retVal = {(byte)0x00};
try {
retVal = d_Cipher.doFinal(ciphertext);
} catch (BadPaddingException e) {
Log.e(TAG, e.toString());
}
return retVal;
}
public String convertByteArrayToHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
private static byte[] convertStringtobyte(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 byte[] getSalt() {
return salt;
}
public SecretKey getSecretKey() {
return secretKey;
}
public static SecretKey createSecretKey(char[] password) throws NoSuchAlgorithmException, InvalidKeySpecException {
PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance(PBEWithSHA256And256BitAES);
return keyFac.generateSecret(pbeKeySpec);
}
}
I will call mCryptoHelper.decrypt(String str) then this results in Illegal block size exception
My Env: Android 1.6 on Eclipse
#Vamsi is correct, it looks like a new Salt is being generated. This should be generated once, and stored as a known to the program. If the salt changes, then the encrypt/decrypt data checks aren't going to match.
In the code, each time i am generating the "salt",
SecureRandom saltGen = SecureRandom.getInstance(randomAlgorithm);
this.salt = new byte[SALT_LENGTH];
saltGen.nextBytes(this.salt);
hence there is a difference between the encryption and decryption cipher. so it is giving the error Bad Pad block or Padding block corrupted.
If i declare the Salt to some known value, it is working fine.

Categories

Resources