2011-07-04 14 views
13

Próbuję szyfrować ciągi w .NET przy użyciu algorytmu RSA i odszyfrować wynik w Javie. W tej chwili byłem w stanie zrobić coś odwrotnego (Zaszyfruj w Javie, Odszyfruj w .NET). Tutaj mam kod, który faktycznie działa (szyfrowanie Java):Szyfrowanie RSA .NET Szyfrowanie 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; 

I (.NET deszyfrowanie)

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

Teraz chcę zrobić odwrotnie ... Ale mam pewne błędy, takie jak (rozmiar klucza powinien wynosić 128 bajtów ... itd.) Jak mam to zrobić?

Tu dodam aktualny kod zakaz pracy:

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

Daj nam trochę śladów stosu. Czy określasz te same schematy wypełnienia? Jestem w stanie zaszyfrować w .Net odszyfrować w Javie i na odwrót, nie ma problemu. Chociaż używam PKCS5Padding (Java) i PKCS7 (.Net) i nie twarde klucze kodu. –

+0

Nie mogę podać żadnego śladu, ponieważ otrzymywane przeze mnie błędy są różne (jak powiedziałem, rozmiar klucza, wyściełane wyjątki jako: javax.crypto.BadPaddingException: dane muszą zaczynać się od zera) ... Mogę opublikować kod, który nie jest pracuję, ale teraz nad tym pracuję. Jeśli mógłbyś napisać, jak to robisz, byłbym bardzo wdzięczny, ponieważ jest to dla mnie ważne, aby rozwiązać ten problem w ciągu najbliższych kilku dni ... – Reixons

Odpowiedz

8

ostatnie kilka linijek kodu Java swojej odszyfrować nie ma sensu. Te linie to:

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

Musisz odwrócić kolejność kroków użytych do zaszyfrowania w .NET. Po pierwsze, powinieneś Base64 dekodować zakodowany ciąg, aby uzyskać bajty szyfrów. Zrobiłeś to, ale błędnie oznaczono wynik jako base64String. Prawdopodobnie powinieneś nazwać ten wynik cipherData. Po drugie, musisz odszyfrować dane cipherData, aby uzyskać zwykły tekst. Po trzecie, powinieneś utworzyć ciąg znaków z plainbytes przy użyciu konstruktora String dwóch argumentów z zestawem znaków dla drugiego argumentu. Oto, jak powinien wyglądać kod lub w jego pobliżu.

byte[] cipherData = Base64.decode(encodedString); 
byte[] plainBytes = cipher.doFinal(cipherData); 

return new String(plainBytes, "UTF-8"); 

Wreszcie w Javie każdy przedmiot ma metodę toString(), ale nie zawsze to, co chcesz. W przypadku tablic metoda toString() zwraca po prostu reprezentację identyfikatora obiektu dla tej tablicy, sortując odpowiednik JVM adresu pamięci.

EDIT:

brakowało mi, że jesteś również za pomocą niewłaściwego klucza w kodzie odszyfrować. Korzystasz z klucza publicznego RSA, ale zamiast tego musisz użyć klucza prywatnego RSA.

+0

Używam klucza prywatnego, ale aby go wygenerować, używam tego samego modułu i wykładnika, którego używam do generowania publicznego ... czy to nie prawda? – Reixons

+0

miałeś rację, problem z moim pierwszym kod był taki, że używałem także wykładnika do generowania klucza prywatnego i powinienem użyć części klucza "D" Teraz działa. Dziękuję wszystkim! – Reixons

+0

Robię coś bardzo podobnego, ale w wyniku odszyfrowania, dostaję Null bufor wejściowy: java.lang.IllegalArgumentException. bufor wejściowy Null gdzieś w kodzie mam wydrukowane mój klucz prywatny i wydaje się być coś takiego: Sun RSA klucz prywatny, 1024 bitów moduł: 17117003084657245951324093201042962541622648817557411074899862199275295356525279994079227 prywatny wykładnik: 9947330202515462552673473204475943107757877312593094815482420010684084799297468584099129255754448231415771883606131 58181121242481 Wyjąłem jego część, ponieważ była zbyt długa. Każdy pomysł, dlaczego tak się dzieje – c0d3Junk13

1

Jak zwróciła się zając niektóre fragmenty kodu. Klucze RSA pochodzą z certyfikatów 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

Wielkie dzięki Petey! Mam zamiar wypróbować kod ... Mam nadzieję, że to działa i nie daje mi żadnych problemów z bajtem [] do konwersji ciągów. Spróbuję to zaadaptować (nie używam certyfikatów lub AES) i opowiem coś, jak tylko spróbuję. Dzięki jeszcze raz! – Reixons

+0

@ Reixons, bez problemu, daj mi znać, jeśli mogę w ogóle pomóc. Co będziesz szyć? Jeśli jest dłuższy niż długość klucza RSA, powinieneś użyć AES + RSA. –

+0

Cóż, testowałem kod i mam pewne problemy. Otrzymuję: javax.crypto.BadPaddingException: dane muszą zaczynać się od zera. Postaram się opisać je lepiej za 2 godziny. Nie mam dość reputacji, aby to zrobić teraz !! :( – Reixons

0

Oto odpowiedź, której nie mogłem opublikować wczoraj, związaną z pierwszą odpowiedzią na mój wpis.

Cóż, testowałem kod i mam pewne problemy. Starałem się nie zmieniać niczego, chyba że było to absolutnie konieczne. Najpierw pojawia się błąd tutaj:

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

W „Powierzenie” usługodawca kryptograficzny nie jest rozpoznawana ... Więc zostawiłem tylko pierwszy parametr. Następnie pojawia się ten błąd:

javax.crypto.BadPaddingException: Data must start with zero 

Próbowałem przez WebService napisany w .NET, który zwraca zawsze tablice bajtowe. Może jest jakiś problem z tłumaczeniem. Wiem, że muszę używać liczb Base64 i (jeśli nie używam AES), muszę rozbić Struny na kawałki o rozmiarze 128 bajtów (ograniczone przez klucz RSA). Nadal pracuję nad problemem, aby zrozumieć, dlaczego mogłem zaszyfrować w Javie i odszyfrować w .NET, ale nie odwrotnie.

Jeszcze raz dziękuję za pomoc!