Java read a encrypted string and decode it - java

I am trying to encrypt a string with a user defined password and then decode it with the string again.
My code:
SecurityManager.java
package de.example.org;
import javax.crypto.*;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
public class SecurityManager {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
private static final SecureRandom secureRandom = new SecureRandom();
private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder();
private static final SecretKeyFactory factory;
static {
try {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static PBEKeySpec generatePBEKeySpec(String password) {
return new PBEKeySpec(password.toCharArray(), generateRandomString(16).getBytes(), 65536, 128);
}
public static String generateRandomString(int length) {
byte[] randomBytes = new byte[length];
secureRandom.nextBytes(randomBytes);
return base64Encoder.encodeToString(randomBytes);
}
public static String generateEncryptedKey(String password) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
SecretKey secretKey = factory.generateSecret(generatePBEKeySpec(password));
byte[] encodedKey = secretKey.getEncoded();
// Convert the secretKey to a SecretKeySpec
Key secretKeySpec = new SecretKeySpec(encodedKey, ALGORITHM);
// Encrypt the original string
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
String random = generateRandomString(128);
System.out.println(random);
byte[] encryptedBytes = cipher.doFinal(random.getBytes());
return new String(encryptedBytes);
}
public static String decryptKey(String encryptedKey, String password) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
SecretKey secretKey = factory.generateSecret(generatePBEKeySpec(password));
byte[] encodedKey = secretKey.getEncoded();
// Convert the secretKey to a SecretKeySpec
Key secretKeySpec = new SecretKeySpec(encodedKey, ALGORITHM);
// Decrypt the encrypted string
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(encryptedKey.getBytes());
return new String(decryptedBytes);
}
}
Executing the function in main:
String encrypted = SecurityManager.generateEncryptedKey("123");
String decrypted = SecurityManager.decryptKey(encrypted, "123");
System.out.println(decrypted);
Error:
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at java.base/com.sun.crypto.provider.CipherCore.prepareInputBuffer(CipherCore.java:887)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:729)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:434)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2206)
at de.example.org.SecurityManager.decryptKey(SecurityManager.java:66)
at de.example.org.main.Main.main(Main.java:11)
I have been sitting on this for hours now, and with bytes I can encrypt it. But since I want to store the encrypted string, so it's still available after a restart, storing the bytes in a file would be less secure AFAIK.

My code wasn't actually able to decrypt. This code does the job:
package de.alexx1.birthdaynotf.helper;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
public class SecurityManager {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String CHARSET = "UTF-8";
private static final int KEY_SIZE = 128;
private static final int ITERATIONS = 65536;
private static final int SALT_LENGTH = 16;
private static final SecureRandom secureRandom = new SecureRandom();
private static final Base64.Encoder base64Encoder = Base64.getEncoder();
public static String generateRandomString(int length) {
byte[] randomBytes = new byte[length];
secureRandom.nextBytes(randomBytes);
return base64Encoder.encodeToString(randomBytes);
}
public static String encrypt(String plainText, String password) throws Exception {
byte[] salt = generateSalt();
SecretKey secretKey = generateSecretKey(password, salt);
byte[] keyBytes = secretKey.getEncoded();
Key key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(CHARSET));
byte[] iv = cipher.getIV();
byte[] encryptedText = new byte[salt.length + iv.length + encryptedBytes.length];
System.arraycopy(salt, 0, encryptedText, 0, salt.length);
System.arraycopy(iv, 0, encryptedText, salt.length, iv.length);
System.arraycopy(encryptedBytes, 0, encryptedText, salt.length + iv.length, encryptedBytes.length);
return Base64.getEncoder().encodeToString(encryptedText);
}
public static String decrypt(String encryptedText, String password) throws Exception {
byte[] encryptedTextBytes = Base64.getDecoder().decode(encryptedText.getBytes(CHARSET));
byte[] salt = Arrays.copyOfRange(encryptedTextBytes, 0, SALT_LENGTH);
byte[] iv = Arrays.copyOfRange(encryptedTextBytes, SALT_LENGTH, SALT_LENGTH + 16);
byte[] cipherText = Arrays.copyOfRange(encryptedTextBytes, SALT_LENGTH + 16, encryptedTextBytes.length);
SecretKey secretKey = generateSecretKey(password, salt);
Key key = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] decryptedBytes = cipher.doFinal(cipherText);
return new String(decryptedBytes, CHARSET);
}
private static SecretKey generateSecretKey(String password, byte[] salt) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEY_SIZE);
return factory.generateSecret(spec);
}
private static byte[] generateSalt() {
byte[] salt = new byte[SALT_LENGTH];
secureRandom.nextBytes(salt);
return salt;
}
}

Related

Error when decrypting first bytes Java AES/CBC/PKCS5PADDING

