Converting a String to byte[] for decryption - java

im facing a problem in my code.
I want to encrypt the Password from the user and save it to an SQL Database.
The Code im Using to Encrypt the Password with AES:
String key = "1234567890123456"; // 128 bit key
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(Passwort.getBytes());
String verschlüsselt = new String(encrypted);
Now im saving the String "verschlüsselt" to my Database.
In my LoginGUI im getting the String with the Password from the database:
String psswd = res.getString("Passwort"); //Getting the Password from Database and saving it into String
System.out.println(psswd);
The PrintOut is: "!?¿[ŸÊm,r~¤u" which is the correct encrypted password.
Now i'm trying to decrypt the password with following code:
String key = "1234567890123456"; // 128 bit key
cipher.init(Cipher.DECRYPT_MODE, aesKey);
EPasswort = new String(cipher.doFinal(bpsswd)); //Im facing the problem here
I Know that i can't decrypt the String and that I have to convert the String into an byte[].
I've done that in several ways:
byte[] password = psswd.getBytes();
System.out.println(password);
password = psswd.getBytes("UTF-8");
System.out.println(password);
EPasswort = new String(cipher.doFinal(password));
But the Output is always something the decrypter can't work with:
[B#ab33b4
[B#189090b
How do i convert my String with the Password (!?¿[ŸÊm,r~¤u) into an byte[] so my decrypter can work with it?
Thanks for any help.

You should encrypt the String and than save it as a String, in this example I'm using a Base64 encoder and a different cypher but the logic behind is the same. You should save bytes or String instead of using the reference to your bytes, here an example:
#Test
public void testCrypt () {
final String ENCRYPT_ALGO = "AES/GCM/NoPadding";
final int TAG_LENGTH_BIT = 128;
final int IV_LENGTH_BYTE = 12;
final int SALT_LENGTH_BYTE = 16;
final String password = "password";
final byte[] salt = getRandomNonce(SALT_LENGTH_BYTE);
final byte[] iv = getRandomNonce(IV_LENGTH_BYTE);
final SecretKey aesKeyFromPassword = getAESKeyFromPassword(password.toCharArray(), salt);
String msg = "Test";
String out = "";
try {
out = encrypt(ENCRYPT_ALGO, TAG_LENGTH_BIT, iv, aesKeyFromPassword, msg);
} catch (Exception e) {
e.printStackTrace();
}
byte[] plainText = new byte[0];
try {
plainText = decrypt(ENCRYPT_ALGO, TAG_LENGTH_BIT, iv, aesKeyFromPassword, out);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Decrypted " + out + " in: " + new String(plainText, StandardCharsets.ISO_8859_1));
}
following the encrypt method:
private String encrypt(final String ENCRYPT_ALGO, final int TAG_LENGTH_BIT, final byte[] iv,
final SecretKey aesKeyFromPassword, String msg) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
final byte[] pText = msg.getBytes(StandardCharsets.ISO_8859_1);
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
final byte[] cipherText = cipher.doFinal(pText);
String out = Base64.getEncoder().encodeToString(cipherText);
System.out.println("Encrypted " + msg + " as: " + out);
return out;
}
private static SecretKey getAESKeyFromPassword(final char[] password, final byte[] salt) {
final int KEY_LENGTH = 128;
final int ITERATION_COUNT = 65536;
try {
final SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
final KeySpec spec = new PBEKeySpec(password, salt, ITERATION_COUNT, KEY_LENGTH);
return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
} catch (final Exception e) {
LOGGER.error(e);
throw new RedException(e);
}
}
private static byte[] getRandomNonce(final int numBytes) {
final byte[] nonce = new byte[numBytes];
new SecureRandom().nextBytes(nonce);
return nonce;
}
Once you save the msgCrypted in db you should retrieve it and process it to decrypt like this:
private byte[] decrypt(final String ENCRYPT_ALGO, final int TAG_LENGTH_BIT, final byte[] iv,
final SecretKey aesKeyFromPassword, String out) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
Cipher dCipher = Cipher.getInstance(ENCRYPT_ALGO);
dCipher.init(Cipher.DECRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
final byte[] plainText = dCipher.doFinal(Base64.getDecoder().decode(out));
return plainText;
}
In the console you should have something like this:

You are printing the reference to the byte array, not the elements.
Run this for demonstration:
public static void main (String [] args) {
String s = "12345678";
byte [] b = s.getBytes ();
System.out.println (b);
for (int i = 0; i < 8; i++) {
System.out.println (b [i]);
}
}
Output:
[B#7a81197d
49
50
51
52
53
54
55
56

Related

Java AES GCM AEAD Tag mismatch

Im trying to write a program to encrypt any type of file. I had my encryption classes already done, when I noticed (at first it worked) that I am getting an AEADBadTagException whenever I try to decrypt any of my files.
Here is my encryption/decryption class:
class Encryptor {
private static final String algorithm = "AES/GCM/NoPadding";
private final int tagLengthBit = 128; // must be one of {128, 120, 112, 104, 96}
private final int ivLengthByte = 12;
private final int saltLengthByte = 64;
protected final Charset UTF_8 = StandardCharsets.UTF_8;
private CryptoUtils crypto = new CryptoUtils();
// return a base64 encoded AES encrypted text
/**
*
* #param pText to encrypt
* #param password password for encryption
* #return encoded pText
* #throws Exception
*/
protected byte[] encrypt(byte[] pText, char[] password) throws Exception {
// 64 bytes salt
byte[] salt = crypto.getRandomNonce(saltLengthByte);
// GCM recommended 12 bytes iv?
byte[] iv = crypto.getRandomNonce(ivLengthByte);
// secret key from password
SecretKey aesKeyFromPassword = crypto.getAESKeyFromPassword(password, salt);
Cipher cipher = Cipher.getInstance(algorithm);
// ASE-GCM needs GCMParameterSpec
cipher.init(Cipher.ENCRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(tagLengthBit, iv));
byte[] cipherText = cipher.doFinal(pText);
// prefix IV and Salt to cipher text
byte[] cipherTextWithIvSalt = ByteBuffer.allocate(iv.length + salt.length + cipherText.length).put(iv).put(salt)
.put(cipherText).array();
Main.clearArray(password, null);
Main.clearArray(null, salt);
Main.clearArray(null, iv);
Main.clearArray(null, cipherText);
aesKeyFromPassword = null;
cipher = null;
try {
return cipherTextWithIvSalt;
} finally {
Main.clearArray(null, cipherTextWithIvSalt);
}
}
// für Files
protected byte[] decrypt(byte[] encryptedText, char[] password)
throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
// get back the iv and salt from the cipher text
ByteBuffer bb = ByteBuffer.wrap(encryptedText);
byte[] iv = new byte[ivLengthByte];
bb.get(iv);
byte[] salt = new byte[saltLengthByte];
bb.get(salt);
byte[] cipherText = new byte[bb.remaining()];
bb.get(cipherText);
// get back the aes key from the same password and salt
SecretKey aesKeyFromPassword;
aesKeyFromPassword = crypto.getAESKeyFromPassword(password, salt);
Cipher cipher;
cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(tagLengthBit, iv));
byte[] plainText = cipher.doFinal(cipherText);
Main.clearArray(password, null);
Main.clearArray(null, iv);
Main.clearArray(null, salt);
Main.clearArray(null, cipherText);
aesKeyFromPassword = null;
cipher = null;
bb = null;
try {
return plainText;
} finally {
Main.clearArray(null, plainText);
}
}
protected void encryptFile(String file, char[] pw) throws Exception {
Path pathToFile = Paths.get(file);
byte[] fileCont = Files.readAllBytes(pathToFile);
byte[] encrypted = encrypt(fileCont, pw);
Files.write(pathToFile, encrypted);
Main.clearArray(pw, null);
Main.clearArray(null, fileCont);
Main.clearArray(null, encrypted);
}
protected void decryptFile(String file, char[] pw)
throws IOException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
Path pathToFile = Paths.get(file);
byte[] fileCont = Files.readAllBytes(pathToFile);
byte[] decrypted = decrypt(fileCont, pw);
Files.write(pathToFile, decrypted);
Main.clearArray(pw, null);
Main.clearArray(null, fileCont);
Main.clearArray(null, decrypted);
}
}
The corresponding CryptoUtils class:
class CryptoUtils {
protected byte[] getRandomNonce(int numBytes) {
byte[] nonce = new byte[numBytes];
new SecureRandom().nextBytes(nonce);
try {
return nonce;
} finally {
Main.clearArray(null, nonce);
}
}
// Password derived AES 256 bits secret key
protected SecretKey getAESKeyFromPassword(char[] password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
// iterationCount = 65536
// keyLength = 256
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
try {
return secret;
} finally {
secret = null;
}
}
// hex representation
protected String hex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
try {
return result.toString();
} finally {
result.delete(0, result.length() - 1);
}
}
// print hex with block size split
protected String hexWithBlockSize(byte[] bytes, int blockSize) {
String hex = hex(bytes);
// one hex = 2 chars
blockSize = blockSize * 2;
// better idea how to print this?
List<String> result = new ArrayList<>();
int index = 0;
while (index < hex.length()) {
result.add(hex.substring(index, Math.min(index + blockSize, hex.length())));
index += blockSize;
}
try {
return result.toString();
} finally {
result.clear();
}
}
}
The Exception occurs at byte[] plainText = cipher.doFinal(cipherText); in the decrypt method.
Im unsure if the tagLenthBit must be the ivLengthByte * 8, I did try it though and it didnt make any difference.
I'm providing my own example code for AES 256 GCM file encryption with PBKDF2 key derivation because I'm too lazy to check all parts of your code :-)
The encryption is done with CipherInput-/Outputstreams because that avoids "out of memory errors" when encrypting larger files (your code is reading the complete plaintext / ciphertext in a byte array).
Please note that the code has no exception handling, no clearing of sensitive data/variables and the encryption/decryption result is a simple "file exist" routine but I'm sure you can use it as a good basis for your program.
That's a sample output:
AES 256 GCM-mode PBKDF2 with SHA512 key derivation file encryption
result encryption: true
result decryption: true
code:
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class AesGcmEncryptionInlineIvPbkdf2BufferedCipherInputStreamSoExample {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, IOException,
InvalidKeyException, InvalidKeySpecException, InvalidAlgorithmParameterException {
System.out.println("AES 256 GCM-mode PBKDF2 with SHA512 key derivation file encryption");
char[] password = "123456".toCharArray();
int iterations = 65536;
String uncryptedFilename = "uncrypted.txt";
String encryptedFilename = "encrypted.enc";
String decryptedFilename = "decrypted.txt";
boolean result;
result = encryptGcmFileBufferedCipherOutputStream(uncryptedFilename, encryptedFilename, password, iterations);
System.out.println("result encryption: " + result);
result = decryptGcmFileBufferedCipherInputStream(encryptedFilename, decryptedFilename, password, iterations);
System.out.println("result decryption: " + result);
}
public static boolean encryptGcmFileBufferedCipherOutputStream(String inputFilename, String outputFilename, char[] password, int iterations) throws
IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException {
SecureRandom secureRandom = new SecureRandom();
byte[] salt = new byte[32];
secureRandom.nextBytes(salt);
byte[] nonce = new byte[12];
secureRandom.nextBytes(nonce);
Cipher cipher = Cipher.getInstance("AES/GCM/NOPadding");
try (FileInputStream in = new FileInputStream(inputFilename);
FileOutputStream out = new FileOutputStream(outputFilename);
CipherOutputStream encryptedOutputStream = new CipherOutputStream(out, cipher);) {
out.write(nonce);
out.write(salt);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec keySpec = new PBEKeySpec(password, salt, iterations, 32 * 8); // 128 - 192 - 256
byte[] key = secretKeyFactory.generateSecret(keySpec).getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * 8, nonce);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
byte[] buffer = new byte[8096];
int nread;
while ((nread = in.read(buffer)) > 0) {
encryptedOutputStream.write(buffer, 0, nread);
}
encryptedOutputStream.flush();
}
if (new File(outputFilename).exists()) {
return true;
} else {
return false;
}
}
public static boolean decryptGcmFileBufferedCipherInputStream(String inputFilename, String outputFilename, char[] password, int iterations) throws
IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException {
byte[] salt = new byte[32];
byte[] nonce = new byte[12];
Cipher cipher = Cipher.getInstance("AES/GCM/NOPadding");
try (FileInputStream in = new FileInputStream(inputFilename); // i don't care about the path as all is lokal
CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
FileOutputStream out = new FileOutputStream(outputFilename)) // i don't care about the path as all is lokal
{
byte[] buffer = new byte[8192];
in.read(nonce);
in.read(salt);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec keySpec = new PBEKeySpec(password, salt, iterations, 32 * 8); // 128 - 192 - 256
byte[] key = secretKeyFactory.generateSecret(keySpec).getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * 8, nonce);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
int nread;
while ((nread = cipherInputStream.read(buffer)) > 0) {
out.write(buffer, 0, nread);
}
out.flush();
}
if (new File(outputFilename).exists()) {
return true;
} else {
return false;
}
}
}

