So this particular exception is pretty common, yet my problem is slightly different from what is usually asked.
I've got a AES decrytpion and encryption function defined as followed:
public static byte[] encrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher;
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
public static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
Now if I perform a single decryption like this:
System.out.println(Arrays.toString(
AES256Cipher.decrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(bKeys[b]), HexBytePlainWriter.hexStringToByteArray(zkeys[a^b]))
)
)));
The byte array outputs just fine. Whereas if I perform double encryption/decryption:
System.out.println("dec: " + HexBytePlainWriter.ByteToHexString(
AES256Cipher.decrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
AES256Cipher.decrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(bKeys[b]),
AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(bKeys[b]), HexBytePlainWriter.hexStringToByteArray(zkeys[a^b]))
)
))));
I get the famous javax.crypto.BadPaddingException: Given final block not properly padded Exception. Note that a and b are just integers (assume they are both 0). Currently, the IVBytes is just an empty byte array of size 16, declared with new byte[16]. and aKeys and bKeys are both String arrays with AES encypted (random) strings (length 32 bytes).
These are the helper functions I use (to turn byte[] into a hex string and vice versa):
public static String ByteToHexString (byte[] data) {
StringBuilder buf = new StringBuilder();
for (byte b : data) {
int halfbyte = (b >>> 4) & 0x0F;
int two_halfs = 0;
do {
buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
halfbyte = b & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString();
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
I suspect that the output of the first decryption malforms the ciphertext in such a way that the outer part throw the exception. I've check the size and the outer part outputs 32 bytes, so that should be OK. Does this not comply with the PKC5Padding?
Any help is much appreciated.
Edit:
It looks like my minimal example was faulty: I used key B first instead of A. Jon Skeet did give me an idea though. I will edit if I've got anything new.
Edit2:
The idea was correct. I was looping over a Garbled truth table (for those interested, check this Wikipedia article) and checking all possible ciphertexts (CT). The problem was if you pick an incorrect CT and use double decryption on it, it will throw the exception because the first decryption returns garbage. A simple check on the keys in the table fixed this.
You're using the wrong keys for decrypting. You're encrypting with key B, then encrypting the result with key A. You're then trying to decrypt that result with key B, and the final result with key A.
Each time you decrypt, you should be specifying the same key that was used to perform the "most recent" encryption operation. So:
Encrypt Encrypt Decrypt Decrypt
with B with A with A with B
Plain text -> encrypted I -> encrypted II -> encrypted I -> plain text
I'd also suggest that performing these operations one statement at a time, rather than having to read from the bottom up due to doing everything in a single statement, would make it a lot easier to understand what's going on.
Related
We have recently migrated our infrastructure from Solaris(Oracle/Sun Java) to AIX(IBM Java).
Our clients will upload an encrypted file using the algorithm(AES) and key shared by us,once the encrypted files are placed in our server, an batch routine will decrypt using the same key. This was working well till migration but post migration, the AES decryption functionality does not work.
Earlier we used
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
Post migration, we have changed it as
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
When batch is executing, we get exception as below
javax.crypto.IllegalBlockSizeException: Input length (with padding) not multiple of 16 bytes
at com.ibm.crypto.provider.AESCipher.a(Unknown Source)
at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
at com.ibm.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Unknown Source)
The code used for decryption
private byte[] decrypt(byte[] data, String corporateId, String algorithm)
throws Exception {
String path = corporateId + ".key";
byte[] key = (byte[]) null;
try {
key = returnbyte(path);
} catch (IOException e) {
e.printStackTrace();
}
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.logger.info("Provider Info " + cipher.getProvider().getInfo());
byte[] keyBytes = new byte[16];
int len = key.length;
if (len > keyBytes.length) {
len = keyBytes.length;
}
System.arraycopy(key, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(2, keySpec, ivSpec);
BASE64Decoder decoder = new BASE64Decoder();
byte[] results = decoder.decodeBuffer(hexStringFromBytes(data));
byte[] ciphertext = cipher.doFinal(results);
return ciphertext;
}
hexStringFromBytes Method:
public static String hexStringFromBytes(byte[] ba) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ba.length; i++) {
if ((i > 0) && ((i & 0x1F) == 0)) {
sb.append("\n");
} else if ((i > 0) && ((i & 0x3) == 0)) {
sb.append("");
}
sb.append(hexChars[((0xF0 & ba[i]) >> 4)]);
sb.append(hexChars[(0xF & ba[i])]);
}
return sb.toString();
}
Not sure about the cause of problem, cipher.doFinal(results); throws error.
The class loader also shows that IBMJCE provider being used. Struck with this issue for 3 days. Any direction or guidance to resolve issue is much appreciated. Thanks in advance.
The issue is probably with your padding. As it says " Input length (with padding) not multiple of 16 bytes". As I found in the previous questions, the is not suitable for AES, cause AES block size is 16, not 8, You can find it below:
AES/CBC/PKCS5Padding vs AES/CBC/PKCS7Padding with 256 key size performance java
So You must try to use another padding algorithm for it to work.
This is the code in question:
decrypt(self):
"""Decrypt one block"""
data = self.source.read(1024)
if not data:
return ""
iv = data[:16]
encrypted = data[16:]
counter = Crypto.Util.Counter.new(64, prefix=iv[:8], initial_value=struct.unpack(">Q", iv[8:])[0])
cipher = Crypto.Cipher.AES.new(self.info["CpData"], Crypto.Cipher.AES.MODE_CTR, counter=counter)
return cipher.decrypt(encrypted)
This is the line I have problems understanding:
counter = Crypto.Util.Counter.new(64, prefix=iv[:8], initial_value=struct.unpack(">Q", iv[8:])[0])
What does it do and how do I replicate it in Java? Currently I have this, but the result is not what I expect:
public static byte[] decrypt(byte[] encryptedData) throws Exception {
Key key = new SecretKeySpec(keyBytes, "AES");
Cipher c = Cipher.getInstance("AES/CTR/NoPadding");
byte[] iv = Arrays.copyOfRange(encryptedData, 0, 16) ; // first 16 bytes
byte[] data = Arrays.copyOfRange(encryptedData, 16, 1024); // rest
IvParameterSpec ivSpec = new IvParameterSpec(iv);
c.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decValue = c.doFinal(data);
return decValue;
}
Hours of googling have not yielded a useable result. How do I use this counter thing in Java?
Thanks!
On a quick look it appears that there is 8 bytes of IV prepended to the incoming cyphertext. Extract the first 8 bytes and use them as an IV to set up AES-CTR. Then decrypt the rest of the cyphertext.
Blowfish is capable of strong encryption and can use key sizes up to 56 bytes (a 448 bit key).
The key must be a multiple of 8 bytes (up to a maximum of 56).
I want to write example will automatically pad and unpad the key to size. Because Blowfish creates blocks of 8 byte encrypted output, the output is also padded and unpadded to multiples of 8 bytes.
actually want to write java code to simulate-
http://webnet77.com/cgi-bin/helpers/blowfish.pl
I am using info for tool-
ALGORITM = "Blowfish";
HEX KEY = "92514c2df6e22f079acabedce08f8ac3";
PLAIN_TEXT = "sangasong#song.com"
Tool returns-
CD3A08381467823D4013960E75E465F0B00C5E3BAEFBECBB
Please suggest.
Tried the java code:
public class TestBlowfish
{
final String KEY = "92514c2df6e22f079acabedce08f8ac3";
final String PLAIN_TEXT = "sangasong#song.com";
byte[] keyBytes = DatatypeConverter.parseHexBinary(KEY);
}
public static void main(String[] args) throws Exception
{
try
{
byte[] encrypted = encrypt(keyBytes, PLAIN_TEXT);
System.out.println( "Encrypted hex: " + Hex.encodeHexString(encrypted));
}catch (GeneralSecurityException e)
{
e.printStackTrace();
}
}
private static byte[] encrypt(byte[] key, String plainText) throws GeneralSecurityException
{
SecretKey secret_key = new SecretKeySpec(key, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secret_key);
return cipher.doFinal(plainText.getBytes());
}
Result -
Encrypted hex: 525bd4bd786a545fe7786b0076b3bbc2127425f0ea58c29d
So the script uses an incorrect version of PKCS#7 padding that does not pad when the size of the input is already dividable by the block size - both for the key and the plaintext. Furthermore it uses ECB mode encryption. Neither of which should be used in real life scenarios.
The following code requires the Bouncy Castle provider to be added to the JCE (Service.addProvider(new BouncyCastleProvider())) and that the Hex class of Bouncy Castle libraries is in the class path.
Warning: only tested with limited input, does not cut the key size if the size of the key is larger than the maximum.
WARNING: THE FOLLOWING CODE IS NOT CRYPTOGRAPHICALLY SOUND
import org.bouncycastle.util.encoders.Hex;
public class BadBlowfish {
private static SecretKey createKey(String theKey) {
final byte[] keyData = theKey.getBytes(StandardCharsets.US_ASCII);
final byte[] paddedKeyData = halfPadPKCS7(keyData, 8);
SecretKey secret = new SecretKeySpec(paddedKeyData, "Blowfish");
return secret;
}
private static byte[] halfUnpadPKCS7(final byte[] paddedPlaintext, int blocksize) {
int b = paddedPlaintext[paddedPlaintext.length - 1] & 0xFF;
if (b > 0x07) {
return paddedPlaintext.clone();
}
return Arrays.copyOf(paddedPlaintext, paddedPlaintext.length - b);
}
private static byte[] halfPadPKCS7(final byte[] plaintext, int blocksize) {
if (plaintext.length % blocksize == 0) {
return plaintext.clone();
}
int newLength = (plaintext.length / blocksize + 1) * blocksize;
int paddingLength = newLength - plaintext.length;
final byte[] paddedPlaintext = Arrays.copyOf(plaintext, newLength);
for (int offset = plaintext.length; offset < newLength; offset++) {
paddedPlaintext[offset] = (byte) paddingLength;
}
return paddedPlaintext;
}
public static void main(String[] args) throws Exception {
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
SecretKey key = createKey("123456781234567");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plaintextData = cipher.doFinal(Hex.decode("085585C60B3D23257763E6D8BB0A0891"));
byte[] unpaddedPlaintextData = halfUnpadPKCS7(plaintextData, cipher.getBlockSize());
String plaintextHex = Hex.toHexString(unpaddedPlaintextData);
System.out.println(plaintextHex);
String plaintext = new String(unpaddedPlaintextData, StandardCharsets.UTF_8);
System.out.println(plaintext);
}
}
I am not sure about the relevance of this question: IMHO there is no point of getting the same output as this script: you have no guaranty about how secure/efficient it is...
What raises my eyebrow is the part about the padding: there are several solution to pad a block, some of then are simple but very unsecured, and maybe this script is using one of these "bad" solution.
Did you check that your program is able to retrieve the correct plain text ? (you will need to code the matching decrypt function).
If so, it means that it works correctly and it can be used for whatever your original purpose was, regardless what the ouput of this script is...
I want to encrypt and decrypt integers with AES but can't get it going.
To test the basic cryptographic process I wrote a simple method that takes input data, encrypts and decrypts it with the same parameters and returns the result.
Here is my failing JUnit test case that checks whether the input and the output data are equal.
#Test
public void test4() throws UnsupportedEncodingException {
Random random = new Random();
SecretKey secretKey = Tools.generateKey("secretKey".getBytes("UTF-8"));
byte[] initializationVector = Tools.intToByteArray(random.nextInt());
// ensuring that the initialization vector has the correct length
byte[] ivHash = Tools.hashMD5(initializationVector);
int value = random.nextInt();
byte[] input = Tools.intToByteArray(value);
byte[] received = Tools.enDeCrypt(input, secretKey, ivHash);
assertEquals(data.hashCode(), received.hashCode());
}
Method generateKey:
public static SecretKeySpec generateKey(byte[] secretKey) {
try {
// 256 bit key length
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(secretKey);
byte[] key = md.digest();
return new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
Method for int -> byte[] conversion:
public static byte[] intToByteArray(int a) {
// block size is 128 bit, thus I append zeros
byte[] intByte = ByteBuffer.allocate(4).putInt(a).array();
byte[] longerIntByte = new byte[16];
for (int i = 0; i < 4; i++) {
longerIntByte[i] = intByte[i];
}
for (int i = 4; i < longerIntByte.length; i++) {
longerIntByte[i] = 0;
}
return longerIntByte;
}
Here is the code for encryption and decryption:
public static byte[] enDeCrypt(byte[] data, SecretKey secretKey,
byte[] initialisationVector) {
try {
IvParameterSpec ivSpec = new IvParameterSpec(initialisationVector);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
byte[] encrypted = cipher.doFinal(data);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
} catch (NoSuchAlgorithmException | NoSuchPaddingException
| InvalidKeyException | InvalidAlgorithmParameterException
| IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException(e);
}
}
assertEquals(data.hashCode(), received.hashCode()) is very unlikely to pass unless data and received refer to the same object (since byte arrays inherit the identity hash code method from Object). I don't see where data comes from, but that is probably not the case here. You should use Arrays.equals(data, received).
Apart from that, there are various cryptographic issues here:
Random is not "random enough" for cryptographic purposes; you should use SecureRandom.
Key derivation using plain SHA-256 is dubious. You should consider using a key derivation algorithm that is specifically designed for this, like PBKDF2.
AES with 256-bit keys is not always better than 128-bit keys. Check this page. In this case it's completely bogus since passphrases rarely even reach 128 bits of entropy.
Random IVs – good, but why jump through hoops when you could just directly use SecureRandom.nextBytes(). Hashing the IV doesn't add anything useful.
There's no reason to do manual zero padding when you could instead let the library handle it. Just specify PKCS5Padding instead of NoPadding.
I'm making an app that encrypts some files. I want to use gnu's cryptix library. It says it is no longer developed since 2005, but I guess it has everything I need... should I use something else?
And I have a question about encrypting a single file. Right now I do it with a loop like this:
for(int i=0; i+block_size < bdata.length; i += block_size)
cipher.encryptBlock(bdata, i, cdata, i);
So my question is how to encrypt the last block that may not have the same size as the block_size. I was thinking maybe a should add some extra data to the last block, but than I don't know how to decrypt that...
I would strongly suggest using AES encryption and it too comes with the JAVA SDK. Have a look at: Using AES with Java Technology which will give you some great example. To read up more on AES see: Advanced Encryption Standard - Wikipedia.
Never use your own encryption scheme or an older form of an encryption scheme. AES has been tried and tested by people with far greater knowledge in that field then us, so you know it will work. Where as with your own or an old encryption scheme we might miss a fatal loop hole that will leave our data open to attacks.
See this question here to see the difference in the encryption schemes: Comparison of DES, Triple DES, AES, blowfish encryption for data
Addendum:
AES in java will work flawlessly for 192 and 256bit keys but you will have to install the newer JCE Policy Files. See here and here. You should also place the files in your JDK or else it wont work when executed from your IDE.
Note: Make sure you download the correct JCE policy files, depending on your Java version i.e 1.4, 1.5 1.6 or 7.
However if you use 128bit keys no need to install the newer JCE files.
Here is a template of some secure AES usage in java it use CBC/AES/PKCS5Padding and a random IV using RandomSecure.
Note you need both the key and IV for decrypting:
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This program generates a AES key, retrieves its raw bytes, and then
* reinstantiates a AES key from the key bytes. The reinstantiated key is used
* to initialize a AES cipher for encryption and decryption.
*/
public class AES {
/**
* Encrypt a sample message using AES in CBC mode with a random IV genrated
* using SecyreRandom.
*
*/
public static void main(String[] args) {
try {
String message = "This string contains a secret message.";
System.out.println("Plaintext: " + message + "\n");
// generate a key
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128); // To use 256 bit keys, you need the "unlimited strength" encryption policy files from Sun.
byte[] key = keygen.generateKey().getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
// build the initialization vector (randomly).
SecureRandom random = new SecureRandom();
byte iv[] = new byte[16];//generate random 16 byte IV AES is always 16bytes
random.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// initialize the cipher for encrypt mode
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
System.out.println("Key: " + new String(key, "utf-8") + " This is important when decrypting");
System.out.println("IV: " + new String(iv, "utf-8") + " This is important when decrypting");
System.out.println();
// encrypt the message
byte[] encrypted = cipher.doFinal(message.getBytes());
System.out.println("Ciphertext: " + asHex(encrypted) + "\n");
// reinitialize the cipher for decryption
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
// decrypt the message
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("Plaintext: " + new String(decrypted) + "\n");
} catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
/**
* Turns array of bytes into string
*
* #param buf Array of bytes to convert to hex string
* #return Generated hex string
*/
public static String asHex(byte buf[]) {
StringBuilder strbuf = new StringBuilder(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
}
I always use BouncyCastle
I also use the streaming framework instead of the for loop you were describing: it deals with the issue raised. Mostly I use that because when it comes to cryptography (and threading) I rarely trust my own code, I trust the people that live eat and breath it. Here is the code I use when I want "gash" cryptography. i.e. I have no particular threat model, and just want something "a little secure".
The hex encoding of the keys makes them much easier to manipulate / store and so on. I use "makeKey" to ... well ... make a key, then I can use the key in the encrypt and decrypt methods. You can obviously go back to using byte[] instead of hex strings for the keys.
private static boolean initialised;
private static void init() {
if (initialised)
return;
Security.addProvider(new BouncyCastleProvider());
initialised = true;
}
public static String makeKey() {
init();
KeyGenerator generator = KeyGenerator.getInstance(algorithm, provider);
generator.init(keySize);
Key key = generator.generateKey();
byte[] encoded = key.getEncoded();
return Strings.toHex(encoded);
}
public static String aesDecrypt(String hexKey, String hexCoded) {
init();
SecretKeySpec key = new SecretKeySpec(Strings.fromHex(hexKey), algorithm);
Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding", provider);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] codedBytes = Strings.fromHex(hexCoded);
CipherInputStream inputStream = new CipherInputStream(new ByteArrayInputStream(codedBytes), cipher);
byte[] bytes = getBytes(inputStream, 256);
String result = new String(bytes, "UTF-8");
return result;
}
public static String aesEncrypt(String hexKey, String input) {
init();
SecretKeySpec key = new SecretKeySpec(Strings.fromHex(hexKey), algorithm);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(input.length());
CipherOutputStream outputStream = new CipherOutputStream(byteArrayOutputStream, cipher);
setText(outputStream, input);
byte[] outputBytes = byteArrayOutputStream.toByteArray();
String output = new String(Strings.toHex(outputBytes));
return output;
}
public static void setText(OutputStream outputStream, String text, String encoding) {
try {
outputStream.write(text.getBytes(encoding));
outputStream.flush();
} finally {
outputStream.close();
}
}
public static byte[] getBytes(InputStream inputStream, int bufferSize) {
try {
List<ByteArrayAndLength> list = Lists.newList();
while (true) {
byte[] buffer = new byte[bufferSize];
int count = inputStream.read(buffer);
if (count == -1) {
byte[] result = new byte[ByteArrayAndLength.length(list)];
int index = 0;
for (ByteArrayAndLength byteArrayAndLength : list) {
System.arraycopy(byteArrayAndLength.bytes, 0, result, index, byteArrayAndLength.length);
index += byteArrayAndLength.length;
}
assert index == result.length;
return result;
}
list.add(new ByteArrayAndLength(buffer, count));
}
} finally {
inputStream.close();
}
}
static class ByteArrayAndLength {
byte[] bytes;
int length;
public ByteArrayAndLength(byte[] bytes, int length) {
super();
this.bytes = bytes;
this.length = length;
}
static int length(List<ByteArrayAndLength> list) {
int result = 0;
for (ByteArrayAndLength byteArrayAndLength : list) {
result += byteArrayAndLength.length;
}
return result;
}
}
I've taken out some of the exception catching to reduce the size of the code, and Strings.fromHex turns the string back into a byte[]
Maybe you should consider using a javax.crypto package.
Here is an example of how to use Ciphers:
DES encryption
Hope this helps
I would seriously think twice before going this route. The development of the software was halted because standard alternatives exist, and have a look at the mailing list, there's been no significant activity since 2009. In my book that means that the software is abandoned, and abandoned software means you're more or less on your own.
Have a look here on SO, there are several questions and answers that may help you like this one. An at first sight interesting package that could simplify things for you (but still using the standard JCE infrastructure) is jasypt