RSA .NET加密Java解密

我试图通过使用RSA算法加密.NET中的字符串并在Java中解密结果。 目前,我已经能够做相反的事情(在Java中加密,在.NET中解密)。 在这里,我有我的代码实际工作(JAVA加密):

byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8="); byte[] exponentBytes = Base64.decode("AQAB"); BigInteger modulus = new BigInteger(1, modulusBytes ); BigInteger exponent = new BigInteger(1, exponentBytes); RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent); KeyFactory fact = KeyFactory.getInstance("RSA"); PublicKey pubKey = fact.generatePublic(rsaPubKey); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8"); byte[] cipherData = cipher.doFinal( plainBytes ); String encryptedString = Base64.encode(cipherData); return encryptedString; 

和(.NET解密)

 const int PROVIDER_RSA_FULL = 1; const string CONTAINER_NAME = "Tracker"; CspParameters cspParams; cspParams = new CspParameters(PROVIDER_RSA_FULL); cspParams.KeyContainerName = CONTAINER_NAME; RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams); rsa1.FromXmlString("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=AQAB

+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==

yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE="); string data2Decrypt = "BaB21vY+RD/jiY3AAsb269fIWTEH38s0xLUfJ7CoVUgaQ6vYzB0tiJ1Ag9HNEdCcuZdGchhqnms8jpsqsHC1iKrz6QCLsgUU7VNWDfQqZYR6Rl/GwR0biK2STnOL+g06f/JUdixHOHOgROify1m8qppYo5plpOVMqYFzEMREMkM="; byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt); byte[] plain = rsa1.Decrypt(encyrptedBytes, false); string decryptedString = System.Text.Encoding.UTF8.GetString(plain); Console.WriteLine("SALIDA: " + decryptedString);

现在我想做相反的事情…但我得到一些错误(密钥的大小应该是128字节……等)我应该怎么做?

在这里,我添加了当前的非工作代码:

。净

 public string Encrypt(string text) { const int PROVIDER_RSA_FULL = 1; const string CONTAINER_NAME = "Tracker"; CspParameters cspParams; cspParams = new CspParameters(PROVIDER_RSA_FULL); cspParams.KeyContainerName = CONTAINER_NAME; RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams); rsa1.FromXmlString("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=AQAB

92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==

4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k="); System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] textBytes = encoding.GetBytes(text); byte[] encryptedOutput = rsa1.Encrypt(textBytes, false); string outputB64 = Convert.ToBase64String(encryptedOutput); Console.WriteLine(outputB64); return outputB64; }

Java的

 public static String Decrypt(String encodedString) throws IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException { byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8="); byte[] exponentBytes = Base64.decode("AQAB"); BigInteger modulus = new BigInteger(1, modulusBytes ); BigInteger exponent = new BigInteger(1, exponentBytes); RSAPrivateKeySpec rsaPrivKey = new RSAPrivateKeySpec(modulus, exponent); KeyFactory fact = KeyFactory.getInstance("RSA"); PrivateKey privKey = fact.generatePrivate(rsaPrivKey); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privKey); 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(); } 

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 。 其次,您需要解密cipherData以获取纯文本。 第三,你应该使用带有Charset的two-arg String构造函数为第二个参数从plainbytes创建一个字符串。 这是代码应该是什么样的,或接近它。

 byte[] cipherData = Base64.decode(encodedString); byte[] plainBytes = cipher.doFinal(cipherData); return new String(plainBytes, "UTF-8"); 

最后,在Java中,每个对象都有一个toString()方法,但它并不总能做到你想要的。 对于数组,toString()方法只返回该数组的对象id的表示,类似于内存地址的JVM。

编辑:

我错过了你在解密代码中也使用了错误的密钥。 您正在使用RSA公钥,但您必须使用RSA私钥。

正如您所要求的那样是一些代码片段。 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); } 

C#.Net:

 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(); } 

这是我昨天无法发布的答案,与我的post的第一个答案有关。

好吧,我测试了代码,我遇到了一些问题。 除非完全有必要,否则我试图不改变任何东西。 首先我在这里得到一个错误:

 Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER); 

“Entrust”加密提供程序无法识别……所以我只留下了第一个参数。 然后我收到这个错误:

 javax.crypto.BadPaddingException: Data must start with zero 

我已经尝试过用.NET编写的WebService,它总是返回字节数组。 也许翻译中存在某种问题。 我知道我必须使用Base64号码(如果我不使用AES),我必须将我的字符串分成128字节大小的片段(受RSA密钥限制)。 我仍然在研究这个问题,以便了解为什么我可以用Java加密并在.NET中解密而不是相反。

再次感谢你的帮助!!