Reputation: 379
I have a following code in C#. It does encoding an array of bytes with an AES symmetric algorithm. I need to write Java equivalent of this code.
class Program
{
static void Main(string[] args)
{
string a = "ABCDEFGHIJKLMNOP";
byte[] bytes = Encoding.ASCII.GetBytes(a);
byte[] cipher = encode(bytes, "1111111122222222111111112222222211111111222222221111111122222222", "66666666555555556666666655555555");
}
private static byte[] encode(byte[] toEncrypt, string sKey, string sIV)
{
byte[] IV = new byte[16];
byte[] key = new byte[32];
byte[] array = new byte[toEncrypt.Length];
string s;
for (int i = 0; i < IV.Length; ++i)
{
s = sIV.Substring(i * 2, 2);
IV[i] = Convert.ToByte(s, 16);
}
for (int i = 0; i < key.Length; ++i)
{
s = sKey.Substring(i * 2, 2);
key[i] = Convert.ToByte(s, 16);
}
MemoryStream filecrypt = new MemoryStream(array);
AesManaged encrypt = new AesManaged();
encrypt.Mode = CipherMode.CBC;
encrypt.Padding = PaddingMode.None;
encrypt.BlockSize = 128;
encrypt.KeySize = 256;
CryptoStream cs = new CryptoStream(filecrypt, encrypt.CreateEncryptor(key, IV), CryptoStreamMode.Write);
cs.Write(toEncrypt, 0, toEncrypt.Length);
cs.Close();
return array;
}
}
This is my attempt of writing this in Java. The code looks fine, but the output is different, something must be wrong.
public class Main {
public static void main(String [] args) {
byte [] code = encode("ABCDEFGHIJKLMNOP".getBytes(), "1111111122222222111111112222222211111111222222221111111122222222", "66666666555555556666666655555555");
}
private static byte[] toByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
int a;
int b;
for (int i = 0; i < len; i += 2) {
a = (Character.digit(s.charAt(i), 16) << 4);
b = Character.digit(s.charAt(i+1), 16);
int n = (Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16);
data[i / 2] = (byte) (n);
}
return data;
}
private static byte[] encode(byte[] toEncrypt, String skey, String siv)
{
byte[] key = toByteArray(skey);
byte[] iv = toByteArray(siv);
byte[] array = new byte[toEncrypt.length];
Cipher cipher;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
array = cipher.doFinal(array);
} catch (Exception ex) {
ex.printStackTrace();
}
return array;
}
}
Any clues and ideas will be very appreciated.
Upvotes: 6
Views: 5819
Reputation: 92
public String notify(String message, String encryptionKey) {
Security.addProvider(new BouncyCastleProvider());
// System.out.println(message);
byte[] key = Base64.decode(encryptionKey);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
byte[] data = Base64.decode(message);
String decryptedString = "";
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(data);
decryptedString = new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(decryptedString);
return decryptedString;
}
This code should decrypt the encrypted message adding the required padding - default 128bit and you shall need to provide encryption key though. However this is my C# version of the same code
void DecryptMessage(string message)
{
var deserializedMessage = JsonConvert.DeserializeObject<List<string>>(message.ToString());
byte[] decodedEncryptionKey = Convert.FromBase64String(encryptkey);
byte[] data = Convert.FromBase64String(deserializedMessage[0]);
byte[] iv = new byte[16];
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
using (ICryptoTransform decrypt = aes.CreateDecryptor(decodedEncryptionKey, iv))
{
byte[] dest = decrypt.TransformFinalBlock(data, 0, data.Length);
decrypt.Dispose();
Console.WriteLine(Encoding.UTF8.GetString(dest));
}
}
Upvotes: 0
Reputation: 210
I don't know C# pretty well but in general you want multiple consecutive encryption results to be different. This is why you specify an initial IV for the AES algorithm. An encryption code could look like the following:
public String encrypt( String stringToEncrypt, IvParameterSpec ivSpec ) {
if ( stringToEncrypt == null ) {
return null;
}
try {
Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec( key, "AES" );
cipher.init( Cipher.ENCRYPT_MODE, keySpec, ivSpec );
byte[] data = cipher.doFinal( stringToEncrypt.getBytes( "UTF-8" ) );
return String.format( "%s:%s", Base64.encode( ivSpec.getIV() ), Base64.encode( data ) );
} catch ( Exception e ) {
throw new RuntimeException( "Unable to encrypt the string", e );
}
}
Your key and your IV should be generated using SecureRandom as this provides the best entropy in java:
byte[] iv = new byte[32];
random.nextBytes( iv );
byte[] key = new byte[32];
random.nextBytes( key );
Furthermore, you might want to calculate an HMAC afterwards - java also supports multiple solutions here. By checking the HMAC on the receiver side you can prevent a padding oracle attack.
To compare different encryption results I would compare them base64 encoded.
Note: It is ok to save the IV next to the ciphertext - it is just there to protect against pre computation attacks.
Upvotes: 4
Reputation: 61902
You're initializing byte[] array = new byte[toEncrypt.length];
for some reason, but you never write the contents of toEncrypt
into it before encryption. You could use System.arraycopy(toEncrypt, 0, array, 0, array.length);
, but it would be easier to just use
byte[] array;
...
array = cipher.doFinal(toEncrypt);
...
return array;
Upvotes: 2
Reputation: 17574
Personally, if your objective is to simply get AES encryption with Java you should not base your code on a C# class. Sure they may be similar, but Java has strong libraries for that already.
With that aside, I wish I had my encryption book here to explain it to you, but unfortunately the best i can do now is only to provide you with a good examples that someone else tried:
I hope these links help you achieve your objective.
Also, regarding your specific c# code, I fail to see where you are specifying the following code in Java:
encrypt.BlockSize = 128;
encrypt.KeySize = 256;
In the second tutorial I suggest you have an example where they specify the key size. I Hope I helped!
Upvotes: 0