【问题标题】:.NET TripleDESCryptoServiceProvider equivalent in JavaJava 中的 .NET TripleDESCryptoServiceProvider 等效项
【发布时间】:2009-09-10 06:54:58
【问题描述】:

请不要问我为什么。我只是在 .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());
  }
}

样本输入/输出

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"

【问题讨论】:

  • 这是可行的。提供一些测试输入和输出。
  • 我添加了示例输入/输出,谢谢!!

标签: c# java .net encryption 3des


【解决方案1】:

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

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

此类应与 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

【讨论】:

  • 哇!我“不知道”你在说什么 :D 但它有效。我保证阅读该主题以更好地理解加密算法。再次感谢!!!
【解决方案2】:

你遇到了一些问题,

  1. 如果您想在 .NET 和 Java 上生成相同的密钥材料,您的密钥必须是 24 字节。
  2. IV 必须是块大小,对于三重 DES,它是 8 个字节。
  3. 在 Java 中,您需要指定默认模式和填充,即“DESede/CBC/NoPadding”。

完成这些更改后,您应该能够在 Java 端对其进行解密。

【讨论】:

  • 但是你能加密他的明文吗? SunJCE 将拒绝任何不是 8 字节倍数的输入。
  • 在 JCE 术语中,NoPaddding 相当于零填充。在 CBC 模式下,它将被填充到块大小。假设您在填充后有 3 个额外的字节。 NoPadding 将用“00 00 00”填充它。 PKCS5 将具有“03 03 03”。在测试解密时,我总是先使用 NoPadding,它总是有效的。然后你可以弄清楚什么是填充。
【解决方案3】:

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

你有没有Java代码的来源,它会帮助发现错误。

【讨论】:

  • 我实际上不记得我尝试了多少东西,当然我什至没有接近正确的代码。所以更好的是有人知道如何从头开始制作它
  • 你没有Java代码吗? #2 我们还需要从 Java 代码中进出样本。
【解决方案4】:

试试下面的。对于实际使用,我会得到一个 base64 库,比如 commons 编解码器或使用 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)));
    }

}

【讨论】:

    猜你喜欢
    • 2017-10-03
    • 1970-01-01
    • 1970-01-01
    • 2016-04-16
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2023-03-23
    • 1970-01-01
    相关资源
    最近更新 更多