TripleDES加密在Java中工作正常,但在C#中却不能

时间:2019-01-31 12:20:55

标签: java c# algorithm encryption

我在执行三重DES加密时遇到密钥错误。代码在Java中工作正常,但在C#.net中给出了错误。

我有可以在TripleDES加密中正常工作的Java代码,我需要在c#中转换我的java代码。我在转换过程中面临弱密钥错误。在给出的java和c#代码下面。

1)Java代码

post_install do |installer|
  installer.pods_project.targets.each do |target|
    setup_all_swift_versions(target, my_project_pods_swift_versions)
  end
end

2)C#代码

public class TripleDES {
    private DESedeKeySpec desKeySpec;

    public TripleDES(String key) {
        try {
            byte[] keyBytes = { (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02};



            this.desKeySpec = new DESedeKeySpec(keyBytes);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public byte[] encrypt(byte[] origData) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            SecretKey key = factory.generateSecret(this.desKeySpec);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(origData);
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] decrypt(byte[] crypted) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            SecretKey key = factory.generateSecret(this.desKeySpec);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");  //DESede/CBC/PKCS5Padding
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(crypted);
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) throws Exception {
        TripleDES des = new TripleDES("");

      byte[] data = { (byte)0x04, (byte)0x12, (byte)0x05, (byte)0xFF, (byte)0xFB, (byte)0xA6, (byte)0x66, (byte)0xCF};
      //byte[] data = { (byte)0x04, (byte)0x12, (byte)0x15, (byte)0xAF, (byte)0xFD, (byte)0xD8, (byte)0x88, (byte)0xBB};  


//-----------------Edited-----------------
String text = new BigInteger(1, data).toString(16);
System.out.println("Before encryption = " +text);             
    byte[] crypted = des.encrypt(data);
String text1 = new BigInteger(1, crypted).toString(16);
    System.out.println("Encrypted = " +text1);
byte[] decrypted = des.decrypt(crypted);
String text2 = new BigInteger(1, decrypted).toString(16);
    System.out.println("Decrypted = " +text2);
    }

}

键:020202020202020202020202020202020202

数据:041205FFFBA666CF

结果:A334C92CEC163D9F

任何人都可以用c#编写产生与Java相同结果的代码。

2 个答案:

答案 0 :(得分:0)

在我开始之前,我想说我不推荐或支持您遵循这种方式,以迫使TripleDES使用它认为较弱的密钥,但是,考虑到您正在使用它,仅用于解密,这是一种使用反射的方法。

首先,您必须“强制” TripeDES类以使用您要使用的弱键。为此,我们使用反射来绕过对尝试设置键(alg.Key = key并直接设置成员变量时执行的弱键的检查:

//alg.Key = key; - THIS IS REPLACED BY THE BELOW
FieldInfo keyField = alg.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
keyField.SetValue(alg, key);

TripleDES的键值现在将设置为您的弱键(alg.Key);

接下来,您有一个小错误,因为您忘记了关闭填充:

alg.Mode = CipherMode.ECB;
alg.Padding = PaddingMode.None; // Add this, as the default padding is PKCS7

最后,在创建解密器时将进一步检查弱密钥,因此我们必须再次使用Reflection绕过该检查并创建ICryptoTransform:

// Comment out the below line and use the code below
// CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
ICryptoTransform Decryptor;
MethodInfo createMethod = alg.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
Decryptor = createMethod.Invoke(alg, new object[] { alg.Key, alg.Mode, alg.IV, alg.FeedbackSize, 1 }) as ICryptoTransform;
CryptoStream cs = new CryptoStream(ms, Decryptor, CryptoStreamMode.Write);

代码现在将运行并接受弱密钥,并执行您要查找的解密。

但是,在我看来输出并没有达到您的期望:

?Data
"4aU3DcHkiCTEywpiewWIow=="

至少现在可以使用TripleDES来使用任何键。

答案 1 :(得分:0)

3DES密钥是一个24字节的值,该值分为两个三个8字节的值:key0key1key2

由于任何时候key1等于key2key0时,3DES都是DES_Encrypt(key2,DES_Decrypt(key1,DES_Encrypt(key0,data)))),因此算法被简化为DES。这就是.NET的TripleDES向您警告的内容。

此处的正确测试应考虑清除(或设置或固定)每个字节中的奇偶校验位,但是手动操作的版本是:

SymmetricAlgorithm alg;
IEnumerable<byte> key0 = key.Take(8);
IEnumerable<byte> key1 = key.Skip(8).Take(8);
IEnumerable<byte> key2 = key.Skip(16);

if (key0.SequenceEquals(key1))
{
    alg = DES.Create();
    alg.Key = key2.ToArray();
}
else if (key1.SequenceEquals(key2))
{
    alg = DES.Create();
    alg.Key = key0.ToArray();
}
else
{
    alg = TripleDES.Create();
    alg.Key = key;
}

要更换两个衬管:

TripleDES alg = TripleDES.Create();
alg.Key = key;