java - C# AES 加密到 java 8 解密
问题描述
我试图在 C# 中模仿 java 加密例程,因为端点是基于 java 的,并且将解密 C# 生成的值。
我已经尝试了不同的实现,使用SOAesCryptoServiceProvider
和AesManaged
web 中的几个示例,但我仍然无法让 java 端点成功解密该值,它与{"message":"AUTHENTICATION_ERROR: Error while decrypting the cipher.","status":"Error"}
.
使用邮递员,我能够调用 java 端点并使用下面发布的 java 代码生成的加密文本检索文档,因此该部分得到了肯定验证。
端点使用标头值来解密文本并验证内容,以下是相关的代码片段:
java加密
private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8"); byte[]ivBytes = iv.getBytes("UTF-8");
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
//encrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
return cipher;
}
public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(encryptedTextBytes);
}
标题
interface_name: interfaceName
strength: 256
salt: salt_sixteen1234
iterate: 100
iv: sixteen_value_12
ciphertext: ECtKO7VluxCPFS/D8LVsb2bOQjhViIZm+O3zfMqSwJOLLTpDL4xdgwmIWr+41n5j
C# 加密
...
using (var csp = new AesCryptoServiceProvider())
{
ICryptoTransform e = GetCryptoTransform(csp, true, key, salt, iv);
byte[] inputBuffer = Encoding.UTF8.GetBytes(plainText);
byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
string encrypted = Convert.ToBase64String(output);
return encrypted;
}
...
private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting, string password, string salt, string iv, int iterations)
{
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), iterations);
byte[] key = spec.GetBytes(16);
csp.IV = Encoding.UTF8.GetBytes(iv);
csp.Key = key;
if (encrypting)
{
return csp.CreateEncryptor();
}
return csp.CreateDecryptor();
}
解决方案
为了测试任何 C# 加密,我在您的 Java 代码中添加了一个解密方法,并成功运行了一整轮(加密和解密)。
对于 C# 部分,我懒得检查您的代码(就像@Topaco 所做的那样),并使用我自己的代码和您的凭据来获取可以呈现给 Java 解密方法的输出。
让我们从更长的安全警告开始:代码使用静态初始化向量和静态盐,并且 PBKDF2 密钥派生的迭代计数太低(至少应使用 10.000)。这些代码没有任何异常处理,仅用于教育目的。
运行 C# 代码会给出一个简短的输出:
AES CBC 256 string encryption with PBKDF2 SHA1 key derivation
plaintext: The quick brown fox jumps over the lazy dog
ciphertext: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
将密文呈现给 Java 解密将给出以下输出:
C# AES encrypt to java 8 decrypt
plaintext: The quick brown fox jumps over the lazy dog
ciphertext: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
decryptedtext: The quick brown fox jumps over the lazy dog
decryption of a ciphertext from C#
ciphertextFromCsharp: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
decryptedtextFromCsharp: The quick brown fox jumps over the lazy dog
两种代码都可在此处进行实时自测(Java:https ://repl.it/@javacrypto/JavaAes256EncryptionWithPBKDF2SHA1keyderivation,C#: https : //repl.it/@javacrypto/CsharpAes256Pbkdf2Encryption#main.cs )。
C#-代码:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program {
public static void Main() {
Console.WriteLine("AES CBC 256 string encryption with PBKDF2 SHA1 key derivation");
// credentials
string plaintext = "The quick brown fox jumps over the lazy dog";
string password = "myPassword";
string saltString = "salt_sixteen1234";
var iterationsCount = 100;
string ivString = "sixteen_value_12";
Encoding enc = Encoding.UTF8;
byte[] saltBytes = enc.GetBytes(saltString);
byte[] iv = enc.GetBytes(ivString);
byte[] key;
try {
// pbkdf2 sha1 key derivation
using (var pbkdf2 = new Rfc2898DeriveBytes(
password,
saltBytes,
iterationsCount,
HashAlgorithmName.SHA1))
{
key = pbkdf2.GetBytes(32);
}
Console.WriteLine("plaintext: {0}", plaintext);
string ciphertext = encrypt(key, iv, plaintext);
Console.WriteLine("ciphertext: {0}", ciphertext);
}
catch(Exception e) {
Console.WriteLine("Error: {0}", e.Message);
}
}
static string encrypt(byte[] key, byte[] IV, string data) {
byte[] encrypted;
using(Aes aesAlg = Aes.Create()) {
aesAlg.Key = key;
aesAlg.IV = IV;
aesAlg.Mode = CipherMode.CBC;
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// create the streams used for encryption.
using(var msEncrypt = new MemoryStream()) {
using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using(var swEncrypt = new StreamWriter(csEncrypt)) {
//Write all data to the stream.
swEncrypt.Write(data);
}
encrypted = msEncrypt.ToArray();
}
}
}
return Convert.ToBase64String(encrypted);
}
}
Java代码:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("C# AES encrypt to java 8 decrypt");
String plaintext = "The quick brown fox jumps over the lazy dog";
String password = "myPassword";
String iv = "sixteen_value_12";
String salt = "salt_sixteen1234";
int iterations = 100;
int keySize = 256;
System.out.println("plaintext: " + plaintext);
String ciphertext = AES_encrypt(plaintext, password, salt, iv, iterations, keySize);
System.out.println("ciphertext: " + ciphertext);
String decryptedtext = AES_decrypt(ciphertext, password, salt, iv, iterations, keySize);
System.out.println("decryptedtext: " + decryptedtext);
System.out.println("\ndecryption of a ciphertext from C#");
String ciphertextFromCsharp = "5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4";
System.out.println("ciphertextFromCsharp: " + ciphertextFromCsharp);
String decryptedtextFromCsharp = AES_decrypt(ciphertextFromCsharp, password, salt, iv, iterations, keySize);
System.out.println("decryptedtextFromCsharp: " + decryptedtextFromCsharp);
}
private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8"); byte[]ivBytes = iv.getBytes("UTF-8");
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
//encrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
return cipher;
}
public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(encryptedTextBytes);
}
public static String AES_decrypt(String cipherText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
Base64.Decoder decoder = Base64.getDecoder();
Cipher cipher = generateCipher(Cipher.DECRYPT_MODE, password, salt, iv, iterations, keySize);
return new String(cipher.doFinal(decoder.decode(cipherText)), StandardCharsets.UTF_8);
}
}
推荐阅读
- python - OpenCV image stitching never finishes
- android - Implementing Custom Back Navigation in Android
- android - Is there a way to store registered devices FCM tokens in Firebase Console?
- linq - How to calculate the 5th heighest salary from Employee Table and Salary Table using LINQ query
- r - Is there a way where i can rearrange a dataframe and turn it into a 3 column dataframe
- c# - How to query the sum of each person's availability base on their skill
- http - I do not understand this paragraph explaining web browser caching
- javascript - 将 js 对象键值设置为始终引用现有变量
- visual-studio - Visual Studio not recognizing installed Core SDKs
- python-3.x - Plotting Grid Search CV grid parameter results on one graph