I was implementing encryption decryption of a file using the AES/CBC/PKCS5PADDING algorithm. And I noticed some peculiarity. With the correct order of initialization of the IV, everything is decrypted correctly. But if the order is wrong (see commented out lines), the beginning of the line is decoded incorrectly.
But if the decryption happens with wrong IV in CBC mode then nothing should be decrypted. After all, that's how AES/CBC works.
My question is - why is the string still decrypted with the wrong IV ?
Output
org.junit.ComparisonFailure:
Expected :Test string Test string Test string Test string Test string Test string
Actual :�Eݠ�/ՙ�, 9B�� string Test string Test string Test string Test string
Code
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
public class CryptographyService {
private static final String SECRET_KEY_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA256";
private static final String CIPHER_ALGORITHM_MODE_PADDING = "AES/CBC/PKCS5PADDING";
private static final String CIPHER_ALGORITHM = "AES";
private static final int SALT_LEN = 32;
private static byte[] createSalt() {
byte[] salt = new byte[SALT_LEN];
SecureRandom random = new SecureRandom();
random.nextBytes(salt);
return salt;
}
private static SecretKey secretKeyCreate(String userPassword, byte[] salt) throws NoSuchAlgorithmException,
InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance(SECRET_KEY_DERIVATION_ALGORITHM);
KeySpec spec = new PBEKeySpec(userPassword.toCharArray(), salt, 25000, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), CIPHER_ALGORITHM);
return secret;
}
public static void encrypt(String userPassword, String fileEncryptName, String jsonPasswordsData)
throws NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IOException {
byte[] salt = createSalt();
SecretKey secretKey = secretKeyCreate(userPassword, salt);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_MODE_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
//cipher.init(Cipher.ENCRYPT_MODE, secretKey); // incorrect decrypt
try (FileOutputStream fileOutputStream = new FileOutputStream(fileEncryptName);
CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher)) {
fileOutputStream.write(iv);
fileOutputStream.write(salt);
fileOutputStream.flush();
cipherOutputStream.write(jsonPasswordsData.getBytes(StandardCharsets.UTF_8));
}
}
public static String decrypt(String userPassword, String fileDecryptName) throws NoSuchPaddingException,
NoSuchAlgorithmException, IOException, InvalidParameterSpecException, InvalidKeySpecException,
InvalidAlgorithmParameterException, InvalidKeyException {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_MODE_PADDING);
AlgorithmParameters params = cipher.getParameters();
int ivLength = params.getParameterSpec(IvParameterSpec.class).getIV().length;
byte[] iv = new byte[ivLength];
byte[] salt = new byte[SALT_LEN];
byte[] plainText;
try (FileInputStream fileInputStream = new FileInputStream(fileDecryptName);
CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher)) {
fileInputStream.read(iv);
fileInputStream.read(salt);
SecretKey secretKey = secretKeyCreate(userPassword, salt);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
plainText = cipherInputStream.readAllBytes();
}
return new String(plainText, StandardCharsets.UTF_8);
}
}

PBEWithSHA256AndAES_256 decryption works on Windows not on Unix/Linux

I have the following code which works on Windows and Linux/Unix but will not decrypt an encrypted text that has been encrypted on Linux/Unix or vice versa.
I am aware that this will also generate the same encrypted text everytime, but I've removed some of the code to get to the very basic.
I am sure it's not related to Charset encoding, as the encoded String is the same on both OS, even the SecretKey is the same on both.
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class Encryptor {
private static final String password = "passwordKey";
private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final byte [] salt = "test salt as string".getBytes(UTF_8);
public static String encrypt(String text) throws UnsupportedEncodingException {
IvParameterSpec ivSpec = new IvParameterSpec(password.getBytes(UTF_8));
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 10000, ivSpec);
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 10000);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithSHA256AndAES_256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("PBEWithSHA256AndAES_256");
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
byte [] encrypted = cipher.doFinal(text.getBytes(UTF_8));
return Base64.encodeBase64String(encrypted);
}
public static String decrypt(String encryptedText) throws UnsupportedEncodingException {
IvParameterSpec ivSpec = new IvParameterSpec(password.getBytes(UTF_8));
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 10000, ivSpec);
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 10000);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithSHA256AndAES_256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("PBEWithSHA256AndAES_256");
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
byte [] decoded = Base64.decodeBase64String(encryptedText);
byte [] decrypted = cipher.doFinal(decoded);
return new String(decrypted, UTF_8);
}
public static void main(String args []) throws UnsupportedEncodingException {
String encryptedFromWindows = "eFRvTevgk/oslll+234r5tdsss==";
System.out.println(decrypt(encryptedFromWindows));
}
}
Exception:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
The problem was a bug in the JDK version of _64. Upgraded to _121 and it worked. IT wasn't a known oracle bug but they had mentioned in another similar bug of issues with encryption in that release.

