Java TripleDESCryptoServiceProvider等效于Java

时间:2009-09-09 16:54:37

标签: c# java .net encryption 3des

拜托,请不要问我为什么。我只是在.NET中使用此代码来加密/解密数据字符串。我现在需要在java中制作“完全”相同的功能。我已经为DESede crypt尝试了几个例子,但它们都没有给出与.net中这个类相同的结果。

我甚至在ssl后面创建一个.net webserbvice来服务于.net写的这两种方法但是如果不用尽所有的可能性就太愚蠢了。

也许你们中的一些在这个领域更有相关性的java人将会有如何做到这一点。

谢谢!!!

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输入/输出

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"

4 个答案:

答案 0 :(得分:7)

代码如下,但首先是一些注释。

  1. 必须为每条消息选择不同的初始化向量。硬编码初始化向量没有意义。 IV应与密文一起发送给消息接收者(这不是秘密)。
  2. 我使用自己的实用程序类进行base-64编码。您可以使用sun.misc.BASE64Encodersun.misc.BASE64Decoder代替,使用像BouncyCastle这样的第三方库,也可以自己编写。
  3. 您正在使用双键三重DES,其中第一个键和第三个键相同。我修改了sharedkey来反映这一点,因为Java DESede密码总是需要192位密钥;由键生成器来处理键控选项。
  4. CBC IV仅为64位。我只使用了sharedvector的前64位。
  5. 此类应与C#版本互操作。

    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");
      }
    
    }
    

    输出:

      

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

         

    userNameHere:passwordHere

答案 1 :(得分:2)

你遇到了一些问题,

  1. 如果要在.NET和Java上生成相同的密钥材料,则密钥必须为24个字节。
  2. IV必须是块大小,对于Triple DES来说是8个字节。
  3. 在Java中,您需要指定默认模式和填充,即“DESede / CBC / NoPadding”。
  4. 进行这些更改后,您应该能够在Java端解密它。

答案 2 :(得分:0)

您是否确定.NET代码使用与Java代码相同的填充?我看到.NET代码中没有指定填充,这就是我问的原因。

您是否碰巧拥有Java代码的来源,这将有助于发现错误。

答案 3 :(得分:0)

尝试以下方法。对于实际使用,我会得到一个像commons编解码器一样的base64库,或者使用BouncyCastle附带的编解码器

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

public class Encryption {

    private static SecretKey sharedkey;
    private static byte [] sharedvector;

    static {
        int keySize = 168;
        int ivSize = 8;
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            keyGenerator.init(keySize);
            sharedkey = keyGenerator.generateKey();

            sharedvector = new byte [ivSize];
            byte [] data = sharedkey.getEncoded();

            int half = ivSize / 2;
            System.arraycopy(data, data.length-half, sharedvector, 0, half);
            System.arraycopy(sharedvector, 0, sharedvector, half, half);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static void main(String [] args) throws Exception {
        System.out.println(Decrypt(Encrypt("Hello World")));

    }

    public static String Encrypt(String val) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));

        return new sun.misc.BASE64Encoder().encode(cipher.doFinal(val.getBytes()));
    }

    public static String Decrypt(String val) throws GeneralSecurityException, IOException {
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));

        return new String(cipher.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(val)));
    }

}