2011-07-04 31 views
13

Estoy tratando de encriptar cadenas en .NET usando un algoritmo RSA y descifrar el resultado en Java. Por el momento, he podido hacer lo contrario (cifrar en Java, descifrar en .NET). Aquí tengo mi código que realmente funciona (cifrado JAVA):Encriptación RSA .NET Descifrado 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; 

Y (descifrado .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); 

Ahora quiero hacer lo contrario ... pero me da algunos errores como (el tamaño de la clave debe ser de 128 bytes ... etc.) ¿Cómo debo hacerlo?

Aquí añado el vigente código no trabaja:

.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

Danos algunos rastros de pila. ¿Estás especificando los mismos esquemas de relleno? Puedo encriptar en .Net descifrar en Java, y viceversa, no hay problema. Aunque utilizo PKCS5Padding (Java) y PKCS7 (.Net) y no cifro las claves. –

+0

No puedo dar ningún rastro porque los errores que obtengo varían (como dije el tamaño de la clave, excepciones de relleno como: javax.crypto.BadPaddingException: los datos deben comenzar con cero) ... Puedo publicar el código que no lo hace trabajo, pero estoy trabajando en eso ahora. Si pudieras por favor publicar cómo lo haces, estaría muy agradecido porque es importante para mí resolver este problema en los próximos días ... – Reixons

Respuesta

8

Las últimas líneas de su código de descifrado de Java no tienen sentido. Estas líneas son:

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

Debe invertir el orden de los pasos que utilizó para encriptar en .NET. En primer lugar, debe decodificar Base64 la cadena codificada para obtener los bytes de cifrado. Hiciste eso, pero etiquetaste erróneamente el resultado como base64String. Probablemente deberías llamar a este resultado cipherData. En segundo lugar, debe descifrar el cifrado de datos para obtener texto sin formato. En tercer lugar, debe crear una cadena de plainbytes utilizando el constructor de cadenas two-arg con Charset para el segundo argumento. Aquí es cómo debería ser el código, o cerca de él.

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

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

Por último, en Java Cada objeto tiene un método toString(), pero no siempre hace lo que quiere. Para las matrices, el método toString() simplemente devuelve una representación de id de objeto para esa matriz, una especie del equivalente de JVM de una dirección de memoria.

EDIT:

me perdí también está usando la tecla equivocada en el código de descifrado. Está utilizando la clave pública RSA, pero en su lugar debe usar la clave privada RSA.

+0

Estoy usando la clave privada pero para generarla, estoy usando el mismo módulo y exponente que uso para generar el público ... ¿no es correcto? – Reixons

+0

tenías razón, el problema con mi primera El código era que también estaba usando el exponente para generar la clave privada y debería usar la parte "D" de la clave. Ahora funciona. ¡Gracias a todos! – Reixons

+0

Estoy haciendo algo muy similar, pero como resultado del descifrado, me estoy poniendo un buffer de entrada nula: java.lang.IllegalArgumentException:. buffer de entrada nulo en algún lugar del código imprimí mi clave privada y parece ser algo como esto: clave privada RSA Sun, 1024 bits módulo: 17117003084657245951324093201042962541622648817557411074899862199275295356525279994079227 Exponente privado: 9947330202515462552673473204475943107757877312593094815482420010684084799297468584099129255754448231415771883606131 58181121242481 Saqué partes porque era demasiado largo. Alguna idea de por qué sucede esto – c0d3Junk13

1

A medida que se solicitan son liebre algunos fragmentos de código. Las claves RSA son de x509 certs.

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

Muchas gracias Petey! Voy a probar el código ... Espero que funcione y no me da ningún problema con el byte [] para la conversión de cadenas. Intentaré adaptarlo (no estoy usando certs o AES) y publicaré algo tan pronto como lo intente. ¡Gracias de nuevo! – Reixons

+0

@Reixons, no hay problema, avíseme si puedo ayudarlo. ¿Qué vas a estar encriptando? Si es más largo que la longitud de su clave RSA, debe usar AES + RSA. –

+0

Bueno, he probado el código y tengo algunos problemas. Obtengo: javax.crypto.BadPaddingException: los datos deben comenzar con cero. Trataré de describirlo mejor en 2 h. ¡No tengo suficiente reputación para hacerlo ahora! :( – Reixons

0

Aquí está la respuesta que no pude publicar ayer, relacionada con la primera respuesta a mi publicación.

Bueno, he probado el código y tengo algunos problemas. Intenté no cambiar nada a menos que fuera completamente necesario. En primer lugar me sale un error aquí:

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

El proveedor de cifrado "Entrust" no se reconoce ... Así que queda sólo el primer parámetro. Entonces me sale este error:

javax.crypto.BadPaddingException: Data must start with zero 

He tratado a través de un servicio web escrito en .NET que devuelve siempre matrices de bytes. Tal vez haya algún tipo de problema en la traducción. Sé que tengo que usar números Base64 y (si no uso AES) tengo que dividir mis cadenas en pedazos con un tamaño de 128 bytes (limitado por la clave RSA). Todavía estoy trabajando en el problema para darme cuenta de por qué podría cifrar en Java y descifrar en .NET, pero no lo contrario.

Gracias de nuevo por su ayuda !!

Cuestiones relacionadas