3DES - Decrypt encrypted text (by JAVA) in C# - java

Here is the situation:
The encrypted text is done in JAVA (which we have no JAVA background at all)
The method is 3DES
The padded is PKCS#5
Base 64
The decryption will be in C#, and here is the code:
public static string DecryptString(string Message, string Passphrase)
{
byte[] Results;
UTF8Encoding UTF8 = new UTF8Encoding();
MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
byte[] DataToDecrypt = Convert.FromBase64String(Message);
try
{
ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
}
finally
{
TDESAlgorithm.Clear();
HashProvider.Clear();
}
return UTF8.GetString(Results);
}
However, when tried to decrypt, got the error message: BAD DATA
Where am I missing here?
Thanks in advance.
Added, and here's how the encryption works:
<cffunction name="getToken" returntype="String" output="false">
<cfscript>
plainText = getPlainText();
rawSecretKey = CreateObject("java","sun.misc.BASE64Decoder").decodeBuffer(variables.encryptionKey);
secretKeySpec = CreateObject("java","javax.crypto.spec.SecretKeySpec").init(rawSecretKey,"DESEDE");
cipher = CreateObject("java","javax.crypto.Cipher").getInstance("DESEDE");
cipher.init(Cipher.ENCRYPT_MODE, secretkeySpec);
encrypted = cipher.doFinal(plainText.getBytes()); // a byte array (a binary in CF)
return URLEncodedFormat(ToString(ToBase64(encrypted)));
</cfscript>
</cffunction>
Update:
This issue has been resolved. The problem was that the key needed to be converted from Base64.

The answer:
Instead of:
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
Do this:
byte[] TDESKey = Convert.FromBase64String(Passphrase);
That solves this issue.

Related

Encrypting Java then Decrypting C# AES256 Encryption with HMACSHA256, Padding is invalid

