C# encrypted data getting truncated using Java decryption code - java

All,I am posting some encrypted xml data(Using AES-128 ) to another application that uses Java to decrypt.When the Java code decrypts the xml,the start tag of the xml is getting truncated and fails validation.I don't have access to their code base .I can decrypt the same data using C# without any data loss.Please see the code I use to encrypt and Decrypt the data . I have researched this and based on the research ,I added the FlushFinalBlocks() and Close() to the CryptoStream in the encryption logic ,but this doesnt seem to fix the issue.
Encryption Code:
public static string Aes128Encrypt(string plainText)
{
string encodedPayload = null;
string base64Iv = null;
string base64Key = null;
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.BlockSize = 128;
base64Iv = Convert.ToBase64String(aesAlg.IV);
base64Key = Convert.ToBase64String(aesAlg.Key);
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(plainBytes, 0, plainBytes.Length);
csEncrypt.FlushFinalBlock();
encodedPayload = Convert.ToBase64String(msEncrypt.ToArray());
csEncrypt.Close();
}
msEncrypt.Flush();
msEncrypt.Close();
}
}
return encodedPayload ;
}
Decryption Code:
public static string Aes128Decrypt(string base64Key, string base64IV, string encodedPayload)
{
string plainText = null;
byte[] key = Convert.FromBase64String(base64Key);
byte[] iv = Convert.FromBase64String(base64IV);
byte[] encryptedBytes = Convert.FromBase64String(encodedPayload);
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.KeySize = 128;
aesAlg.Mode = CipherMode.CBC;
aesAlg.BlockSize = 128;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = key;
aesAlg.IV = iv;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(encryptedBytes))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plainText = srDecrypt.ReadToEnd();
}
}
}
}
return plainText;
}
Testing Code:
string textXml = #"<person>
<firstName>Rennish</firstName>
<lastName>Joseph</lastName>
<accountNumber>12345678910</accountNumber>
<ssn>123456</ssn>
</person>";
Aes128Encrypt(textXml);
string encodedPayload = "4p6uU7SiqB0uCzsrWXMOStP02HM7mKA6QVzcKoNdu3w1+MYLjYVbW/Ig3XPKRRafeu+WKDMuKJJaEREkrZt/Ycvc50wfe2naJ9d0UT5B7Fre1gIsNfZUIK3SF304+WF8zX730mVsluJABKT3JCkk9AkOGCQWPYzcZvH9dojIqGP7V+2j1+IMOPMWWFIitkAi8B7ALxMuMcepzX2/cxHxH7NeID0ytEGUzGfJXSAzQcvBX9dWwUqdMX3Eip5SRPMsotnWWsFTjDuOiZk/q5fuxxWbS6cuYn/64C/vQjEIuheQKn0ZOIDLNPCUavvWD2u6PWNKMNgW/qUIq13W9PQxzIiQxrT7ZqPFJu75C1KdXXUG5lghU7EBAGehHC/5BqFjs9SuYJkV1RrchMEzytrJIQ7Zp4CnOU6Q1rEhFTaMk/s=";
string encodedKey = "2zpVbIxqvjSfJo7zkXzl2A==";
string encodedIV = "5WOQPdmB/BkECmuPdNTaLw==";
Aes128Decrypt(encodedKey, encodedIV, encodedPayload);
Data after encryption at the JAVA application looks like this
<rson>
<firstName>Rennish</firstName>
<lastName>Joseph</lastName>
<accountNumber>12345678910</accountNumber>
<ssn>123456</ssn>
</person>

Interesting problem.
I think the encryption and decryption works fine on both sides.
If part of the encrypted message was lost in transmission you would not be able to decrypt it due to the avalanche effect. So it appears that characters go missing in the plain text.
This might be an encoding issue in the plain text message. The bytes you have encoded and the bytes they decoded are probably the same. The way they are interpreted might not be.
Now there are two options here:
Either <person> becomes <rson> or it becomes rson> and there was a copy-paste mistake.
If the latter case is true then we're missing 3 bytes. This makes me think that the protocol might presume the presence of a byte order marker andsimply removes the first 3 bytes to get rid of it.
If the former case you'd have some very weird encoding issues. As all missing characters appear to be in the ascii range so they shouldn't have these issues.
Easy to test though:
1. Try sending with a byte order marker.
2. Try sending with <XXperson>
3. Try sending some characters with accents and the like.