Decrypting Rijndael in Android

I basically need to decrypt a password I retrieve from a server encrypted with Rijndael, I have never worked with encrypting/decrypting before and I am completely lost. I found somewhere in this web that Java has some methods implemented without need of external libraries to do so but I didn't get it. The only thing I need is the decrypt since I won't be writing back into the server anyways.
Any idea on how to do it or where I could find documentation about it?
I don't know if this code, taken from an answer here is what I am looking for, I don't understand much of it, as I said, I've never worked with this kind of stuff before:
byte[] sessionKey = null; //Where you get this from is beyond the scope of this post
byte[] iv = null ; //Ditto
byte[] plaintext = null; //Whatever you want to encrypt/decrypt
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//You can use ENCRYPT_MODE or DECRYPT_MODE
cipher.calling init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
byte[] ciphertext = cipher.doFinal(plaintext);
Thanks in advance.
Here is a Simple Crypto utility class that might be of help to you. Its based on the code written by ferenc.hechler posted at the following url :
http://www.androidsnippets.com/encryptdecrypt-strings
I have made some changes to it to fit my needs.
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class SimpleCrypto {
private static final int KEY_SIZE = 128;
public static String encrypt(String seed, String cleartext) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
final byte[] rawKey = getRawKey(seed.getBytes());
final byte[] result = encrypt(rawKey, cleartext.getBytes());
return bin2hex(result);
}
public static String decrypt(String seed, String encrypted) throws NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException {
final byte[] rawKey = getRawKey(seed.getBytes());
final byte[] enc = toByte(encrypted);
final byte[] result = decrypt(rawKey, enc);
return new String(result);
}
public static String decrypt(String seed, byte[] encrypted) throws NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException {
final byte[] rawKey = getRawKey(seed.getBytes());
final byte[] result = decrypt(rawKey, encrypted);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws NoSuchAlgorithmException {
final KeyGenerator kgen = KeyGenerator.getInstance("AES");
final SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(KEY_SIZE, sr); // 192 and 256 bits may not be available
final SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
public static byte[] encrypt(byte[] raw, byte[] clear) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
final SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
final byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
public static byte[] decrypt(byte[] raw, byte[] encrypted) throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
final SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
final byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return bin2hex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
final int len = hexString.length() / 2;
final 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 byte[] getHash(String str) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
digest.reset();
return digest.digest(str.getBytes());
}
static String bin2hex(byte[] data) {
return String.format("%0" + (data.length * 2) + "X", new BigInteger(1, data));
}
}
Here is how you would use it to decrypt something :
final String ssid = "MY_WIFI_SSID";
final String encWifiKey = "myEncryptedWifiKeyString";
String wifiKey = "";
try {
wifiKey = new String(SimpleCrypto.decrypt(SimpleCrypto.getHash(ssid), Base64.decode(encWifiKey, Base64.DEFAULT)));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}

Converted SecretKey into bytes, how to convert it back to a SecretKey?

I convert the secretkey into bytes with following code
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
byte[] bkey=key.getEncoded();
Now how do I get the key from bkey? I tried:
SecretKeySpec secretkey = new SecretKeySpec(bkey,"DES");
SecretKeyFactory sfkey = SecretKeyFactory.getInstance("DES");
SecretKey skey = sfkey.generateSecret(secretkey);
I get the following error:
Error during Exception java.security.spec.InvalidKeySpecException: Inappropriate key specification
This should work
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
byte[] data = key.getEncoded();
SecretKey key2 = new SecretKeySpec(data, 0, data.length, "DES");
Try some of this code...
import javax.crypto.Cipher;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.InvalidKeyException;
public class DESede {
private static String algorithm = "DESede";
private static Key key = null;
private static SecretKey secretKey = null;
private static Cipher cipher = null;
private static DESede obj = new DESede();
private DESede() {
try {
key = KeyGenerator.getInstance(algorithm).generateKey();
KeyGenerator.getInstance(algorithm).getProvider();
byte[] keyBytes = key.getEncoded();
String keyFormat = key.getFormat();
String keyAlgorithm = key.getAlgorithm();
String keyString = new String(keyBytes);
System.out.println("Key Format::" + keyFormat);
System.out.println("Key Algorithm::" + keyAlgorithm);
System.out.println("Key String::" + keyString);
keyString.getBytes();
secretKey = new SecretKeySpec(keyBytes, 0, keyBytes.length, "DESede");
byte[] secretKeyBytes = key.getEncoded();
String secretKeyFormat = key.getFormat();
String secretKeyAlgorithm = key.getAlgorithm();
String secretKeyString = new String(secretKeyBytes);
System.out.println("Secret Key Format::" + secretKeyFormat);
System.out.println("Secret Key Algorithm::" + secretKeyAlgorithm);
System.out.println("Secret Key String::" + secretKeyString);
String keyNewString = "bXŒ*êÂÕê›æOÄ’Îý‘ãô|8¶Ë1­";
byte[] keyNewBytes = keyString.getBytes();
secretKey = new SecretKeySpec(keyBytes, 0, keyBytes.length, "DESede");
cipher = Cipher.getInstance(algorithm);
} catch (Exception e) {
}
}
public static DESede getInstance() {
return obj;
}
public static byte[] encrypt(String input) throws InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
System.out.println("Inside encrypt()");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] inputBytes = input.getBytes();
System.out.println("Exit encrypt()");
return cipher.doFinal(inputBytes);
}
public static String decrypt(byte[] encryptionBytes)
throws InvalidKeyException, BadPaddingException,
IllegalBlockSizeException {
System.out.println("Inside decrypt()");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] recoveredBytes = cipher.doFinal(encryptionBytes);
String recovered = new String(recoveredBytes);
System.out.println("Exiting decrypt()");
return recovered;
}
public static void main(String args[]) throws InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
byte[] encryptedValue = DESede.encrypt("plz try encrypt and decrypt me");
System.out.println("encryptedValue::" + encryptedValue);
String decryptedValue = DESede.decrypt(encryptedValue);
System.out.println("decryptedValue::" + decryptedValue);
}
}

