C# RSA.NET加密Java解密
我正在尝试使用RSA算法在.NET中加密字符串,并在Java中解密结果。目前,我可以做相反的事情(用Java加密,用.NET解密)。 在这里,我有我的实际工作的代码(JAVA加密): 和(.NET解密)C# RSA.NET加密Java解密,c#,java,security,cryptography,C#,Java,Security,Cryptography,我正在尝试使用RSA算法在.NET中加密字符串,并在Java中解密结果。目前,我可以做相反的事情(用Java加密,用.NET解密)。 在这里,我有我的实际工作的代码(JAVA加密): 和(.NET解密) 根据您的要求,这里有一些代码片段。RSA密钥来自x509证书 Java RSA/AES: // symmetric algorithm for data encryption final String ALGORITHM = "AES"; // Padding for symmetric alg
根据您的要求,这里有一些代码片段。RSA密钥来自x509证书 Java RSA/AES:
// symmetric algorithm for data encryption
final String ALGORITHM = "AES";
// Padding for symmetric algorithm
final String PADDING_MODE = "/CBC/PKCS5Padding";
// character encoding
final String CHAR_ENCODING = "UTF-8";
// provider for the crypto
final String CRYPTO_PROVIDER = "Entrust";
// RSA algorithm used to encrypt symmetric key
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// symmetric key size (128, 192, 256) if using 192+ you must have the Java
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// installed
int AES_KEY_SIZE = 256;
private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// get the public key from the encryption certificate to encrypt with
PublicKey pubKey = cert.getPublicKey();
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
// set the cipher to use the public key
rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);
// encrypt the aesKey
return rsaCipher.doFinal(aesKey);
}
private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException {
// get the symmetric key generator
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(AES_KEY_SIZE); // set the key size
// generate the key
SecretKey skey = keyGen.generateKey();
// convert to binary
byte[] rawAesKey = skey.getEncoded();
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to encrypt mode, with the generated key
aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// get the initialization vector being used (to be returned)
byte[] aesIV = aesCipher.getIV();
// encrypt the data
byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);
// package the aes key, IV, and encrypted data and return them
return new AESEncryptedContents(rawAesKey, aesIV, encryptedData);
}
private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV,
byte[] encryptedData) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
NoSuchProviderException {
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to decrypt mode with the AES key, and IV
aesCipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(aesIV));
// decrypt and return the data
byte[] decryptedData = aesCipher.doFinal(encryptedData);
return decryptedData;
}
private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey)
throws IllegalBlockSizeException, BadPaddingException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, NoSuchProviderException {
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
// set the cipher to use the public key
rsaCipher.init(Cipher.DECRYPT_MODE, privKey);
// encrypt the aesKey
return rsaCipher.doFinal(encryptedAesKey);
}
public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) {
if (data == null)
throw new ArgumentNullException("data");
byte[] encryptedData; // data to return
// begin AES key generation
RijndaelManaged aesAlg = new RijndaelManaged();
aesAlg.KeySize = AES_KEY_SIZE;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
// aes Key to be encrypted
byte[] aesKey = aesAlg.Key;
// aes IV that is passed back by reference
aesIV = aesAlg.IV;
//get a new RSA crypto service provider to encrypt the AES key with the certificates public key
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider())
{
//add the certificates public key to the RSA crypto provider
rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false));
//encrypt AES key with RSA Public key
//passed back by reference
encryptedAesKey = rsaCSP.Encrypt(aesKey, false);
//get an aes encryptor instance
ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor();
encryptedData = encryptWithAes(aesEncryptor, data);
}
if (encryptedData == null)
throw new CryptographicException(
"Fatal error while encrypting with AES");
return encryptedData;
}
private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) {
MemoryStream memStream = null; // stream to write encrypted data to
CryptoStream cryptoStream = null; // crypto stream to encrypted data
try {
memStream = new MemoryStream();
// initiate crypto stream telling it to write the encrypted data to
// the memory stream
cryptoStream = new CryptoStream(memStream, aesEncryptor,
CryptoStreamMode.Write);
// write the data to the memory stream
cryptoStream.Write(data, 0, data.Length);
} catch (Exception ee) {
// rethrow
throw new Exception("Error while encrypting with AES: ", ee);
} finally {
// close 'em
if (cryptoStream != null)
cryptoStream.Close();
if (memStream != null)
memStream.Close();
}
// return the encrypted data
return memStream.ToArray();
}
C#Net:
// symmetric algorithm for data encryption
final String ALGORITHM = "AES";
// Padding for symmetric algorithm
final String PADDING_MODE = "/CBC/PKCS5Padding";
// character encoding
final String CHAR_ENCODING = "UTF-8";
// provider for the crypto
final String CRYPTO_PROVIDER = "Entrust";
// RSA algorithm used to encrypt symmetric key
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// symmetric key size (128, 192, 256) if using 192+ you must have the Java
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// installed
int AES_KEY_SIZE = 256;
private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// get the public key from the encryption certificate to encrypt with
PublicKey pubKey = cert.getPublicKey();
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
// set the cipher to use the public key
rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);
// encrypt the aesKey
return rsaCipher.doFinal(aesKey);
}
private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException {
// get the symmetric key generator
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(AES_KEY_SIZE); // set the key size
// generate the key
SecretKey skey = keyGen.generateKey();
// convert to binary
byte[] rawAesKey = skey.getEncoded();
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to encrypt mode, with the generated key
aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// get the initialization vector being used (to be returned)
byte[] aesIV = aesCipher.getIV();
// encrypt the data
byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);
// package the aes key, IV, and encrypted data and return them
return new AESEncryptedContents(rawAesKey, aesIV, encryptedData);
}
private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV,
byte[] encryptedData) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
NoSuchProviderException {
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to decrypt mode with the AES key, and IV
aesCipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(aesIV));
// decrypt and return the data
byte[] decryptedData = aesCipher.doFinal(encryptedData);
return decryptedData;
}
private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey)
throws IllegalBlockSizeException, BadPaddingException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, NoSuchProviderException {
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
// set the cipher to use the public key
rsaCipher.init(Cipher.DECRYPT_MODE, privKey);
// encrypt the aesKey
return rsaCipher.doFinal(encryptedAesKey);
}
public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) {
if (data == null)
throw new ArgumentNullException("data");
byte[] encryptedData; // data to return
// begin AES key generation
RijndaelManaged aesAlg = new RijndaelManaged();
aesAlg.KeySize = AES_KEY_SIZE;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
// aes Key to be encrypted
byte[] aesKey = aesAlg.Key;
// aes IV that is passed back by reference
aesIV = aesAlg.IV;
//get a new RSA crypto service provider to encrypt the AES key with the certificates public key
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider())
{
//add the certificates public key to the RSA crypto provider
rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false));
//encrypt AES key with RSA Public key
//passed back by reference
encryptedAesKey = rsaCSP.Encrypt(aesKey, false);
//get an aes encryptor instance
ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor();
encryptedData = encryptWithAes(aesEncryptor, data);
}
if (encryptedData == null)
throw new CryptographicException(
"Fatal error while encrypting with AES");
return encryptedData;
}
private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) {
MemoryStream memStream = null; // stream to write encrypted data to
CryptoStream cryptoStream = null; // crypto stream to encrypted data
try {
memStream = new MemoryStream();
// initiate crypto stream telling it to write the encrypted data to
// the memory stream
cryptoStream = new CryptoStream(memStream, aesEncryptor,
CryptoStreamMode.Write);
// write the data to the memory stream
cryptoStream.Write(data, 0, data.Length);
} catch (Exception ee) {
// rethrow
throw new Exception("Error while encrypting with AES: ", ee);
} finally {
// close 'em
if (cryptoStream != null)
cryptoStream.Close();
if (memStream != null)
memStream.Close();
}
// return the encrypted data
return memStream.ToArray();
}
Java解密代码的最后几行没有意义。这些线路是:
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
您必须颠倒在.NET中用于加密的步骤顺序。首先,您应该对编码的字符串进行Base64解码以获得密码字节。您这样做了,但将结果错误标记为base64String
。您可能应该调用此结果cipherData
。其次,您需要解密密码数据以获得纯文本。第三,您应该使用双参数字符串构造函数从纯字节创建一个字符串,第二个参数为字符集。下面是代码应该是什么样子,或者与之相近
byte[] cipherData = Base64.decode(encodedString);
byte[] plainBytes = cipher.doFinal(cipherData);
return new String(plainBytes, "UTF-8");
最后,在Java中,每个对象都有一个toString()方法,但它并不总是做您想做的事情。对于数组,toString()方法只返回该数组的对象id表示形式,类似于内存地址的JVM
编辑:
我没有注意到您在解密代码中也使用了错误的密钥。您使用的是RSA公钥,但您必须使用RSA私钥。这是我昨天无法发布的答案,与我发布的第一个答案相关
嗯,我已经测试了代码,我有一些问题。我一直试图不改变任何事情,除非它是完全必要的。 首先,我在这里得到一个错误:
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
无法识别“委托”加密提供程序。。。所以我只留下了第一个参数。然后我得到这个错误:
javax.crypto.BadPaddingException: Data must start with zero
我尝试了一个用.NET编写的Web服务,它总是返回字节数组。也许在翻译过程中出现了一些问题。我知道我必须使用Base64数字,并且(如果我不使用AES),我必须将字符串分成128字节大小的片段(受RSA密钥限制)。
我仍在研究这个问题,以了解为什么我可以在Java中加密,在.NET中解密,而不是相反
再次感谢你的帮助 给我们一些堆叠痕迹。是否指定相同的填充方案?我可以在.Net中加密,在Java中解密,反之亦然,没问题。虽然我使用PKCS5Padding(Java)和PKCS7(.Net)并且没有硬编码密钥,但我无法给出任何跟踪,因为我得到的错误是不同的(正如我所说的密钥大小,将异常填充为:javax.crypto.baddingexception:数据必须以零开始)。。。我可以发布不起作用的代码,但我现在正在处理它。如果你能告诉我你是怎么做的,我将非常感激,因为在接下来的几天里解决这个问题对我来说非常重要……非常感谢Petey!我将尝试这段代码……我希望它能工作,并且不会给我任何字节[]到字符串转换的问题。我将尝试调整它(我不使用证书或AES),我将在尝试后尽快发布。再次感谢@Reixons,没问题,如果我能帮忙,请告诉我。你要加密什么?如果它比你的RSA密钥长度长,你应该使用AES+RSA。好吧,我已经测试了代码,我有一些问题。我得到:javax.crypto.BadPaddingException:数据必须从零开始,我将在2h内尝试更好地描述它。我现在没有足够的声誉去做这件事!!:(我使用的是私钥,但为了生成私钥,我使用的模和指数与生成公钥的模和指数相同……对吗?你是对的,我的第一个代码的问题是,我也使用指数生成私钥,我应该使用“D”密钥的一部分。现在它工作了。谢谢大家!!我正在做一些非常类似的事情,但由于解密,我得到了一个空输入缓冲区:java.lang.IllegalArgumentException:空输入缓冲区在代码中的某个地方。我打印了我的私钥,它似乎是这样的:Sun RSA私钥,1024位模数:1711700308465724595132409320104296254162648817557411074899862199275295356525279994079227私人指数:99473302025154625525526734732044759431077578773125948154824200106840847929746840991292557544482314157718836061315811212481我取出了它的一部分,因为它太长了。知道为什么会发生这种情况吗我注意到在做了byte[]cipherData=Base64.decode(encodedString);cipherData为null。为什么会这样?基本上:返回新字符串(cipherData,“UTF-8”);返回null,现在我得到的是:数据必须以零开始:javax.crypto.BadPaddingException:数据必须以零开始
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
javax.crypto.BadPaddingException: Data must start with zero