Related

C# DESede Symmetric ECB Encryption (I am so close - slightly differing characters)!

My output that I have to match is from Java DESede using a BouncyCastle Jar from 2005 ... I am very close...
Here is my output in Java (which is correct) followed by my output in C# ... if you view in an editor, you will see they ALMOST match, except in C# where it has a forward slash "/" in Java it has "%2F", "%2D" and at the end where C# has is an "=" , Java has "%3D". Any ideas? (I added spaces to show they match up - but you will only see them in an editor.)
F3e8sdZ%2F951IRiguIAVqfDLyWptqlbWik5tvFzItcxJCEmupzD9wXp%2BDzIbrf2J2dPpXyEXL2QU%3D (Java - Correct)
F3e8sdZ/ 951IRiguIAVqfDLyWptqlbWik5tvFzItcxJCEmupzD9wXp+ DzIbrf2J2dPpXyEXL2QU= (C# - Close?)
Here is my C# Code:
public static string DoubleTrippleDESede(string strToEncode, ref string symKey, ref ICryptoTransform cipher)
{
try
{
//byte[] input = Encoding.UTF8.GetBytes("DESede (3DES) Encryption in RAILO CFML");
byte[] input = Encoding.UTF8.GetBytes(strToEncode);
//byte[] key = Convert.FromBase64String("ru8femXhTm9jwdGdhb/4Sw==");
byte[] key = Convert.FromBase64String(symKey);
TripleDESCryptoServiceProvider algorithm = new TripleDESCryptoServiceProvider();
algorithm.Mode = CipherMode.ECB;
algorithm.BlockSize = 64;
algorithm.KeySize = 192; // 24 byte key
algorithm.Key = key; //Original
//algorithm.Key = key.CopyTo(algorithm.Key,)
cipher = algorithm.CreateEncryptor();
byte[] encrypted = cipher.TransformFinalBlock(input, 0, input.Length);
Debug.WriteLine("encrypted (.NET): {0}", Convert.ToBase64String(encrypted));
return Convert.ToBase64String(encrypted);
}
catch (Exception ex)
{
return ex.Message;
}
}
Any guidance would be greatly appreciated!!!! I've been at this for 2 weeks and finally can taste victory (I think!?)
Your Java output appears to have additionally been urlencoded. You should be able to call System.Uri.EscapeDataString() to match your present output.

Cannot open "SecretBox" generated by TweetNacl (Java) with "Libsodium-net" (C#)

I'm having problems opening a Nacl SecretBox (generated in java using the TweetNaclFast library) in C# using the libsodium-net library.
I also can't do it the other way around (open a libsodium-net generated box using TweetNaclFast).
In the following example i'll create a SecretBox using TweetNaclFast (Java) and try to open it with libsodium-net (C#)
Creating the SecretBox (Java)
String secretMessage = "Hello Stack overflow!";
byte[] messageBytes = secretMessage.getBytes("UTF-8");
byte[] keyBytes = secureRandomGenerator(); //returns 32 random bytes (256 bits)
byte[] nonceBytes = TweetNaclFast.makeSecretBoxNonce();
byte[] boxBytes = new TweetNaclFast.SecretBox(keyBytes).box(messageBytes,nonceBytes);
System.out.println("Base64 box -> "+Base64.encodeBase64String(boxBytes));
System.out.println("Base64 key -> "+Base64.encodeBase64String(keyBytes));
System.out.println("Base64 nonce -> "+Base64.encodeBase64String(nonceBytes));
Creation Output
Base64 box -> iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==
Base64 key -> FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=
Base64 nonce -> 2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV
Opening the SecretBox (C#)
string box = "iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==";
string key = "FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=";
string nonce = "2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV";
try
{
byte[] message = Sodium.SecretBox.Open(
Convert.FromBase64String(box),
Convert.FromBase64String(nonce),
Convert.FromBase64String(key));
Console.WriteLine(Encoding.UTF8.GetString(message));
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
Open Output
Failed to open SecretBox
at Sodium.SecretBox.Open(Byte[] cipherText, Byte[] nonce, Byte[] key)
Any idea about what i might be doing wrong?
EDIT
I guess the problem is with one of the libraries (libsodium-net most likely).
If i create a SecretBox with the same variables i get a different box...
Creating a Secret Box with TweetNaclFast
String message = "Hello Stack overflow!";
String key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
String nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";
SecretBox box = new SecretBox(Base64.decodeBase64(key));
byte[] cipherText = box.box(message.getBytes("UTF-8"), Base64.decodeBase64(nonce));
RETURNS: yDCt/kOLFUWPZpV3deVNUZaH0ZHLVmj9Nvm8QlbVKPe1a/INDw==
Creating a Secret Box with libsodium-net
string message = "Hello Stack overflow!";
string key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
string nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";
byte[] box = Sodium.SecretBox.Create(Encoding.UTF8.GetBytes(message),
Convert.FromBase64String(nonce),
Convert.FromBase64String(key));
Console.WriteLine(Convert.ToBase64String(box));
RETURNS: AAAAAAAAAAAAAAAAAAAAAMgwrf5DixVFj2aVd3XlTVGWh9GRy1Zo/Tb5vEJW1Sj3tWvyDQ8=
Sodium.SecretBox.Create uses the original NaCl crypto_box() API, which requires extra padding before the message and the ciphertext.
This API is a bit confusing and is rarely useful except in C. Even in C, people using it end up writing wrappers to prepend or get rid of the padding.
The box and secretbox constructions, as exposed by most APIs, do not require extra padding. The ciphertext is directly returned without 16 extra bytes before. The message can be directly given without prepending 16 nul bytes.
TweetNaclFast does not require any padding, but libsodium-net apparently does.
The extra 16 bytes before the ciphertext you are observing with libsodium-net do not contain any useful information. It's just a bunch of zeros. You can safely strip them, and add them later when calling Sodium.SecretBox.Open.
Note that unlike Sodium.SecretBox, Sodium.PublicKeyBox doesn't require padding.
I should have read the documentation (RTFM)...
Apparently libsodium-net adds a 16byte authentication tag on the start of the ciphertext (https://bitbeans.gitbooks.io/libsodium-net/content/secret-key_cryptography/authenticated_encryption.html). If i remove the first 16 bytes i get the same output as the TweetNaclFast SecretBox.
string message = "Hello Stack overflow!";
string key = "uCEgauAQDWGDkcclGe1rNV6V77xtizuemhgxzM5nqO4=";
string nonce = "+RTDstWX1Wps5/btQzSMHWBqHU9s6iqq";
byte[] box = Sodium.SecretBox.Create(Encoding.UTF8.GetBytes(message),
Convert.FromBase64String(nonce),
Convert.FromBase64String(key));
byte[] boxWithoutAuthenticationTag = new byte[box.Length - 16];
Array.Copy(box, 16, boxWithoutAuthenticationTag, 0, box.Length - 16);
Console.WriteLine(Convert.ToBase64String(boxWithoutAuthenticationTag));
now returns: yDCt/kOLFUWPZpV3deVNUZaH0ZHLVmj9Nvm8QlbVKPe1a/INDw==
To open (decrypt) the first example's secret box use the following code:
string box = "iNEpgwFIo6nyaLNgMpSWqwTQ9Z5y/y+BUXszXVFZ2gP2A3XJ0Q==";
string key = "FKpCo/AhRRUjdQIpzMbZSnnzfBx1e/Ni9VZyNWYEB8E=";
string nonce = "2qngWbMLFVNiPTFqTVO9nsraB8ACIrwV";
try
{
//Libsodium-net SecretBox.Open() requires a 16 byte authentication tag at the start of the ciphertext
//TweetNaclFast boxing method does not append a 16 byte authentication tag anywhere
//Thus, we need to add a 16 byte authentication tag at the start of ciphertext encripted by TweetNaclFast
byte[] authenticationTag = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //Zeroed 16 Bytes Authentication Tag
byte[] tweetNaclFastCiphertextBytes = Convert.FromBase64String(box);
byte[] libsodiumNetLikeCiphertext = new byte[tweetNaclFastCiphertextBytes.Length + authenticationTag.Length];
Array.Copy(authenticationTag, libsodiumNetLikeCiphertext, authenticationTag.Length);
Array.Copy(tweetNaclFastCiphertextBytes, 0, libsodiumNetLikeCiphertext, authenticationTag.Length, tweetNaclFastCiphertextBytes.Length);
byte[] nonceBytes = Convert.FromBase64String(nonce);
byte[] keyBytes = Convert.FromBase64String(key);
Console.WriteLine(Encoding.UTF8.GetString(Sodium.SecretBox.Open(libsodiumNetLikeCiphertext, nonceBytes, keyBytes)));
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
It should now return Hello Stack overflow!

Decrypting AES encrypted string in C#

I am trying to decrypt an AES encrypted string from Java, in C#. When I decrypt, it returns gibberish and does not match the original plain text, which was encrypted via Java code. Pls guide me on what is going wrong here.
Attached the Java code for encryption and the C# code for decryption. Pls let me know if you need more details.
I tried AesCryptoServiceProvider as well and it did not work either. You can see the code tried in the commented code in C#.
Pls note that I can make changes on my C# code only to match the Java code and can not make any edits to Java side.
Java code for Encryption:
/** encrypt cipher */
private static final Cipher ENCRYPT_CIPHER = generateCipher(Cipher.ENCRYPT_MODE);
private static String ENCRYPT_KEY = "key";
/**
* #param val
* #return encrypted value
* #throws Exception
*/
public String encrypt(final String val) throws Exception {
return new String(Base64.encodeBase64(ENCRYPT_CIPHER.doFinal(val.getBytes()), true)).toString();
}
/**
* #param encrypt
* #return cipher
*/
protected static Cipher generateCipher(final int encrypt) {
try {
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(encrypt, SecretKeyFactory.getInstance("AES").generateSecret(new IBMAESKeySpec(Base64.decodeBase64(ENCRYPT_KEY.getBytes()))));
return cipher;
} catch (final Exception e) {
return null;
}
}
C# code for decryption:
private static String ENCRYPT_KEY = "key";
public String decodeString (String encodedStr)
{
/*using (var aesCryptoProvider = new AesCryptoServiceProvider())
{
aesCryptoProvider.BlockSize = 128;
aesCryptoProvider.KeySize = 256;
aesCryptoProvider.Key = Convert.FromBase64String(ENCRYPT_KEY.ToString());
aesCryptoProvider.Padding = PaddingMode.Zeros;
aesCryptoProvider.Mode = CipherMode.ECB;
using (var decryptor = aesCryptoProvider.CreateDecryptor())
using (var memoryStream = new MemoryStream(Convert.FromBase64String(encodedStr)))
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
using (var streamReader = new StreamReader(cryptoStream, Encoding.UTF8))
{
decodedStr = streamReader.ReadToEnd();
}
}
*/
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Convert.FromBase64String(ENCRYPT_KEY.ToString()); ;
aesAlg.BlockSize = 128;
aesAlg.KeySize = 256;
aesAlg.Mode = CipherMode.ECB;
aesAlg.Padding = PaddingMode.Zeros;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor();
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(encodedStr)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
decodedStr = srDecrypt.ReadToEnd();
}
}
}
}
}
This is just a quick answer. Haven't done a ton of research into it, but have you checked to see if the endian-ness matches? It looks like C# (.NET) is little-endian, but the JVM is big-endian. I'm not sure if it swaps it for network transmission, however (then it would just match the hardware). Just an idea. If I find anything additional, I'll update my answer.

Bouncycastle in Java odd encryption and decryption results

So I have been working with the Bouncycastle libraries in an attempt to connect with a remote server. This process has been problematic from the get go and now I'm close to getting everything working but some odd things are happening.
When I first started building out the encryption process I was told to use AES 256 with PKCS7Padding. After some nagging I was provided with a c++ example of the server code. It turned out that the IV is 256 bit so I had to use the RijndaelEngine instead. Also in order for this to work correctly I have to use ZeroBytePadding.
Here is my code:
socket = new Socket(remoteIP, port);
outputStream = new PrintWriter(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
byte[] base_64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes("UTF-8");
Security.addProvider(new BouncyCastleProvider());
public String AESEncrypt(String out) throws IOException, DataLengthException, IllegalStateException, InvalidCipherTextException {
byte[] EncKey = key;
byte randKey;
Random randNumber = new Random();
randKey = base_64[randNumber.nextInt(base_64.length)];
EncKey[randKey&0x1f] = randKey;
RijndaelEngine rijndaelEngine = new RijndaelEngine(256);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine), new ZeroBytePadding());
ParametersWithIV keyParameter = new ParametersWithIV(new KeyParameter(EncKey), iv);
cipher.init(true, keyParameter);
byte[] txt = out.getBytes();
byte[] encoded = new byte[cipher.getOutputSize(txt.length)];
int len = cipher.processBytes(txt, 0, txt.length, encoded, 0);
cipher.doFinal(encoded, len);
char keyChar = (char) randKey;
String encString = new String(Base64.encode(encoded));
encString = encString.substring(0, encString.length()-1) + randKey;
return encString;
}
public void AESDecrypt(String in) throws DataLengthException, IllegalStateException, IOException, InvalidCipherTextException {
byte[] decKey = key;
byte[] msg = in.getBytes();
byte randKey = msg[msg.length-1];
decKey[randKey&0x1f] = randKey;
byte[] trimMsg = new byte[msg.length-1];
System.arraycopy(msg, 0, trimMsg, 0, trimMsg.length);
in = new String(trimMsg);
RijndaelEngine rijndaelEngine = new RijndaelEngine(256);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine), new ZeroBytePadding());
ParametersWithIV keyParameter = new ParametersWithIV(new KeyParameter(decKey), iv);
cipher.init(false, keyParameter);
byte[] encoded = Base64.decode(in.trim());
byte[] decoded = new byte[cipher.getOutputSize(encoded.length)];
int len = cipher.processBytes(encoded, 0, encoded.length, decoded, 0);
cipher.doFinal(decoded, len);
String decString = new String(decoded);
}
Here is a test function I am using to send and receive messages:
public void serverTest() throws DataLengthException, IllegalStateException, InvalidCipherTextException, IOException {
//out = AESEncrypt(out);
outputStream.write(out + "\n");
outputStream.flush();
String msg = "";
while ((msg = inputStream.readLine()) != null) {
AESDecrypt(msg);
}
}
The key and iv don't change with the exception of the last byte in the key. If I am encrypting I get a random base64 char and change the last byte to that. If its decryption I get the last byte from the message and set the last value of the key to it for decryption.
In the c++ example there was an unencrypted message and two encrypted messages. I could deal with those fine.
Here is the problem, when I send my message to the remote server "encrypted" the app waits for a response until the connection times out but never gets one. If I send the message unencrypted I get either 7 responses which I can successfully decrypt and finally
org.bouncycastle.util.encoders.DecoderException: unable to decode base64 string:
String index out of range: -4 at org.bouncycastle.util.encoders.Base64.decode(Unknown Source)
or my last line before the error will look like this:
?"??n?i???el????s???!_S=??ah????CR??l6??]?{?l??Y?????Gn???+?????9!'??gU&4>??{X????G?.$c=??0?5??GP???_Q5????8??Z\?~???<Kr?????[2\ ???a$?C??z%?W???{?.?????eR?j????~?B"$??"z??W;???<?Yu??Y*???Z?K?e!?????f?;O(?Zw0B??g<???????????,)?L>???A"?????<?????W??#\???f%??j ?EhY/?? ?5R?34r???#?1??I??????M
If I set the encryption/decryption to use PKCS7Padding I get no response when my message is encrypted still but with decryption from the server I get between 2 to 6 responses and then
org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
I am at a loss with this. I don't know what I might be doing wrong so I have come here. I'm hoping the so community can point out my errors and guide me in the right direction.
I have a bit of an update I found my error in the encryption. I wasn't placing the random base64 value at the end of the encrypted string correctly so now I am doing like this.
encString += (char)randKey;
I can get response from the server now. Now the problem is I will some times get one or two readable lines but the rest are all garbage. I asked the individuals who run the server about it and they said in some c# code that they reference the have
return UTF8Encoding.UTF8.GetString(resultArray);
and thats all I have to go off of. I have tried UTF-8 encoding any place where I do getBytes or new String, and I have tried making the BurrferReader stream UTF-8 but it's still garbage.
Have you seedn the BCgit? this has bouncycastle code and examples. I am using the Csharp version in this repository. https://github.com/bcgit/bc-java
All crypto primitive examples are stored here: https://github.com/bcgit/bc-java/tree/master/core/src/test/java/org/bouncycastle/crypto/test
Try this code for testing Aes-CBC
private void testNullCBC()
throws InvalidCipherTextException
{
BufferedBlockCipher b = new BufferedBlockCipher(new CBCBlockCipher(new AESEngine()));
KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917"));
b.init(true, new ParametersWithIV(kp, new byte[16]));
byte[] out = new byte[b.getOutputSize(tData.length)];
int len = b.processBytes(tData, 0, tData.length, out, 0);
len += b.doFinal(out, len);
if (!areEqual(outCBC1, out))
{
fail("no match on first nullCBC check");
}
b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f")));
len = b.processBytes(tData, 0, tData.length, out, 0);
len += b.doFinal(out, len);
if (!areEqual(outCBC2, out))
{
fail("no match on second nullCBC check");
}
}

