C# DES 与 Java DES Byte[] 和 BlockSize 不同
C# DES vs Java DES Byte[] and BlockSize differs
我正在努力让 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#输出
Algorithm: DES?/CBC/PKCS7
BlockSize: 64
barray length: 16
barray: 107 125 91 205 77 206 98 120 214 194 64 167 128 97 132 75
base64: a31bzU3OYnjWwkCngGGESw==
Java输出
Algorithm: DES/CBC/PKCS7Padding
BlockSize: 8
barray length: 8
barray: 45 100 -86 103 9 -7 -19 -76
base64: LWSqZwn57bQ=
我正在尝试从 Java 代码中获得与我已经从 C#
中获得的完全相同的 Byte[]
输出。但我设法看到的唯一区别是块大小与两者不同。
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=
@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' }
因为"peanuts"是(在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 中很容易看出是相同的.
我正在努力让 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#输出
Algorithm: DES?/CBC/PKCS7
BlockSize: 64
barray length: 16
barray: 107 125 91 205 77 206 98 120 214 194 64 167 128 97 132 75
base64: a31bzU3OYnjWwkCngGGESw==
Java输出
Algorithm: DES/CBC/PKCS7Padding
BlockSize: 8
barray length: 8
barray: 45 100 -86 103 9 -7 -19 -76
base64: LWSqZwn57bQ=
我正在尝试从 Java 代码中获得与我已经从 C#
中获得的完全相同的 Byte[]
输出。但我设法看到的唯一区别是块大小与两者不同。
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=
@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' }
因为"peanuts"是(在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 中很容易看出是相同的.