AES encryption .Net to Android for mobile

I referred to the below link
AES Encryption .net to swift,
But, applying the same for ANDROID, I am not able to get the correct AES encryption with version(PBKDF2) conversion for my code. NEED HELP.
public static String Encrypt(String PlainText) throws Exception {
try {
byte[] salt = new byte[] { 0x49, 0x76, 0x61, 0x6E, 0x20, 0x4D,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 };
System.out.println("Exception setting up cipher: "+pbkdf2("<keyname>",salt.toString(),1024,128));
Cipher _aesCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
byte[] keyBytes =pbkdf2("<keyname>",salt.toString(),1024,128).getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
byte[] iv ="OFRna73m*aze01xY".getBytes();//pbkdf2("<keyname>",salt.toString(),2,64).getBytes();
IvParameterSpec ivSpec = new IvParameterSpec(iv);
_aesCipher.init(1, keySpec, ivSpec);
byte[] plainText = PlainText.getBytes();
byte[] result = _aesCipher.doFinal(plainText);
return Base64.encodeToString(result, Base64.DEFAULT);//Base64.encode(result,1));
} catch (Exception ex1) {
System.out.println("Exception setting up cipher: "
+ ex1.getMessage() + "\r\n");
ex1.printStackTrace();
return "";
}
}
public static String pbkdf2(String password, String salt, int iterations, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
char[] chars = password.toCharArray();
PBEKeySpec spec = new PBEKeySpec(chars, salt.getBytes(), iterations, keyLength);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = skf.generateSecret(spec).getEncoded();
return toHex(hash);
}
// Converts byte array to a hexadecimal string
private static String toHex(byte[] array) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; i++) {
sb.append(Integer.toString((array[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
Please check below code .
I have created Singletone class for the same so that i can access it anywhere in app.
Below Points Should be same like .net or swift
Important Points are IV , SALT and PASSWORD
Please check this too PBKDF2WithHmacSHA1
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
to generate key we used this
KeySpec spec = new PBEKeySpec(password, salt, 2, 256);
Importnant points are (password, salt,iterantion,bytes) this must be same like other platform which you are using with like .net or swift
public class AesBase64Wrapper {
private static String IV = "it should be same like server or other platform";
private static String PASSWORD = "it should be same like server or other platform";
private static String SALT = "it should be same like server or other platform";
private static volatile AesBase64Wrapper sSoleInstance = new AesBase64Wrapper();
//private constructor.
private AesBase64Wrapper() {
}
public static AesBase64Wrapper getInstance() {
return sSoleInstance;
}
// For Encryption
public String encryptAndEncode(String raw) {
try {
Cipher c = getCipher(Cipher.ENCRYPT_MODE);
byte[] encryptedVal = c.doFinal(getBytes(raw));
//String retVal = Base64.encodeToString(encryptedVal, Base64.DEFAULT);
String retVal = Base64.encodeToString(encryptedVal, Base64.NO_WRAP);
return retVal;
}catch (Throwable t) {
throw new RuntimeException(t);
}
}
public String decodeAndDecrypt(String encrypted) throws Exception {
// byte[] decodedValue = Base64.decode(getBytes(encrypted),Base64.DEFAULT);
byte[] decodedValue = Base64.decode(getBytes(encrypted), Base64.NO_WRAP);
Cipher c = getCipher(Cipher.DECRYPT_MODE);
byte[] decValue = c.doFinal(decodedValue);
return new String(decValue);
}
private String getString(byte[] bytes) throws UnsupportedEncodingException {
return new String(bytes, "UTF-8");
}
private byte[] getBytes(String str) throws UnsupportedEncodingException {
return str.getBytes("UTF-8");
}
private Cipher getCipher(int mode) throws Exception {
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = getBytes(IV);
String xyz = String.valueOf(generateKey());
Log.i("generateKey", xyz);
c.init(mode, generateKey(), new IvParameterSpec(iv));
return c;
}
private Key generateKey() throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
char[] password = PASSWORD.toCharArray();
byte[] salt = getBytes(SALT);
KeySpec spec = new PBEKeySpec(password, salt, 2, 256);
SecretKey tmp = factory.generateSecret(spec);
byte[] encoded = tmp.getEncoded();
byte b = encoded[1];
Log.e("Secrete Key", String.valueOf(encoded));
return new SecretKeySpec(encoded, "CBC");
}
}
In Activity you can use it like
String EncryptString = AesBase64Wrapper.getInstance().encryptAndEncode("hello");
String DecryptString = AesBase64Wrapper.getInstance().encryptAndEncode(EncryptString);
// You will Get Output in Decrypted String

Android javax.crypto.BadPaddingException: pad block corrupted

I am trying to decrypt a file using the following code:
Uri targURI = Uri.parse("content://xxxx/yyy.txt");
try {
InputStream content = getContentResolver().openInputStream(targURI);
BufferedReader reader1 = new BufferedReader(new InputStreamReader(content));
String line1;
String text = "";
while ((line1 = reader1.readLine()) != null) {
text+=line1;
}
Log.i("FILE ENCRYPTED", text);
String DECRYPTED = "";
DECRYPTED = decrypt(text);
Log.i("FILE DECRYPTED:", DECRYPTED);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public String decrypt(String paramString) throws Exception {
String md5_pin1 = "";
String md5_pin = MD5(md5_pin1);
SecretKeySpec keySpec = new SecretKeySpec(md5_pin.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] paramString1 = Base64.decode(paramString.getBytes(), 0);
byte[] paramstring2 = cipher.doFinal(paramString1);
String decoded = new String(paramstring2, "UTF-8");
return decoded;
}
#NonNull
public static String MD5(String paramString) throws Exception {
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(paramString.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
int i=0;
while( i < messageDigest.length) {
String str = Integer.toHexString( messageDigest[i] & 0xFF );
if (str.length() == 1) {
hexString.append("0");
}
hexString.append(str);
i += 1;
}
return hexString.toString();
}
as it is showed the file is accessed using a content provider, and stored in a String variable, and actually the correct string value is stored (encrypted data).
The way to decrypt it is to get a seed (empty space in this case), and then use MD5 digest, then use that value to encrypt/decrypt the cleartext.
However whenever the code reaches: String decoded = new String(paramstring2, "UTF-8"); the error message: pad block corrupted is thrown.
Any ideas what I am doing wrong?
Avoid using default padding for cipher as it may be different on different environment.
Try the following code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Also use the same padding for encrypting the file.
You can use the following methods:
private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivParams);
return cipher.doFinal(data);
}
private static byte[] decrypt(byte[] encrypted, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivByte = new byte[cipher.getBlockSize()];
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), ivParamsSpec);
return cipher.doFinal(encrypted);
}
This was not a problem related to coding.
Please disregard this question

TripleDES encrypting with vb.net and decrypting with java

I'm creating an interface for two applications that will communicate using encrypted text in .txt files. vb.net app will encrypt and java will decrypt.
vb code
Dim nget As String = System.IO.File.ReadAllText(sInputFilename)
Dim textBytes As Byte() = System.Text.Encoding.Unicode.GetBytes(nget)
Dim Passphrase As String = sKey
Dim UTF8 As New System.Text.UTF8Encoding()
Dim HashProvider As New MD5CryptoServiceProvider()
Dim TDESKey As Byte() = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase))
Dim TDESAlgorithm As New TripleDESCryptoServiceProvider()
TDESAlgorithm.Key = TDESKey
TDESAlgorithm.Mode = CipherMode.ECB
TDESAlgorithm.Padding = PaddingMode.PKCS7
Dim ms As New System.IO.MemoryStream()
Dim encStream As New CryptoStream(ms, TDESAlgorithm.CreateEncryptor(), CryptoStreamMode.Write)
encStream.Write(textBytes, 0, textBytes.Length)
encStream.FlushFinalBlock()
Dim strSave As String = Convert.ToBase64String(ms.ToArray())
My.Computer.FileSystem.WriteAllText(sOutputFilename, strSave, False)
java code
public static void main(String[] args) {
String codedtext = null;
try {
codedtext = readFile("ect.txt", StandardCharsets.UTF_8);
} catch (IOException e1) {
e1.printStackTrace();
}
String decodedtext = null;
try {
decodedtext = _decrypt(codedtext,"abcdefgh");
} catch (Exception e) {
e.printStackTrace();
}
}
private static String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
private static String _encrypt(String message, String secretKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = message.getBytes("utf-8");
byte[] buf = cipher.doFinal(plainTextBytes);
byte [] base64Bytes = Base64.encodeBase64(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
private static String _decrypt(String encryptedText, String secretKey) throws Exception {
byte[] message = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
//byte[] message = encryptedText.getBytes("utf-8");
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");
//Cipher decipher = Cipher.getInstance("DESede");
Cipher decipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
but I'm getting the error
at java.lang.ArrayIndexOutOfBoundsException: -17
at org.apache.commons.codec.binary.Base64.isBase64(Base64.java:137)
at org.apache.commons.codec.binary.Base64.discardNonBase64(Base64.java:478)
at org.apache.commons.codec.binary.Base64.decodeBase64(Base64.java:374)
at Test.MyDec._decrypt(MyDec.java:74)
at Test.MyDec.main(MyDec.java:33)
when decoding from base64

Concatenating MAC and salt with ciphertext

I've been having trouble adding a MAC to my password-based AES encryption/decryption program. I am trying to add the MAC'd plaintext and salt (to be used with password) (both byte arrays) to a final array along with the ciphertext, and then decrypt by reading in the ciphertext file and splitting it back up into salt, MAC, and cipher text byte arrays.
The encryption class seems to be running smoothly but the decryption class does not. I debugged the the class and found that it fails because it never enters the if statement that checks whether the computed and recovered MACs are the same:
if(Arrays.equals(macBytes, hmac))
I couldn't figure out why until I printed out the byte arrays for the salt, message, and MAC, and found that they don't match when printed from the encryption and decryption classes. All the array sizes match up across the two classes, but the byte values change somewhere.
Both classes worked perfectly without the MAC before, but I didn't add the salt directly to the encrypted data then and instead wrote it to a separate file. Including it with the encrypted data makes this slightly more portable for me, but was it a bad choice to do so? Is it better to write it to a separate file? Or am I just missing something blatantly obvious in my code?
Here is the full code.
Encryption class
public class AESEncryption
{
private final String ALGORITHM = "AES";
private final String MAC_ALGORITHM = "HmacSHA256";
private final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private final String KEY_DERIVATION_FUNCTION = "PBKDF2WithHmacSHA1";
private final String PLAINTEXT = "/Volumes/CONNOR P/Unencrypted.txt";
private final String ENCRYPTED = "/Volumes/CONNOR P/Encrypted.txt";
private final String PASSWORD = "javapapers";
private final String LOC = Paths.get(".").toAbsolutePath().normalize().toString();
private static final int SALT_SIZE = 64;
private final int KEY_LENGTH = 128;
private final int ITERATIONS = 100000;
public AESEncryption()
{
try
{
encrypt();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error: " + ex.getClass().getName(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
private void encrypt() throws Exception
{
File encrypted = new File(ENCRYPTED);
File plaintext = new File(PLAINTEXT);
int encryptedSize = (int)encrypted.length();
int plaintextSize = (int)plaintext.length();
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(PLAINTEXT));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(ENCRYPTED));
//Create salt
byte[] salt = new byte[SALT_SIZE];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(salt);
//Create cipher key
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DERIVATION_FUNCTION);
KeySpec keySpec = new PBEKeySpec(PASSWORD.toCharArray(), salt, ITERATIONS, KEY_LENGTH);
SecretKey secret = new SecretKeySpec(factory.generateSecret(keySpec).getEncoded(), ALGORITHM);
//Create cipher
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
//Read plaintext file into byte array
byte[] input = new byte[encryptedSize];
Path path = Paths.get(PLAINTEXT);
input = Files.readAllBytes(path);
byte[] crypt = cipher.doFinal(input);
//Create MAC object and apply to the byte array crypt[] containing the plaintext
KeyGenerator keyGenerator = KeyGenerator.getInstance(MAC_ALGORITHM);
SecretKey macKey = keyGenerator.generateKey();
Mac mac = Mac.getInstance(MAC_ALGORITHM);
mac.init(macKey);
byte[] macBytes = mac.doFinal(crypt);
//Add salt, MAC'd plaintext, and encrypted plaintext to final array
byte[] output = new byte[SALT_SIZE + crypt.length + macBytes.length];
System.arraycopy(salt, 0, output, 0, SALT_SIZE);
System.arraycopy(macBytes, 0, output, SALT_SIZE, macBytes.length);
System.arraycopy(crypt, 0, output, SALT_SIZE + macBytes.length, crypt.length);
//Write array with encrypted data to a new file
bufferedOutputStream.write(output);
bufferedInputStream.close();
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
Decryption class
public class AESDecryption
{
private final String ALGORITHM = "AES";
private final String MAC_ALGORITHM = "HmacSHA256";
private final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private final String KEY_DERIVATION_FUNCTION = "PBKDF2WithHmacSHA1";
private final String PLAINTEXT = "/Volumes/CONNOR P/De-Encrypted.txt";
private final String ENCRYPTED = "/Volumes/CONNOR P/Encrypted.txt";
private final String PASSWORD = "javapapers";
private final String LOC = Paths.get(".").toAbsolutePath().normalize().toString();
private final int SALT_SIZE = 64;
private final int IV_SIZE = 16;
private final int KEY_LENGTH = 128;
private final int ITERATIONS = 100000;
public AESDecryption()
{
try
{
decrypt();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error: " + ex.getClass().getName(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
private void decrypt() throws Exception
{
File encrypted = new File(ENCRYPTED);
File plaintext = new File(PLAINTEXT);
int encryptedSize = (int)encrypted.length();
int plaintextSize = (int)plaintext.length();
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(encrypted));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(plaintext));
//Read in the encrypted data
byte[] input = new byte[encryptedSize];
Path path = Paths.get(ENCRYPTED);
input = Files.readAllBytes(path);
int increment = (input.length-SALT_SIZE)/2;
if(input.length >= (SALT_SIZE + increment))
{
//Recover salt, MAC, and encrypted data and store in arrays
byte[] salt = Arrays.copyOfRange(input, 0, SALT_SIZE);
byte[] macBytes = Arrays.copyOfRange(input, SALT_SIZE, SALT_SIZE + increment);
byte[] crypt = Arrays.copyOfRange(input, SALT_SIZE + increment, input.length);
//Regenerate original MAC
KeyGenerator keyGenerator = KeyGenerator.getInstance(MAC_ALGORITHM);
SecretKey macKey = keyGenerator.generateKey();
Mac mac = Mac.getInstance(MAC_ALGORITHM);
mac.init(macKey);
byte[] hmac = mac.doFinal(crypt);
if(Arrays.equals(macBytes, hmac)) //This is where it fails, never enters
{
//Regenerate cipher and decrypt data
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DERIVATION_FUNCTION);
KeySpec keySpec = new PBEKeySpec(PASSWORD.toCharArray(), salt, ITERATIONS, KEY_LENGTH);
SecretKey secret = new SecretKeySpec(factory.generateSecret(keySpec).getEncoded(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
//Write decrypted data to new text file
byte[] output = cipher.doFinal(crypt);
bufferedOutputStream.write(output);
bufferedInputStream.close();
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
}
}
Thanks for any help. It is much appreciated.
public class AESEncryption
{
private final String ALGORITHM = "AES";
private final String MAC_ALGORITHM = "HmacSHA256";
private final String PRNG_ALGORITHM = "SHA1PRNG";
private final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private final String PLAINTEXT = "/Volumes/CONNOR P/Unencrypted.txt";
private final String ENCRYPTED = "/Volumes/CONNOR P/Encrypted.txt";
private final String PASSWORD = "javapapers";
private final String IV_FILE_NAME = "iv.enc";
private final String LOC = Paths.get(".").toAbsolutePath().normalize().toString();
private final int SALT_SIZE = 16;
private final int IV_SIZE = 16;
private final int KEY_LENGTH = 128;
private final int ITERATIONS = 100000;
private final int START = 0;
public AESEncryption()
{
try
{
encrypt();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error: " + ex.getClass().getName(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
private void encrypt() throws Exception
{
File encrypted = new File(ENCRYPTED);
File plaintext = new File(PLAINTEXT);
int plaintextSize = (int)plaintext.length();
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(plaintext));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(encrypted));
//Create salt for cipher key
byte[] salt = new byte[SALT_SIZE];
SecureRandom saltSecureRandom = SecureRandom.getInstance(PRNG_ALGORITHM);
saltSecureRandom.nextBytes(salt);
//Create cipher key & use to initialize cipher
byte[] keyBytes = PBEKeyFactory.getKey(PASSWORD, salt, ITERATIONS, KEY_LENGTH);
SecretKeySpec secret = new SecretKeySpec(keyBytes, ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
//Create byte array of encrypted data
byte[] input = new byte[plaintextSize];
Path path = Paths.get(PLAINTEXT);
input = Files.readAllBytes(path);
byte[] crypt = cipher.doFinal(input);
//Create salt for the MAC key for added security
byte[] macsalt = new byte[SALT_SIZE];
SecureRandom macsaltSecureRandom = SecureRandom.getInstance(PRNG_ALGORITHM);
macsaltSecureRandom.nextBytes(macsalt);
//PBEKeyFactory.getKey(password, salt, iterations, keylength)
//returns a byte array representation of a SecretKey.
//Used a SecretKeyFactory instead of a KeyGenerator to make key.
//SecretKeyFactory gives back the same key given the same specifications
//whereas KeyGenerator gives back a new random key each time.
byte[] macPBE = PBEKeyFactory.getKey(PASSWORD, macsalt, ITERATIONS, KEY_LENGTH);
SecretKeySpec macKey = new SecretKeySpec(macPBE, MAC_ALGORITHM);
Mac mac = Mac.getInstance(MAC_ALGORITHM);
mac.init(macKey);
byte[] macBytes = mac.doFinal(crypt);
byte[] output = new byte[SALT_SIZE + SALT_SIZE + crypt.length + macBytes.length];
System.arraycopy(salt, START, output, START, SALT_SIZE);
System.arraycopy(macsalt, START, output, SALT_SIZE, SALT_SIZE);
System.arraycopy(macBytes, START, output, SALT_SIZE + SALT_SIZE, macBytes.length);
System.arraycopy(crypt, START, output, SALT_SIZE + SALT_SIZE + macBytes.length, crypt.length);
bufferedInputStream.close();
bufferedOutputStream.write(output);
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
}
public class AESDecryption
{
private final String ALGORITHM = "AES";
private final String MAC_ALGORITHM = "HmacSHA256";
private final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private final String PLAINTEXT = "/Volumes/CONNOR P/De-Encrypted.txt";
private final String ENCRYPTED = "/Volumes/CONNOR P/Encrypted.txt";
private final String PASSWORD = "javapapers";
private final String LOC = Paths.get(".").toAbsolutePath().normalize().toString();
private final int SALT_SIZE = 16;
//MAC key size is 256 bits (32 bytes) since it is created with
//the HmacSHA256 algorithm
private final int MAC_SIZE = 32;
private final int IV_SIZE = 16;
private final int START = 0;
private final int KEY_LENGTH = 128;
private final int ITERATIONS = 100000;
public AESDecryption()
{
try
{
decrypt();
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error: " + ex.getClass().getName(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
private void decrypt() throws Exception
{
File encrypted = new File(ENCRYPTED);
File plaintext = new File(PLAINTEXT);
int encryptedSize = (int)encrypted.length();
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(encrypted));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(plaintext));
//Read in encrypted data
byte[] input = new byte[encryptedSize];
Path path = Paths.get(ENCRYPTED);
input = Files.readAllBytes(path);
if(input.length >= (SALT_SIZE*2 + MAC_SIZE))
{
byte[] cryptSalt = Arrays.copyOfRange(input, START, SALT_SIZE);
byte[] macSalt = Arrays.copyOfRange(input, SALT_SIZE, SALT_SIZE*2);
byte[] macBytes = Arrays.copyOfRange(input, SALT_SIZE*2, (SALT_SIZE*2 + MAC_SIZE));
byte[] cryptBytes = Arrays.copyOfRange(input, (SALT_SIZE*2 + MAC_SIZE), input.length);
//This generates the same MAC key from encryption.
//Before, the KeyGenerator created a new random key
//meaning the derived and computed MAC keys were never the same
byte[] macKeyBytes = PBEKeyFactory.getKey(PASSWORD, macSalt, ITERATIONS, KEY_LENGTH);
SecretKeySpec macKey = new SecretKeySpec(macKeyBytes, MAC_ALGORITHM);
Mac mac = Mac.getInstance(MAC_ALGORITHM);
mac.init(macKey);
byte[] compMacBytes = mac.doFinal(cryptBytes);
//Check if computed and derived MAC's are the same
if(Arrays.equals(macBytes, compMacBytes))
{
//Creates same key from encryption
byte[] cryptKeyBytes = PBEKeyFactory.getKey(PASSWORD, cryptSalt, ITERATIONS, KEY_LENGTH);
SecretKeySpec cryptKey = new SecretKeySpec(cryptKeyBytes, ALGORITHM);
//Creates cipher and reads decrypted data to array
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, cryptKey, new IvParameterSpec(new byte[16]));
byte[] output = cipher.doFinal(cryptBytes);
bufferedInputStream.close();
bufferedOutputStream.write(output);
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
}
}
}
//This class has only one method, getKey(), which returns a byte array
//of a SecretKey of the corresponding parameters
public class PBEKeyFactory
{
private static final String KEY_DERIVATION_FUNCTION = "PBKDF2WithHmacSHA1";
public static byte[] getKey(String password, byte[] salt, int iterations, int length) throws Exception
{
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterations, length);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DERIVATION_FUNCTION);
return factory.generateSecret(keySpec).getEncoded();
}
}

Categories