Extra character in decrypted file from java using aes

I have written code in vb.net to encrypt a file from a memory stream. I also decrypt the file as well as copy the memory stream to a file to assure encryption/ decryption works. My vb solution works.
However my need is to decrypt using Java. When I decrypt my file, I always get an extra "?" character at the very beginning of the file, but other than that the resullts are perfect. Has anyone seen anything like this before? I must admit, my results are from using only one set of data, but I've encrypted it twice using new keys and vectors both times.
A few details. I'm using AES, PKCS7 padding in vb, and PKCS5 padding in Java. The file can be of arbitrary length. Any help is appreciated.
I am posting this from my phone, and don't have the code handy. I can add it tomorrow. I'm just hoping that this description rings a bell with someone.
Thanks,
SH
When I wrote to the MemoryStream in VB, I declared a StreamWriter like so:
Writer = New IO.StreamWriter(MS, System.Text.Encoding.UTF8)
Here's my VB.NET encryption function.
Public Shared Function WriteEncryptedFile(ms As MemoryStream, FileName As String) As List(Of Byte())
Try
Dim original() As Byte
Dim myAes As System.Security.Cryptography.Aes = Aes.Create()
myAes.KeySize = 128
myAes.Padding = PadMode
Dim keys As New List(Of Byte())
keys.Add(myAes.Key)
keys.Add(myAes.IV)
original = ms.ToArray
Dim encryptor As ICryptoTransform = myAes.CreateEncryptor(myAes.Key, myAes.IV)
Using FileEncrypt As New FileStream(FileName, FileMode.Create, FileAccess.Write)
Using csEncrypt As New CryptoStream(FileEncrypt, encryptor, CryptoStreamMode.Write)
csEncrypt.Write(original, 0, original.Length)
csEncrypt.FlushFinalBlock()
FileEncrypt.Flush()
FileEncrypt.Close()
csEncrypt.Close()
End Using
End Using
Return keys
Catch e As Exception
MsgBox("Error during encryption." & vbCrLf & e.Message)
End Try
Return Nothing
End Function
And here's the Java decryption:
public static void DecryptLIGGGHTSInputFile(String fileIn, String fileOut, String base64Key, String base64IV) throws Exception
{
// Get the keys from base64 text
byte[] key = Base64.decodeBase64(base64Key);
byte[] iv= Base64.decodeBase64(base64IV);
// Read fileIn into a byte[]
int len = (int)(new File(fileIn).length());
byte[] cipherText = new byte[len];
FileInputStream bs = new FileInputStream(fileIn);
bs.read(cipherText, 1, len-1);
System.out.println(cipherText.length);
System.out.println((double)cipherText.length/128);
bs.close();
// Create an Aes object
// with the specified key and IV.
Cipher cipher = null;
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Encrypt the message.
SecretKey secret = new SecretKeySpec(key, "AES");
/*
cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
cipherText = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
System.out.println(cipherText);
*/
cipher.init(Cipher.DECRYPT_MODE, secret , new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(cipherText), "UTF-8");
System.out.println(plaintext.length());
FileWriter fw = new FileWriter(fileOut);
fw.write(plaintext);
fw.close();
}
It was a BOM problem. When I created the MemoryStream with VB, I initialized it in UTF-8 encoding. The very first character in my file boosted the size and position of the stream from 0 bytes to 4 bytes, when it should have only been one. The solution was to create an encoding based on UTF-8 without Byte Order Marks, like so:
Dim UTF8EncodingWOBOM As New System.Text.UTF8Encoding(False) 'indicates to omit BOM
Writer = New IO.StreamWriter(MS, UTF8EncodingWOBOM)
I read here that there are frequently issues with encoding incompatibilities between platforms due to the presence or lack of byte order mark, as it is neither recommended or required. It's not right to use one, it's not wrong to use one. You basically have to find a way to deal with them. A plethora of other articles and postings suggested different ways to do it. The gist was, either identify them and deal with them if they exist. Since I have control of both the writing and the reading, it makes about as much sense to do away with them entirely.
SH

Categories