.NET TripleDESCryptoServiceProvider equivalent in Java

14,601

Solution 1

Code follows, but first a few notes.

  1. A different initialization vector must be chosen for every message. Hard-coding the initialization vector does not make sense. The IV should be sent along with the cipher text to the message recipient (it's not secret).
  2. I used my own utility class for base-64 encoding. You can use sun.misc.BASE64Encoder and sun.misc.BASE64Decoder instead, use a third-party library like BouncyCastle, or write your own.
  3. You are using 2-key triple DES, where the first key and the third key is the same. I modified sharedkey to reflect this, since the Java DESede cipher always requires a 192-bit key; it's up to the key generator to handle the keying option.
  4. A CBC IV is only 64 bits. I've used only the first 64 bits of sharedvector.

This class should inter-operate with the C# version.

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Encryption
{

  private static byte[] sharedkey = {
    0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11, 
    0x12, 0x11, 0x0D, 0x0B, 0x07, 0x02, 0x04, 0x08, 
    0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11
  };

  private static byte[] sharedvector = {
    0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11
  };

  public static void main(String... argv)
    throws Exception
  {
    String plaintext = "userNameHere:passwordHere";
    String ciphertext = encrypt(plaintext);
    System.out.println(ciphertext);
    System.out.println(decrypt(ciphertext));
  }

  public static String encrypt(String plaintext)
    throws Exception
  {
    Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new IvParameterSpec(sharedvector));
    byte[] encrypted = c.doFinal(plaintext.getBytes("UTF-8"));
    return Base64.encode(encrypted);
  }

  public static String decrypt(String ciphertext)
    throws Exception
  {
    Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new IvParameterSpec(sharedvector));
    byte[] decrypted = c.doFinal(Base64.decode(ciphertext));
    return new String(decrypted, "UTF-8");
  }

}

Output:

zQPZgQHpjxR+41Bc6+2Bvqo7+pQAxBBVN+0V1tRXcOc=

userNameHere:passwordHere

Solution 2

You got a few problems,

  1. Your key must be 24 bytes if you want generate the same key materials on both .NET and Java.
  2. The IV must be block size, which is 8 bytes for Triple DES.
  3. In Java, you need to specify the default mode and padding, which is "DESede/CBC/NoPadding".

Once you make these changes, you should be able to decrypt it on Java side.

Share:
14,601
David Hofmann
Author by

David Hofmann

15 years of coding since high-school and still enjoying it every single day. Oracle Certified Profesional Java Programmer. Certified Vaadin 8 Developer.

Updated on June 04, 2022

Comments

  • David Hofmann
    David Hofmann almost 2 years

    Please, just don't ask me why. I just have this code in .NET that encrypt/decrypt strings of data. I need now to make 'exactly' the same funcionality in java. I have tried several examples for DESede crypt, but none of them gives the same results as this class in .net.

    I even though on making a .net webserbvice behind ssl to serve this two methods writen in .net but it is just too stupid to do without exhausting all the posibilities.

    Maybe some of you java people which are more related in the area will have on top of your heads how to make it.

    Thanks !!!

    public class Encryption
    {
      private static byte[] sharedkey = {...};
      private static byte[] sharedvector = {...};
    
      public static String Decrypt(String val)
      {
        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
        byte[] toDecrypt = Convert.FromBase64String(val);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, tdes.CreateDecryptor( sharedkey, sharedvector ), CryptoStreamMode.Write);
    
        cs.Write(toDecrypt, 0, toDecrypt.Length);
        cs.FlushFinalBlock();
        return Encoding.UTF8.GetString(ms.ToArray());
      }
    
      public static String Encrypt(String val)
      {
        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
        byte[] toEncrypt = Encoding.UTF8.GetBytes(val);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, tdes.CreateEncryptor( sharedkey, sharedvector ), CryptoStreamMode.Write);
        cs.Write(toEncrypt, 0, toEncrypt.Length);
        cs.FlushFinalBlock();
        return Convert.ToBase64String(ms.ToArray());
      }
    }
    

    Samle input/output

    String plain = "userNameHere:passwordHere";
    Console.WriteLine("plain: " + plain);
    
    
    String encrypted = Encrypt(plain);
    Console.WriteLine("encrypted: " + encrypted);
    // "zQPZgQHpjxR+41Bc6+2Bvqo7+pQAxBBVN+0V1tRXcOc="
    
    String decripted = Decrypt(encrypted);
    Console.WriteLine("decripted: " + decripted); 
    // "userNameHere:passwordHere"
    
  • David Hofmann
    David Hofmann over 14 years
    I actually don't remember how many things I've tried, surely I am not even close to the rigth code. So better is someone know how to make it from the scratch
  • Kyle Rosendo
    Kyle Rosendo over 14 years
    Do you not have the Java code? And #2 we'll also need sample in and out from the Java code.
  • brady
    brady over 14 years
    But can you encrypt his plaintext? The SunJCE will reject any input that isn't a multiple of 8 bytes.
  • David Hofmann
    David Hofmann over 14 years
    Wow ! I've 'no idea' of what you are talking about :D But it works. I promise to have a read on the subject for a good understanding of encryption algorithms. THANKS AGAIN !!!
  • ZZ Coder
    ZZ Coder over 14 years
    In JCE term, NoPaddding is equivalent to the zero-padding. In CBC mode, it will get padded to the blocksize. Say you have 3 extra bytes after paddding. NoPadding will fill it with "00 00 00". PKCS5 will have "03 03 03". When testing decrypting, I always use NoPadding first, it always works. Then you can figure out what padding is.