How to keep the Seed Value a 'secret'? - java

If I am using the following methods to encrypt and decrypt a String...
Shouldn't the seed value be a 'secret' and not 'hard-codded'?
And if so... how would I achieve that goal?
String encryption(String userText){
String seedValue = "SecretKey";
String userTextEncrypted="";
try {
userTextEncrypted = AESHelper.encrypt(seedValue, userText);
} catch (Exception e) {
e.printStackTrace();
}
return userTextEncrypted;
}
String decryption(String encryptedText){
String seedValue = "SecretKey";
String decryptedText="";
try {
decryptedText = AESHelper.decrypt(seedValue, encryptedText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
Below is the AESHelper class...
public class AESHelper {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG","Crypto");
sr.setSeed(seed);
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[] 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 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));
}
}

Related

Cipher Algorithm AES CBC Insecure Android

I am currently using Cipher cipher = Cipher.getInstance ("AES / CBC / PKCS5Padding") on my Android app.
Those responsible for the security of the app tell me this: "It should also be noted that AES encryption is secure when it is not AES CBC.", so they want me to modify the algorithm.
I tried AES/GCM/NoPadding and AES/CTR/PKCS5Padding, if I uninstall the old version and install it again, the app works, but if I install it on top of a version with CBC I get the following error: javax.crypto.BadPaddingException: pad block corrupted
How can I solve this? I am afraid that if I update the app that is in the store, this error will happen to end users.
Notes:
public static String encrypt (String plaintext, String pwd) {
try {
byte [] salt = generateSalt ();
SecretKey key = deriveKey (salt, pwd);
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 (byte [] cipherBytes, SecretKey key, byte [] iv) {
try {
Cipher cipher = Cipher.getInstance (CIPHER_ALGORITHM);
IvParameterSpec ivParams = new IvParameterSpec (iv);
cipher.init (Cipher.DECRYPT_MODE, key, ivParams);
byte [] plaintext = cipher.doFinal (cipherBytes);
String plainrStr = new String (plaintext, "UTF-8");
return plainrStr;
} catch (GeneralSecurityException e) {
throw new RuntimeException (e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException (e);
}
}
etc...
Update!
I decided to make the code cleaner and here it is for you to understand. My goal was to replace "AES / CBC / PKCS7Padding" with "AES / GCM / NoPadding", as they consider AES with CBC unsafe :(
Questions that arose for this GCM implementation: do I have to use GCMParameterSpec on the cipher? Do I need to import the BouncyCastle provider?
public static final String PBKDF2_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
//private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
private static String DELIMITER = "]";
private static final int PKCS5_SALT_LENGTH = 8;
private static SecureRandom random = new SecureRandom();
private static final int ITERATION_COUNT = 1000;
private static final int KEY_LENGTH = 256;
public static String encrypt(String plaintext, String pwd) {
byte[] salt = generateSalt();
SecretKey key = deriveKey(pwd, 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"));
return String.format("%s%s%s%s%s", toBase64(salt), DELIMITER, toBase64(iv), DELIMITER, toBase64(cipherText));
} catch (GeneralSecurityException | UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static String decrypt(String ciphertext, String pwd) {
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(pwd, 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 pwd, byte[] salt) {
try {
KeySpec keySpec = new PBEKeySpec(pwd.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);
}
public static byte[] fromBase64(String base64) {
return Base64.decode(base64, Base64.NO_WRAP);
}

Use Java Cipher equivalent in Flutter

a i need help to decrypt values generated in Android Java App on Flutter.
I need a class who this but in Dart/Flutter:
public class TrippleDes {
// public static String ALGO = "DESede/CBC/PKCS7Padding";
public static String ALGO = "DESede/ECB/PKCS7Padding";
public static String _encrypt(String message, String secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(ALGO);
cipher.init(Cipher.ENCRYPT_MODE, getSecreteKey(secretKey));
byte[] plainTextBytes = message.getBytes("UTF-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte[] base64Bytes = Base64.encode(buf, Base64.DEFAULT);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
public static String _decrypt(String encryptedText, String secretKey) throws Exception {
byte[] message = Base64.decode(encryptedText.getBytes(), Base64.DEFAULT);
Cipher decipher = Cipher.getInstance(ALGO);
decipher.init(Cipher.DECRYPT_MODE, getSecreteKey(secretKey));
byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
public static SecretKey getSecreteKey(String secretKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
return key;
}
}

Decryption using AES algorithm

public void handleResult(Result result) {
final String scanResult = result.getText();
Log.e("QRCode:", scanResult);
String normalTextDec = null;
try {
normalTextDec = AESHelper.decrypt(seedValue, scanResult);
Log.e("Decrypt:",normalTextDec);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
In the above code "scanResult" is the encrypted String. I wanted to decrypt it. When I am printing scanResult on the console it is giving the correct encrypted String but decryption is not working. Can anyone solve this? And I am using AESHelper class for this.
AESHelper class:
public class AESHelper {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
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[] 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 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));
}
}

javax.crypto.BadPaddingException: Given final block not properly padded - when decryptText

When Dycrypt plain text then throw BadPaddingException
javax.crypto.BadPaddingException: Given final block not properly padded
com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
private static final String ENCRYPTION_KEY = "harshitorld!##$%";
private static byte[] randomBytesToDecrypt;
private static final String ALGORITHM = "Rijndael";
private static final String UNICODE_FORMAT = "UTF8";
private static String encrypt(String value) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encValue = c.doFinal(value.getBytes(UNICODE_FORMAT));
String encryptedValue = new BASE64Encoder().encode(encValue);
return encryptedValue;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String encryptedValue) {
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
byte[] decValue = c.doFinal(decordedValue);//////////LINE 50
String decryptedValue = new String(decValue,UNICODE_FORMAT);
return decryptedValue;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
private static Key generateKey() throws Exception {
byte[] keyAsBytes;
keyAsBytes = ENCRYPTION_KEY.getBytes(UNICODE_FORMAT);
Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
return key;
}
public static String encryptText(String normalText) {
return encrypt(normalText);
}
public static String decryptText(String encryptedText) {
return decrypt(encryptedText);
}

Decryption error on Android 4.4

I have algorithm of encryption\ decryption files:
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = new SecureRandom();
sr.setSeed(seed);
kgen.init(sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
It works great, but on Android 4.4 (api 19) I have strangely exception
javax.crypto.BadPaddingException: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
What is it?
Here what I got: http://www.logikdev.com/2010/11/01/encrypt-with-php-decrypt-with-java/
public class AES2 {
private static final String TRANSFORMATION = "AES/CFB8/NoPadding";
private static final String ALGO_MD5 = "MD5";
private static final String ALGO_AES = "AES";
/**
* See http://www.logikdev.com/2012/12/12/md5-generates-31-bytes-instead-of-32/ form more detail.
*
* #param input
* #return
* #throws NoSuchAlgorithmException
*/
private static String md5(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(ALGO_MD5);
byte[] messageDigest = md.digest(input.getBytes());
BigInteger number = new BigInteger(1, messageDigest);
return String.format("%032x", number);
}
public static String decrypt(String encryptedData, String initialVectorString, String secretKey) {
String decryptedData = null;
try {
String md5Key = md5(secretKey);
SecretKeySpec skeySpec = new SecretKeySpec(md5Key.getBytes(), ALGO_AES);
IvParameterSpec initialVector = new IvParameterSpec(initialVectorString.getBytes());
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, initialVector);
byte[] encryptedByteArray = Base64.decode(encryptedData.getBytes(), Base64.DEFAULT);
byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray);
decryptedData = new String(decryptedByteArray);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptedData;
}
}
So you have to create a initialVectorString (example: "fedcba9876543210"). Hope this help.

Categories

Resources