I have a Java encryption routine that I need to decrypt with C#. The Java routine is using a Bouncy Castle line that I've been unable to replicate in C#:
我有一个Java加密例程,我需要用C#解密。 Java例程正在使用我无法在C#中复制的Bouncy Castle行:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
This is the only reference to Bouncy Castle in the Java code.
这是Java代码中对Bouncy Castle的唯一引用。
I have no control over the Java side, only the C# side. All of my C# decryption attempts give me junk data, and the only discrepancy I can spot in the Java code compared with my C# code is the lack of Bouncy Castle on the C# side. Does anyone know how I can assign BouncyCastle as the security provider in C#? I have looked through the Bouncy Castle source code, on their site, and online with no luck.
我无法控制Java端,只能控制C#端。我所有的C#解密尝试都给了我垃圾数据,与我的C#代码相比,我在Java代码中发现的唯一差异是C#端缺少Bouncy Castle。有谁知道如何将CouncyCastle指定为C#中的安全提供程序?我查看了Bouncy Castle的源代码,在他们的网站上,并在网上没有运气。
Edit: Given the responses thus far, I have updated my code to use Bouncy Castle. I am adding my C# decryption code and the Java encryption code below. While I am using Bouncy Castle, I still cannot get the decryption to work properly. I must be overlooking something simple but I cannot see it... Any thoughts are appreciated.
编辑:鉴于迄今为止的回复,我已更新我的代码以使用Bouncy Castle。我在下面添加了我的C#解密代码和Java加密代码。当我使用Bouncy Castle时,我仍然无法使解密正常工作。我必须忽略一些简单的东西,但我看不到它......任何想法都值得赞赏。
C# decryption code:
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 code:
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;
}
3 个解决方案
#1
2
As codes comments: "In C# you either use the BC library directly, or you don't. This kind of "provider" concept doesn't exist." This is similar to using the "lightweight API" in Java. There are no equivalents to the Java JCE API defined by Oracle / OpenJDK.
代码注释:“在C#中,您可以直接使用BC库,也可以不使用。这种”提供者“概念不存在。”这类似于在Java中使用“轻量级API”。 Oracle / OpenJDK定义的Java JCE API没有等价物。
#2
2
I had to do something similar before. My application had to Encrypt data in C# then decrypt it in Java. However, I wrote something that Decrypts data in C# side as well. Here is my code:
我之前不得不做类似的事情。我的应用程序必须在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);
}
}
EDIT:
编辑:
Adding the libraries I have used:
添加我使用过的库:
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;
**EDIT 2: ** Adding the readPrivateKey function:
**编辑2:**添加readPrivateKey函数:
static AsymmetricKeyParameter readPrivateKey(string privateKeyFileName)
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(privateKeyFileName))
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
return keyPair.Private;
}
I also asked a few questions around this matter too, if you look at the questions I asked through my profile or searching the site, you might find some help as well.
我也就此问题提出了一些问题,如果你看一下我通过个人资料或搜索网站提出的问题,你也可以找到一些帮助。
**Edit 3: ** //Adding Encryption function
**编辑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;
}
#3
1
In crypto everything needs to match exactly on both sides. That means checking that everything matches, byte for byte. Do your IV's match byte for byte? Do your final keys (after the KDFs) match byte for byte? Do the two cyphertexts match byte for byte? There may have been transmission problems between the two systems.
在加密中,一切都需要在两侧完全匹配。这意味着检查所有内容是否匹配,逐字节。你的IV匹配字节是否为字节?您的最终密钥(在KDF之后)是否与字节匹配?这两个cyphertexts是否匹配byte的字节?两个系统之间可能存在传输问题。
Do you get any error messages when trying to decrypt, such as a "Bad Padding" error? If you do not, then the padding is being decrypted correctly, even if the bulk of the message is not. That may indicate that the problem is not with the decryption as such, but elsewhere in the system.
尝试解密时是否收到任何错误消息,例如“Bad Padding”错误?如果不这样做,则填充正在被正确解密,即使大部分消息没有。这可能表明问题不在于解密本身,而是在系统的其他地方。
Have you tried passing a very simple message, "Hello World!" through the process? How did that do?
你试过传递一个非常简单的信息,“Hello World!”通过这个过程?那怎么办?
#1
2
As codes comments: "In C# you either use the BC library directly, or you don't. This kind of "provider" concept doesn't exist." This is similar to using the "lightweight API" in Java. There are no equivalents to the Java JCE API defined by Oracle / OpenJDK.
代码注释:“在C#中,您可以直接使用BC库,也可以不使用。这种”提供者“概念不存在。”这类似于在Java中使用“轻量级API”。 Oracle / OpenJDK定义的Java JCE API没有等价物。
#2
2
I had to do something similar before. My application had to Encrypt data in C# then decrypt it in Java. However, I wrote something that Decrypts data in C# side as well. Here is my code:
我之前不得不做类似的事情。我的应用程序必须在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);
}
}
EDIT:
编辑:
Adding the libraries I have used:
添加我使用过的库:
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;
**EDIT 2: ** Adding the readPrivateKey function:
**编辑2:**添加readPrivateKey函数:
static AsymmetricKeyParameter readPrivateKey(string privateKeyFileName)
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(privateKeyFileName))
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
return keyPair.Private;
}
I also asked a few questions around this matter too, if you look at the questions I asked through my profile or searching the site, you might find some help as well.
我也就此问题提出了一些问题,如果你看一下我通过个人资料或搜索网站提出的问题,你也可以找到一些帮助。
**Edit 3: ** //Adding Encryption function
**编辑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;
}
#3
1
In crypto everything needs to match exactly on both sides. That means checking that everything matches, byte for byte. Do your IV's match byte for byte? Do your final keys (after the KDFs) match byte for byte? Do the two cyphertexts match byte for byte? There may have been transmission problems between the two systems.
在加密中,一切都需要在两侧完全匹配。这意味着检查所有内容是否匹配,逐字节。你的IV匹配字节是否为字节?您的最终密钥(在KDF之后)是否与字节匹配?这两个cyphertexts是否匹配byte的字节?两个系统之间可能存在传输问题。
Do you get any error messages when trying to decrypt, such as a "Bad Padding" error? If you do not, then the padding is being decrypted correctly, even if the bulk of the message is not. That may indicate that the problem is not with the decryption as such, but elsewhere in the system.
尝试解密时是否收到任何错误消息,例如“Bad Padding”错误?如果不这样做,则填充正在被正确解密,即使大部分消息没有。这可能表明问题不在于解密本身,而是在系统的其他地方。
Have you tried passing a very simple message, "Hello World!" through the process? How did that do?
你试过传递一个非常简单的信息,“Hello World!”通过这个过程?那怎么办?