我有一个Java加密例程,我需要用C#解密。 Java例程正在使用我无法在C#中复制的Bouncy Castle系列:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
这是Java代码中对Bouncy Castle的唯一引用。
我无法控制Java端,只能控制C#端。我的所有C#解密尝试都给了我垃圾数据,与我的C#代码相比,我在Java代码中发现的唯一差异是C#端缺少Bouncy Castle。有谁知道如何将CouncyCastle指定为C#中的安全提供程序?我在他们的网站上浏览了Bouncy Castle的源代码,但没有运气。
编辑:鉴于到目前为止的回复,我已更新我的代码以使用Bouncy Castle。我在下面添加了我的C#解密代码和Java加密代码。当我使用Bouncy Castle时,我仍然无法使解密正常工作。我必须忽略一些简单的东西,但我看不到它......任何想法都会受到赞赏。
C#解密代码:
public string Decrypt(string stringToDecrypt, string encryption_Key, string init_Vector, string salt)
{
byte[] SALT = Convert.FromBase64String(salt);
int iterations = 12345;
var rfc2898 = new System.Security.Cryptography.Rfc2898DeriveBytes(encryption_Key, SALT, iterations);
byte[] KEY = rfc2898.GetBytes(16);
KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter("AES", KEY);
byte[] IV = Encoding.UTF8.GetBytes(init_Vector);
ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, IV);
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS5Padding");
cipher.Init(false, aesIVKeyParam);
//byte[] bytesToDecrypt = Convert.FromBase64String(stringToDecrypt);
// Gives me "pad block corrupted" error
//byte[] bytesToDecrypt = Encoding.UTF8.GetBytes(stringToDecrypt);
// Gives me "last block incomplete in decryption" error
byte[] bytesToDecrypt = Base64.Decode(Encoding.UTF8.GetBytes(stringToDecrypt));
// Gives me "pad block corrupted" error
byte[] output = cipher.DoFinal(bytesToDecrypt);
return Convert.ToBase64String(output);
}
Java代码:
public class testaes {
/**
* The iteration count for key generation algorithm.
*/
private static final int KEY_ITERATION_COUNT = 12345;
/**
* The key length in bits.
*/
private static final int KEY_LENGTH = 128;
/**
* The algorithm for cipher initialization.
*/
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
/**
* The algorithm for key factory selection.
*/
private static final String KEY_FACTORY_ALGORITHM = "PBKDF2WithHmacSHA1";
/**
* The algorithm for key generation.
*/
private static final String KEY_ALGORITHM = "AES";
/**
* The byte encoding.
*/
private static final String BYTE_ENCODING = "UTF-8";
private static testaes instance = null;
public testaes() {
super();
}
public static testaes getInstance() {
if (instance == null) {
instance = new testaes();
}
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
return instance;
}
/**
* Instantiates the cipher.
*/
private Cipher initCipher(int opmode) throws Exception, NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException {
String access = "XXXXX";
byte[] salt = "XXXXX".getBytes();
String ivString = "XXXXX";
// Build the key from password and salt.
char[] accessCharArray = access.toCharArray();
byte[] saltByteArray = Base64.decodeBase64(salt);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
KeySpec spec = new PBEKeySpec(accessCharArray, saltByteArray, KEY_ITERATION_COUNT, KEY_LENGTH);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), KEY_ALGORITHM);
// Create a cipher based on AES transformation.
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
// Initialize cipher to with Secret Key and IV.
cipher.init(opmode, secretKey, new IvParameterSpec(ivString.getBytes(BYTE_ENCODING)));
return cipher;
}
/**
* Encrypts the data.
*
* @param originalString
* The data to be encrypted.
* @return The encrypted data as String.
*/
public String encryptAES(String originalString) {
String encryptedString = null;
try {
Cipher cipher = initCipher(Cipher.ENCRYPT_MODE);
byte[] encryptedBytes = cipher.doFinal(originalString.getBytes());
String base64Encoded = new String(Base64.encodeBase64(encryptedBytes), Charset.forName(BYTE_ENCODING));
String urlEncoded = URLEncoder.encode(base64Encoded, BYTE_ENCODING);
encryptedString = urlEncoded;
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString;
}
/**
* Decrypts the data.
*
* @param encryptedString
* The encrypted data that is to be decrypted.
* @return The decrypted (original) data as string.
*/
public String decryptAES(String encryptedString) {
String decryptedString = null;
try {
Cipher cipher = initCipher(Cipher.DECRYPT_MODE);
String urlDecoded = URLDecoder.decode(encryptedString, BYTE_ENCODING);
byte[] encryptedBytes = Base64.decodeBase64(urlDecoded.getBytes(Charset.forName(BYTE_ENCODING)));
byte[] originalBytes = cipher.doFinal(encryptedBytes);
decryptedString = new String(originalBytes);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedString;
}
答案 0 :(得分:2)
代码注释:“在C#中,您可以直接使用BC库,也可以不使用。这种”提供者“概念不存在。”这类似于在Java中使用“轻量级API”。 Oracle / OpenJDK定义的Java JCE API没有等价物。
答案 1 :(得分:2)
我以前必须做类似的事情。我的应用程序必须使用C#加密数据,然后用Java解密。但是,我写了一些在C#侧解密数据的东西。这是我的代码:
public static byte[] Decrypt3(byte[] data, string pemFilename)
{
try {
AsymmetricKeyParameter key = readPrivateKey(pemFilename);
RsaEngine e = new RsaEngine();
e.Init(false, key);
byte[] cipheredBytes = e.ProcessBlock(data, 0, data.Length);
return cipheredBytes;
} catch (Exception e) {
Debug.Log ("Exception in Decrypt3: " + e.Message);
return GetBytes(e.Message);
}
}
修改强>
添加我使用过的库:
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using UnityEngine;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Engines;
**编辑2:** 添加readPrivateKey函数:
static AsymmetricKeyParameter readPrivateKey(string privateKeyFileName)
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(privateKeyFileName))
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
return keyPair.Private;
}
我也就此问题提出了几个问题,如果你看一下我通过个人资料或搜索网站提出的问题,你也可以找到一些帮助。
**编辑3:** //添加加密功能
public static byte[] Encrypt3(byte[] data, string pemFilename)
{
byte[] cipheredBytes = null;
try {
AsymmetricKeyParameter key = ReadAsymmetricKeyParameter(pemFilename);
RsaEngine e = new RsaEngine();
e.Init(true, key);
//Debug.Log ("Encryption msg: " + inputMessage);
//cipheredBytes = GetBytes(inputMessage);
//Debug.Log ("bytes: " + GetString(cipheredBytes));
cipheredBytes = e.ProcessBlock(data, 0, data.Length);
}
catch (Exception e) {
Debug.Log (e.Message);
}
return cipheredBytes;
}
答案 2 :(得分:1)
在加密一切需要完全匹配双方。这意味着检查所有内容是否匹配,逐字节。你的IV匹配字节是否为字节?您的最终密钥(在KDF之后)是否与字节匹配?这两个cyphertexts是否匹配byte的字节?两个系统之间可能存在传输问题。
尝试解密时是否收到任何错误消息,例如“Bad Padding”错误?如果不这样做,则填充正在被正确解密,即使大部分消息没有。这可能表明问题不在于解密本身,而在系统的其他地方。
您是否尝试过传递一条非常简单的消息,“Hello World!”通过这个过程?那怎么办?