【发布时间】:2019-03-21 23:38:32
【问题描述】:
我正在尝试根据我找到的另一个 C# 方法复制加密方法。
C#加密方法EncryptText(word, password)调用另一个方法AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)加密纯文本:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.IO;
using System.Text;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
var f = EncryptText("763059", "515t3ma5m15B4d35");//(word, password)
Console.WriteLine(f);
}
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
public static string EncryptText(string input, string password)
{
byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
string result = Convert.ToBase64String(bytesEncrypted);
return result;
}
}
}
使用单词763059和密码515t3ma5m15B4d35,输出如下:
3cHrXxxL1Djv0K2xW4HuCg==
更新:
现在,我创建了一个 Java Class main 我试图复制以前的代码:
public class main {
final static String PASSWORD = "515t3ma5m15B4d35";
final static byte[] SALT = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
final static int KEY_SIZE = 256;
final static int BLOCK_SIZE = 128;
final static int ITERATIONS = 1000;
public static void main(String[] args) {
System.out.println(encryptText("763059", PASSWORD));
}
public static String encryptText(String word, String password) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes("UTF-8"));
password = new String(md.digest(), "UTF-8");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, ITERATIONS, KEY_SIZE);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec skey = new SecretKeySpec(tmp.getEncoded(), "AES");
byte[] iv = new byte[BLOCK_SIZE / 8];
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
byte[] result = ci.doFinal(word.getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(result);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | InvalidKeySpecException ex) {
return null;
}
}
}
更新:
我阅读了有关在 Java 中使用 256 位密钥的信息,我发现我需要添加 Java Cryptography Extensions 以允许 256 个密钥(因为我正在使用 JDK7)。
然后我将库添加到项目中,我也更改了行:
KeySpec spec = new PBEKeySpec(password.toCharArray(), SALT, ITERATIONS, KEY_SIZE);
带有键值:
final static int KEY_SIZE = 256;
现在输出如下:
J1xbKOjIeXbQ9njH+67RNw==
我仍然无法实现我的目标。有什么建议吗?
【问题讨论】:
-
也许我看错了,但你不是在 c# 中使用 256 位密钥,在 Java 中使用 128 位密钥吗?
-
@JohnWu,哦,真的吗?在哪一部分?
-
我建议您 debug.log 记录每个单独的加密调用的输入和输出,以便您可以更轻松地隔离问题。
-
哇,您完全错过了第一次 SHA-256 密码的部分(出于某种未知原因)。你还在努力吗?投反对票;为什么不让 Java 代码至少看起来像 C# 代码?
-
另一个问题是字节数组的数据(密码的哈希值)存储在字符数组中,因为
PBEKeySpec需要一个字符数组。在 PBKDF2-provider 内部,字符数组使用 UTF-8 编码转换回字节数组。原始(在 C# 代码中使用)和重新转换的字节数组在值 >=0x80(大部分存在)方面会有所不同。这会导致两种代码中的密钥和 IV 不同,从而产生不同的加密数据。另一种方法是来自 Bouncy Castle 的PKCS5S2ParametersGenerator,用于生成需要字节数组的密钥和 IV。
标签: java c# encryption aes sha256