I'm currently running into an issue where our decryption portion of our C# site is having trouble with the padding with the encrypted string from java. The .Net code throws this error "Padding is invalid and cannot be removed". The _signKey and _encKey are both 64 bytes.
public String encryptString(String plainText) {
byte[] ciphertext;
byte[] iv = new byte[16];
byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
String _signKey = "****************************************************************";
String _encKey = "****************************************************************";
try {
Mac sha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec shaKS = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256.init(shaKS);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
// Perform Encryption
SecretKeySpec eks = new SecretKeySpec(sessionKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, eks, ivParams);
ciphertext = cipher.doFinal(plainBytes);
System.out.println("ciphertext= " + new String(ciphertext));
// Perform HMAC using SHA-256 on ciphertext
SecretKeySpec hks = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(hks);
ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
outputStream2.write(iv);
outputStream2.write(ciphertext);
outputStream2.flush();
outputStream2.write(mac.doFinal(outputStream2.toByteArray()));
return Base64.encodeBase64String(outputStream2.toByteArray());
} catch (Exception e) {
e.printStackTrace();
}
return plainText;
}
Does does encrypt the string properly as far as I can tell. We cannot change any code on the .Net side to decrypt this because this is being used today.
public static string DecryptString(string ciphertext)
{
using (HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_signKey)))
{
// Convert message to bytes
byte[] encBytes = Convert.FromBase64String(ciphertext);
// Get arrays for comparing HMAC tags
byte[] sentTag = new byte[sha256.HashSize / 8];
byte[] calcTag = sha256.ComputeHash(encBytes, 0, (encBytes.Length - sentTag.Length));
// If message length is too small return null
if (encBytes.Length < sentTag.Length + _ivLength) { return null; }
// Copy tag from end of encrypted message
Array.Copy(encBytes, (encBytes.Length - sentTag.Length), sentTag, 0, sentTag.Length);
// Compare tags with constant time comparison, return null if no match
int compare = 0;
for (int i = 0; i < sentTag.Length; i++) { compare |= sentTag[i] ^ calcTag[i]; }
if (compare != 0) { return null; }
using (AesCryptoServiceProvider csp = new AesCryptoServiceProvider())
{
// Set parameters
csp.BlockSize = _blockBits;
csp.KeySize = _keyBits;
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
// Copy init vector from message
var iv = new byte[_ivLength];
Array.Copy(encBytes, 0, iv, 0, iv.Length);
// Derive session key
byte[] sessionKey = sha256.ComputeHash(Encoding.UTF8.GetBytes(_encKey + iv));
// Decrypt message
using (ICryptoTransform decrypt = csp.CreateDecryptor(sessionKey, iv))
{
return Encoding.UTF8.GetString(decrypt.TransformFinalBlock(encBytes, iv.Length, encBytes.Length - iv.Length - sentTag.Length));
}
}
}
}
If there is anything that sticks out it would be appreciated for the reply.
I didn't read all your code, but this line in Java:
byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
does nothing useful or sensible. The "+" operator does string concatenation, but iv is a byte[], not a String. So java uses iv.toString(), which simply returns a String containing something like [B#1188e820 which is meaningless in this context.
Refer four java code and DotNet code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Java
csp.Padding = PaddingMode.PKCS7; //.Net
You are essentially using different padding, that is the probable source of error; however, there is an alternate view, Refer this great post and this for general fundamentals on padding
The cipher suites supported by deafult Oracle JVM implementation are here
If you notice it does not have 'AES/CBC/PKCS7Padding', a PKCS#7 padding implementation is available in sun.security package, refer this, otherwise you could use Bouncy Castle packages. It would be recommendable to use Bouncy Castle as com.sun package are generally considered unsupported.

How to decrypt a cipher text using Java which is encrypted with Rijndael-256 with custom IV?

I have found a source code at stackoverflow on Rinjndael-256 encryption and decryption written in c#. It is using custom IV appending some extra string. Now I need a decryption method on Java platform. I have found some source code; tried to change and test that. Here is the encryption method on c#:
public static string Encrypt(byte[] text, string key)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Padding = PaddingMode.None;
aes.Mode = CipherMode.CBC;
aes.Key = Encoding.Default.GetBytes(key);
aes.GenerateIV();
string IV = ("-[--IV-[-" + Encoding.Default.GetString(aes.IV));
ICryptoTransform AESEncrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] buffer = text;
return Convert.ToBase64String(Encoding.Default.GetBytes(Encoding.Default.GetString(AESEncrypt.TransformFinalBlock(buffer, 0, buffer.Length)) + IV));
}
The decryption method on java which is not working for me is:
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
}
Edit 1:
I have implemented the php code for decryption.
function decrypt($text, $pkey)
{
$key = $pkey;
$text = base64_decode($text);
$IV = substr($text, strrpos($text, "-[--IV-[-") + 9);
$text = str_replace("-[--IV-[-" . $IV, "", $text);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $IV), "\0");
}
Is there any manual way of implementing Rijndael-256 in Java? As someone said that
There is no support in any of the Sun JCE providers for anything other than Rijndael with the 128-bit blocksize
I don't have an option to use library

convert php mcrypt_encrypt MCRYPT_3DES to Java

I have code in PHP
$res = strtoupper(bin2hex(mcrypt_encrypt(MCRYPT_3DES, $this->hex2str($key), $this->hex2str($data), MCRYPT_MODE_ECB)));
public function hex2str($data) {
$len = strlen($data);
$res = pack("H" . $len, $data);
return $res;
}
I try to create in java version.
Java code :
private String doEncrypt3DES(String key, String data) throws Exception{
SecretKey secretKey;
byte[] keyValue;
Cipher c;
keyValue = Hex.decodeHex(key.toCharArray());
DESedeKeySpec keySpec = new DESedeKeySpec(keyValue);
secretKey = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
// Create the cipher
c = Cipher.getInstance("DESede/ECB/NoPadding");
c.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] text = data.getBytes("utf-8"); // Base64.decodeBase64(data);
byte[] textEncrypt = c.doFinal(text);
String hex = bytesToHex(textEncrypt);
return hex;
}
But they got different result. Can you help me to fix java code?
data : CED0CF172E8AC451B39FC746C5339F29
key : 436C6561724B657944657632536E724D436C6561724B6579
Use hex decode and not utf-8 decode to data.

Testing HmacSHA256 signature

