【问题标题】:C# DES vs Java DES Byte[] and BlockSize differsC# DES 与 Java DES Byte[] 和 BlockSize 不同
【发布时间】:2019-11-10 12:22:28
【问题描述】:

我正在努力让 Java 代码输出与 C# 代码相同的 Byte[]。

C#代码:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    private const string k = "A2B3C4D1";
    private const string kiv = "1A2B3C4D";
    
    public static void Main()
    {
        encrypt("peanuts");
    }
    
    public static void encrypt(string str)
    {
        try
        {
            using (var ms = new MemoryStream())
            using (var csp = new DESCryptoServiceProvider() { Key = Encoding.UTF8.GetBytes(k), IV =  Encoding.UTF8.GetBytes(kiv) })
            {
                Console.WriteLine("Algorithm: DES?/" + csp.Mode + "/" + csp.Padding);
                Console.WriteLine("BlockSize: " + csp.BlockSize);

                using (var cs = new CryptoStream(ms, csp.CreateEncryptor(), CryptoStreamMode.Write))
                using (var sw = new StreamWriter(cs))
                    sw.WriteLine(str);

                byte[] barray = ms.ToArray();

                Console.WriteLine("barray length: " + barray.Length);
            
                Console.WriteLine("barray: " + string.Join(" ", barray));
            }
        }
        catch (Exception ex) { Console.Write(ex.ToString()); }
    }
}

Java 代码:

import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.Security;

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

public class MyClass {
    private static final String k = "A2B3C4D1";
    private static final String kiv = "1A2B3C4D";
    
    public static void main(String args[]) {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

        encrypt("peanuts");
    }
    
    public static void encrypt(String str) {
        try {
            SecretKeySpec key = new SecretKeySpec(k.getBytes(Charset.forName("UTF-8")), "DES");
            IvParameterSpec iv = new IvParameterSpec(kiv.getBytes(Charset.forName("UTF-8")));
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS7Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);
            
            System.out.println("Algorithm: " + cipher.getAlgorithm());
            System.out.println("BlockSize: " + cipher.getBlockSize());
    
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            CipherOutputStream cos = new CipherOutputStream(out, cipher);
            
            cos.write(str.getBytes());
            cos.close();
            
            byte[] barray = out.toByteArray();
            
            System.out.println("barray length: " + barray.length);
        
            System.out.print("barray: ");
            for(byte b : barray){
                System.out.print(" " + b);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

C# 输出

算法:DES?/CBC/PKCS7

块大小:64

数组长度:16

阵列:107 125 91 205 77 206 98 120 214 194 64 167 128 97 132 75

base64: a31bzU3OYnjWwkCngGGESw==

Java 输出

算法:DES/CBC/PKCS7Padding

块大小:8

数组长度:8

数组:45 100 -86 103 9 -7 -19 -76

base64: LWSqZwn57bQ=

我正在尝试从 Java 代码中获得完全相同的 Byte[] 输出,就像我已经从 C# 获得的一样。但我设法看到的唯一区别是两者的块大小不同。

C# Dot.Net Fiddle

Java jDoodle.com

我就是不明白,有什么我遗漏或不明白的地方吗?

编辑

我添加了代码来打印字符串中的字节数组,它不同:

C#

barray length: 16
barray: 107 125 91 205 77 206 98 120 214 194 64 167 128 97 132 75
base64: a31bzU3OYnjWwkCngGGESw==

Java

barray length: 8
barray: 45 100 -86 103 9 -7 -19 -76
base64: LWSqZwn57bQ=

【问题讨论】:

  • 值得注意的是,除非您有特定的理由这样做,否则您应该避免使用 DES - 由于其密钥空间小,它不被认为是安全的。
  • @AlexK。我正在操作byte[] 输出。不幸的是,这必须在 Java 上工作 - C# 实现超出了我的控制
  • C# blocksize 以位为单位,Java blocksize 以字节为单位。就是这么简单。
  • 糟糕,您还使用 WriteLine() 是附加换行符的 C#。只需使用Write(),您应该会得到与Java 相同的结果。或者,将“\n”附加到 Java 字符串,即encrypt("peanuts\n");
  • @JamesKPolk 我已经测试过了,不是这样。 byte[] 物理上是不一样的。我用更多信息更新了这个问题。为什么两种加密都会给出如此不同的输出?

标签: java c# encryption des


【解决方案1】:

@JamesKPolk 是正确的:您在 C# 中加密 { (byte)'p', (byte)'e', (byte)'a', (byte)'n', (byte)'u', (byte)'t', (byte)'s', (byte)'\r', (byte)'\n' },在 Java 中加密 { (byte)'p', (byte)'e', (byte)'a', (byte)'n', (byte)'u', (byte)'t', (byte)'s' }

由于“花生”是(在 UTF-8 中)7 个字节,它可以被 PKCS7 填充到一个 DES 块中。接下来的 1-8 个字节会产生第二个块……而您添加了两个。

将 Dot.Net Fiddle 中的代码更改为 Write 而不是 WriteLine 产生

Algorithm: DES?/CBC/PKCS7
BlockSize: 64
barray length: 8
barray: 45 100 170 103 9 249 237 180
barray: LWSqZwn57bQ=

现在唯一的区别是 C# BlockSize 是位,而您的 Java 代码将其作为字节。

在您的 JDoodle 中将 "peanuts" 更改为 "peanuts\r\n" 即可

Algorithm: DES/CBC/PKCS7Padding
BlockSize: 8
barray length: 16
barray:  107 125 91 -51 77 -50 98 120 -42 -62 64 -89 -128 97 -124 75
barray: a31bzU3OYnjWwkCngGGESw==

如果 barray 十进制内容被打印为无符号值而不是有符号值(将 256 加到所有负数),这也是相同的——在 Base64 中很容易看出这一事实是相同的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多