2011-07-04 178 views
13

我想通过使用RSA算法来加密.NET中的字符串并在Java中解密结果。目前,我可以做相反的事情(Java加密,.NET解密)。 这里我有我的代码,实际工作(JAVA加密):RSA .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("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>"); 

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字节...等)我应该怎么做?

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

.NET

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("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==</P><Q>4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==</Q><DP>5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==</DP><DQ>j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==</DQ><InverseQ>8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==</InverseQ><D>MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k=</D></RSAKeyValue>"); 

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

给我们一些堆栈跟踪。你是否指定了相同的填充方案?我可以在Java中进行.Net解密加密,反之亦然,没问题。尽管我使用PKCS5Padding(Java)和PKCS7(.Net),并且不用硬编码密钥。 –

+0

我不能给任何跟踪,因为我得到的错误是不同的(正如我所说的键的大小,填充异常为:javax.crypto.BadPaddingException:数据必须以零开始)...我可以发布的代码不工作,但我现在正在努力。如果你可以请你发表你的意见,我将非常感激,因为这对我来说很重要,在接下来的几天里解决这个问题...... – Reixons

回答

8

最后的你的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的双参数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私钥。

+0

我使用的是私钥,但为了生成它,我使用了相同的模数和指数来生成公有的一个......是不是正确? – Reixons

+0

你说的对,我的第一个问题代码是,我也使用指数来生成私钥,我应该使用密钥的“D”部分。现在它的工作。谢谢大家!! – Reixons

+0

我做的事情非常相似,但由于解密,我得到一个空输入缓冲区:java.lang.IllegalArgumentException:空输入缓冲区代码中的某处。我打印出我的私钥,它似乎是这样的:Sun RSA私钥,1024位 模数:17117003084657245951324093201042962541622648817557411074899862199275295356525279994079227 私人指数:9947330202515462552673473204475943107757877312593094815482420010684084799297468584099129255754448231415771883606131 58181121242481因为它太长,我拿出了它的一部分。任何想法,为什么发生这种情况 – c0d3Junk13

1

根据你的要求是野兔一些代码片段。 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(); 
} 
+0

非常感谢Petey!我将尝试代码...我希望它能够正常工作,并且不会给字节[]字符串转换带来任何问题。我会尽量适应它(我不使用证书或AES),我会尽快发布。再次感谢! – Reixons

+0

@Reixons,没问题,让我知道我是否可以帮忙。你会加密什么?如果它比你的RSA密钥长度长,你应该使用AES + RSA。 –

+0

那么,我已经测试了代码,并且遇到了一些问题。我得到:javax.crypto.BadPaddingException:数据必须以零开头我会在2小时内更好地描述它。我现在没有足够的声誉去做! :( – Reixons

0

以下是我昨天无法发布的答案,与我的文章的第一个答案有关。

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

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

的“委托”加密提供商无法识别......所以,我离开只是第一个参数。然后我得到这个错误:

javax.crypto.BadPaddingException: Data must start with zero 

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

再次感谢您的帮助!