Is this a secure encryption method

I'm writing an application for Android that uses symmetric key encryption to protect sensitive data. As far as I can tell, Android only directly supports "PBEWithMD5AndDES". How secure is this algorithm? Also, I've included my code below (non-andriod). Is my code correctly encrypting the data?
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class CipherTest
{
private static class EncryptInfo
{
private final byte[] encryptedData;
private final byte[] initVector;
private final byte[] salt;
public EncryptInfo(byte[] encryptedData, byte[] initVector, byte[] salt)
{
this.encryptedData = encryptedData.clone();
this.initVector = initVector.clone();
this.salt = salt.clone();
}
public byte[] getEncryptedData()
{
return encryptedData;
}
public byte[] getInitVector()
{
return initVector;
}
public byte[] getSalt()
{
return salt;
}
}
private static final String keyGenAlgorithm = "PBEWithMD5AndDES";
private static final String keyAlgorithm = "DES";
private static final String cipherTransform = "PBEWithMD5AndDES/CBC/PKCS5Padding";
private static EncryptInfo encrypt(char[] password, byte[] data)
throws NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchPaddingException, InvalidKeyException,
InvalidParameterSpecException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException
{
byte[] salt = new byte[16];
new SecureRandom().nextBytes(salt);
PBEKeySpec keySpec = new PBEKeySpec(password, salt, 1024);
SecretKeyFactory secretKeyFactory = SecretKeyFactory
.getInstance(keyGenAlgorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
keySpec.clearPassword();
byte[] key = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, keyAlgorithm);
Cipher cipher = Cipher.getInstance(cipherTransform);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] initVector = cipher.getParameters().getParameterSpec(
IvParameterSpec.class).getIV();
return new EncryptInfo(cipher.doFinal(data), initVector, salt);
}
public static byte[] decrypt(byte[] data, char[] password, byte[] salt,
byte[] initVector) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException
{
PBEKeySpec keySpec = new PBEKeySpec(password, salt, 1024);
SecretKeyFactory secretKeyFactory = SecretKeyFactory
.getInstance(keyGenAlgorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
keySpec.clearPassword();
byte[] key = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, keyAlgorithm);
Cipher cipher = Cipher.getInstance(cipherTransform);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(
initVector));
return cipher.doFinal(data);
}
public static void main(String[] args) throws Exception
{
char[] password = "password".toCharArray();
EncryptInfo info = encrypt(password, "Message".getBytes());
byte[] decyptedText = decrypt(info.getEncryptedData(), password, info
.getSalt(), info.getInitVector());
System.out.println(new String(decyptedText));
}
}
Both MD5 and DES are weak. If your data being encrypted is really valuable, you should look for some external crypto library for Android that offers AES and SHA256/SHA512 algorithms.
If you want to encrypt data using a symmetric key encryption, I recommend:
1) Use AES, because it is certified by the NSA for data classified as secret.
2) Use a well reviewed implementation so you don't have to research the proper way to configure the code. For example, AESCrypt.
You can find AESCrypt here: http://www.aescrypt.com/java_aes_crypt.html
I've seen AESCrypt used in several financial institutions. AESCrypt for java is a single class that calls JCE methods. Android, JCE is implemented by bouncycastle. I have seen bouncycastle used in several major financial institutions.

Categories

Resources