One problem that I have had to solve in the past was making encryption between Java and .NET possible. Specifically, I was charged to read an encrypted query string parameter from a Java system in my ASP.NET application. After a few iterations of incompatible implementations, I created an implementation in both .NET (c#) and Java to ensure compatibility.
Since this caused me so much pain, I thought I would share my implementation with you in hopes that it will work for you as well.
Let me know if you have any questions or want to provide a decrypt implementation for the java class.
.NET (C#) Implementation
/// <summary>
/// Encryption utility class that implements Triple DES algorithm
/// </summary>
public class TripleDESImplementation
{
//Encryption Key
private byte[] EncryptionKey { get; set; }
// The Initialization Vector for the DES encryption routine
private byte[] IV { get; set; }
/// <summary>
/// Constructor for TripleDESImplementation class
/// </summary>
/// <param name="encryptionKey">The 24-byte encryption key (24 character ASCII)</param>
/// <param name="IV">The 8-byte DES encryption initialization vector (8 characters ASCII)</param>
public TripleDESImplementation(string encryptionKey, string IV)
{
if (string.IsNullOrEmpty(encryptionKey))
{
throw new ArgumentNullException("'encryptionKey' parameter cannot be null.", "encryptionKey");
}
if (string.IsNullOrEmpty(IV))
{
throw new ArgumentException("'IV' parameter cannot be null or empty.", "IV");
}
EncryptionKey = Encoding.ASCII.GetBytes(encryptionKey);
// Ensures length of 24 for encryption key
Trace.Assert(EncryptionKey.Length == 24, "Encryption key must be exactly 24 characters of ASCII text (24 bytes)");
this.IV = Encoding.ASCII.GetBytes(IV);
// Ensures length of 8 for init. vector
Trace.Assert(IV.Length == 8, "Init. vector must be exactly 8 characters of ASCII text (8 bytes)");
}
/// <summary>
/// Encrypts a text block
/// </summary>
public string Encrypt(string textToEncrypt)
{
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = EncryptionKey;
tdes.IV = IV;
byte[] buffer = Encoding.ASCII.GetBytes(textToEncrypt);
return Convert.ToBase64String(tdes.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));
}
/// <summary>
/// Decrypts an encrypted text block
/// </summary>
public string Decrypt(string textToDecrypt)
{
byte[] buffer = Convert.FromBase64String(textToDecrypt);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Key = EncryptionKey;
des.IV = IV;
return Encoding.ASCII.GetString(des.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length));
}
}
Java Implementation
public class TripleDesImplementation {
private String key;
private String initializationVector;
public TripleDesImplementation(String key, String initializationVector)
{
this.key = key;
this.initializationVector = initializationVector;
}
public String encryptText(String plainText) throws Exception{
//---- Use specified 3DES key and IV from other source --------------
byte[] plaintext = plainText.getBytes();
byte[] tdesKeyData = key.getBytes();
byte[] myIV = initializationVector.getBytes();
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(myIV);
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
return Base64Coder.encodeString(new String(cipherText));
}
}
11 comments:
Hey great info, I am also dealing with this problem, but I am doing it from C# Desktop application to a Java servlet, so I need to decrypt on the Java side, I tried to replicate the C# code for decrypt in Java but I only get a 40% of the message decrypted fine, any idea?
For example I sent this as the text to encrypt "_2G4WS52M6W1459365" and I get this "_2G4WS52J���iS�5_2G4WS52J���iS�5"
From first glance, it looks like an encoding issue, but I'd have to see your code to make a better guess.
Hi Sam, I've tried your code and it seems to work excepted when you get an encryted text from java wi th at least one "/" . The C# method can't decrypt the message.Have you already face to this problem ?
Sorry, in fact it's not due to to the "/"
I tried to encrypt this random string "AeRTYhgFD678de4" with these key "4d89g13j4j91j27c582ji693" and iv "zerocool".
In Java i got : cANU9X90FvhHP5wH3t9VMQ==
In C# I got:cANU9X90FvhHgZwH3t9VMQ==
So I can't decrypt the encrypted text from java.
Yann, I haven't experienced this problem before, but I'll take a look. In the mean time, if you end up figuring out the solution, make sure you post it. Thanks!
Sam
When I found this post I got excited, because this is precisely the problem I'm trying to solve, except the other direction. Here is the .NET code I want to convert to java:
Decryptor dec = new Decryptor(EncryptionAlgorithm.TripleDes);
dec.IV = Encoding.ASCII.GetBytes(ssIV);
byte[] key = Encoding.ASCII.GetBytes(ssKEY);
byte[] plainText = dec.Decrypt(Convert.FromBase64String(encryptedCCNumber), key);
return Encoding.ASCII.GetString(plainText);
The issue is that the key is 16 characters, and that is an illegal length for the java decryption. Am I using the wrong algorithm on the java side?
cawineguy, I'm afraid I'm not much of a java expert, so I'm afraid I can't tell you what's going on right off the bat. I'll take a look at it and get back to you if I find anything.
Sam - thanks, I found it in the article you originally referenced. The problem is that Java requires a 24 byte key; so I needed to take the 16 byte password, and pad with the first 8 bytes of the password. now it works like a champ!
So Many Thank Thank Thank.
Very good topic
Sam,
THANK YOU VERY MUCH!!! This is 75% of what I have been looking high and low for. Can you please post the Java Decryptor function for the remaining 25% of the functionality I need??? I am not a java developer, so am having a hard time with this.
Thanks a lot for this great post...
have modified the java code somewhat, but it works fine for me, I encrypting the string in .net and decrypting it on java... hope it'll be helpful for you.
package com.bay.bizlogic;
/**
* Created by Nitin Gaur.
* User: admin
* Date: 4 Feb, 2010
* Time: 12:46:23 PM
* To change this template use File | Settings | File Templates.
*/
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class TripleDES {
private String key;
private String initializationVector;
public TripleDES(String key, String initializationVector)
{
this.key = key;
this.initializationVector = initializationVector;
}
public String encryptText(String plainText) throws Exception{
//---- Use specified 3DES key and IV from other source --------------
byte[] plaintext = plainText.getBytes();
byte[] tdesKeyData = key.getBytes();
// byte[] myIV = initializationVector.getBytes();
Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(initializationVector.getBytes());
c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
byte[] cipherText = c3des.doFinal(plaintext);
return new sun.misc.BASE64Encoder().encode(cipherText);
}
public String decryptText(String cipherText)throws Exception{
byte[] encData = new sun.misc.BASE64Decoder().decodeBuffer(cipherText);
Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
byte[] tdesKeyData = key.getBytes();
SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
IvParameterSpec ivspec = new IvParameterSpec(initializationVector.getBytes());
decipher.init(Cipher.DECRYPT_MODE, myKey, ivspec);
byte[] plainText = decipher.doFinal(encData);
return new String(plainText);
}
}
Thanks...
India
Post a Comment