I'm testing my Hmac with test vectors from https://www.rfc-editor.org/rfc/rfc4231
But on test case 3 "Test with a combined length of key and data that is larger than 64 bytes (= block-size of SHA-224 and SHA-256)." I get a different digest than the correct one.
byte[] key = hexify("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
byte[] data = hexify("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
byte[] correct = hexify("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe");
// Create digest
SecretKey macKey = new SecretKeySpec(key, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(macKey);
byte[] digest = mac.doFinal(data);
Any idea why they become different? What did I miss? I'm very new to this.
// Hex encoded
a5418172bb54bf71f3ec28d1c9f34c48da17007eac4d0ca9e2f8ab54b91603e8
773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe
I can't reproduce your issue. For me, the following SSCCE works just fine:
public static void main(String[] args) throws Exception {
byte[] key = hexify("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
byte[] data = hexify("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
byte[] correct = hexify("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe");
// Create digest
SecretKey macKey = new SecretKeySpec(key, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(macKey);
byte[] digest = mac.doFinal(data);
System.out.println(Arrays.equals(correct, digest));
}
private static byte[] hexify(String string) {
return DatatypeConverter.parseHexBinary(string);
}
Prints: true
Perhaps an error in your display or comparison code?

Equivalent to CryptoStream .NET in Java?

I have an encrypted string in visual basic. NET 2008, the functions to encrypt and decrypt are the following:
Imports System.Security.Cryptography
Public Shared Function Encriptar(ByVal strValor As String) As String
Dim strEncrKey As String = "key12345"
Dim byKey() As Byte = {}
Dim IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
Try
byKey = System.Text.Encoding.UTF8.GetBytes(strEncrKey)
Dim des As New DESCryptoServiceProvider
Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(strValor)
Dim ms As New MemoryStream
Dim cs As New CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
Return Convert.ToBase64String(ms.ToArray())
Catch ex As Exception
Return ""
End Try
End Function
Public Shared Function Desencriptar(ByVal strValor As String) As String
Dim sDecrKey As String = "key12345"
Dim byKey() As Byte = {}
Dim IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
Dim inputByteArray(strValor.Length) As Byte
Try
byKey = System.Text.Encoding.UTF8.GetBytes(sDecrKey)
Dim des As New DESCryptoServiceProvider
If Trim(strValor).Length = 0 Then
Throw New Exception("Password No debe estar en Blanco")
End If
inputByteArray = Convert.FromBase64String(strValor)
Dim ms As New MemoryStream
Dim cs As New CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
Return encoding.GetString(ms.ToArray(), 0, ms.ToArray.Count)
Catch ex As Exception
Return ""
End Try
End Function
for example the word "android" encrypted with this function gives me the result "B3xogi/Qfsc="
now I need to decrypt the string "B3xogi/Qfsc=" it from java, by the same key, which is "key12345", and the result should be "android"...anyone know how to do this?
Thanks in advance.
Using Apache Commons Codec for hex and base64 encoding/decoding, you can use the following code:
KeySpec ks = new DESKeySpec("key12345".getBytes("UTF-8"));
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(ks);
IvParameterSpec iv = new IvParameterSpec(
Hex.decodeHex("1234567890ABCDEF".toCharArray()));
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decoded = cipher.doFinal(Base64.decodeBase64("B3xogi/Qfsc="));
System.out.println("Decoded: " + new String(decoded, "UTF-8"));
You're using DES encryption.
Here is an example on how to encrypt and decrypt with DES.
The main point is to create a SecretKey, a Cipher using it, and decrypt your String with it.
Mmmh...
I found another article that may best suit your question, because it uses IVBytes :)
public String encryptText(String cipherText) throws Exception {
String plainKey = "key12345";
String plainIV = "1234567890ABCDEF";
KeySpec ks = new DESKeySpec(plainKey.getBytes(encodingType));
SecretKey key = SecretKeyFactory.getInstance(keyDes).generateSecret(ks);
IvParameterSpec iv = new IvParameterSpec(
org.apache.commons.codec.binary.Hex.decodeHex(plainIV.toCharArray()));
Cipher cipher = Cipher.getInstance(encryptAlgo);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] decoded = cipher.doFinal(cipherText.getBytes(encodingType));
return new Base64().encodeToString(decoded);
}
The closest Java classes to .NET's CryptoStream class are the CipherInputStream and CipherOutputStream classes.

Categories