我需要将一个加密的字符串从私钥发送到网络服务器进行身份验证。我有Java客户端代码,可以正确生成加密字符串(这样Web服务器就可以使用公钥解密它)。我正在尝试编写C#代码来执行完全相同的加密 - 但是没有成功。
首先,使用与此类似的keytool在java中生成密钥库:
keytool -genkey -dname "cn=Application Test, ou=XXX, o=YYY, c=US" -alias AppTest -keypass AppTest -keystore AppTest.jks -storepass AppTest -validity 1800 -keyalg RSA
然后这个java代码正确读取密钥库并加密数据(privateKey.getAlgorithm()返回“RSA”):
KeyStore ks = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream("AppTest.jks");
ks.load(is, "AppTest".toCharArray());
is.close();
PrivateKey privateKey = (PrivateKey) ks.getKey(user, password.toCharArray());
// Encrypt with the private key
String stamp = "123456";
byte[] bytesStampUtf8Unencrypted = stamp.getBytes(Charset.forName("UTF-8"));
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] bytesTimestampUtf8Encrypted = cipher.doFinal(bytesStampUtf8Unencrypted);
String encrypted = new String((new Base64()).encode(bytesStampUtf8Unencrypted));
这一切在传递给Web服务时都很有用。然后我使用keytool从java密钥库转换为PKCS12证书,以便在我的.NET应用程序中使用:
keytool -importkeystore -srckeystore AppTest.keystore -destkeystore KEYSTORE.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass AppTest -deststorepass AppTest-srcalias AppTest -destalias AppTest -srckeypass AppTest -destkeypass AppTest -noprompt
使用keytool我比较了密钥库和P12文件的指纹 - 相同。我认为以下C#代码应该可以工作:
X509Certificate2 myCertificate =
new X509Certificate2(@"C:\Temp\KEYSTORE.p12", "AppTest");
RSACryptoServiceProvider privateKey =
myCertificate.PrivateKey as RSACryptoServiceProvider;
String stamp = "123456";
byte[] buffer = Encoding.UTF8.GetBytes(stamp);
byte[] encryptedBytes = privateKey.Encrypt(buffer, false);
String encrypted = Convert.ToBase64String(encryptedBytes);
它正确读取转换后的密钥库文件,执行没有问题,并生成看似加密的数据,但Web服务不喜欢加密的字符串(不能用公钥解密)。当我用Java加密的字符串替换C#加密字符串(在调试器中)并通过C#程序将该字符串发送到Web服务时 - 它一切都运行良好 - 所以我相信问题出在加密过程中,而不是在网络服务沟通中。
我无法控制原始密钥的生成方式(作为java密钥库),也无法控制Web服务所期望的加密方法。我只能控制与基于Java的Web服务交互的.NET客户端。
我错过了一些旗帜,设置,变量,什么?
答案 0 :(得分:2)
与java相比,您确定加密算法,分组密码模式和填充模式在您的C#实现中是等效的执行?
编辑:实际上对于RSACryptoProvider,您可能不需要密码/填充模式 - 请查看MSDN上的示例,特别是有关通过ImportParameters导入公钥信息的部分
答案 1 :(得分:0)
这是一个难以在Java中加密和在.Net中解密的工作条件下找到的解决方案,最后我能够在我的一个项目中实现,使用这个我们可以加密java中的任何字符串并解密它.Net结束使用BouncyCastle API。
我使用Blowfish进行加密/解密:
您可以从http://bouncycastle.org/latest_releases.html
引用bouncycastle等文件 import org.bouncycastle.util.encoders.UrlBase64;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Strings;
public class EncryptString
{
public static void main(String[] args) throws Exception
{
String plain = "UserName=\'pgupta\'&Channel=\'1\'&LevelID=\'1\'&LevelName=\'Super Star colony\'";
String key = "x-392kla%3$*1f";
//To getBytes in UTF8 Encoding
byte[] inBytes = plain.getBytes("UTF8");
byte[] keyByte = key.getBytes("UTF8");
PaddedBufferedBlockCipher _cipher = new PaddedBufferedBlockCipher(new BlowfishEngine());
try
{
_cipher.init(true, new KeyParameter(keyByte));
// Determine the minimum output buffer size
byte[] outBytes = new byte[_cipher.getOutputSize(inBytes.length)];
// 'len' is the actual size returned
int len = _cipher.processBytes(inBytes, 0, inBytes.length, outBytes, 0);
_cipher.doFinal(outBytes,len);
System.out.println("encrypted: " + new String(UrlBase64.encode(outBytes)));
}
catch(Exception e)
{
System.out.println("Exception: " + e.toString());
}
}
}
using System;
using System.Collections.Generic;
using Org.BouncyCastle.Crypto.Paddings;
using System.Text;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
public class Decrypt
{
public string Decryption(string Request)
{
String EncryptedS = Request;
string convertHTML = string.Empty;
String key = ConfigurationSettings.AppSettings["EncDecKey"];//"123456789";
byte[] keyByte = Encoding.UTF8.GetBytes(key);
try
{
byte[] result = BouncyCastleCrypto(false, UrlBase64.Decode(EncryptedS), key);
convertHTML = Encoding.UTF8.GetString(result);
}
catch (Org.BouncyCastle.Crypto.CryptoException ex)
{
convertHTML = "false";
}
return convertHTML;
}
private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, string key)
{
try
{
byte[] keyByte = Encoding.UTF8.GetBytes(key);
_PaddedBufferedBlockCipherWithlowfish.Init(forEncrypt, new KeyParameter(keyByte));
byte[] outBytes = new byte[_PaddedBufferedBlockCipherWithlowfish.GetOutputSize(input.Length)];
int len = _PaddedBufferedBlockCipherWithlowfish.ProcessBytes(input, 0, input.Length, outBytes, 0);
_PaddedBufferedBlockCipherWithlowfish.DoFinal(outBytes, len);
return outBytes;
}
catch (Org.BouncyCastle.Crypto.CryptoException ex)
{
throw new CryptoException(ex.ToString());
}
}
}
注意:请确保两端使用相同的密钥。