Pregunta

Por favor, no me preguntes por qué. Solo tengo este código en .NET que encripta / desencripta cadenas de datos. Ahora necesito hacer 'exactamente' la misma funcionalidad en Java. He probado varios ejemplos para la cripta DESede, pero ninguno de ellos da los mismos resultados que esta clase en .net.

Aunque hice un servicio web .net detrás de ssl para servir estos dos métodos escritos en .net, pero es demasiado estúpido hacerlo sin agotar todas las posibilidades.

Tal vez algunas de ustedes, personas de Java que están más relacionadas en el área, tengan en sus cabezas cómo hacerlo.

¡Gracias!

public class Encryption
{
  private static byte[] sharedkey = {...};
  private static byte[] sharedvector = {...};

  public static String Decrypt(String val)
  {
    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    byte[] toDecrypt = Convert.FromBase64String(val);
    MemoryStream ms = new MemoryStream();
    CryptoStream cs = new CryptoStream(ms, tdes.CreateDecryptor( sharedkey, sharedvector ), CryptoStreamMode.Write);

    cs.Write(toDecrypt, 0, toDecrypt.Length);
    cs.FlushFinalBlock();
    return Encoding.UTF8.GetString(ms.ToArray());
  }

  public static String Encrypt(String val)
  {
    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    byte[] toEncrypt = Encoding.UTF8.GetBytes(val);
    MemoryStream ms = new MemoryStream();
    CryptoStream cs = new CryptoStream(ms, tdes.CreateEncryptor( sharedkey, sharedvector ), CryptoStreamMode.Write);
    cs.Write(toEncrypt, 0, toEncrypt.Length);
    cs.FlushFinalBlock();
    return Convert.ToBase64String(ms.ToArray());
  }
}

Samle entrada / salida

String plain = "userNameHere:passwordHere";
Console.WriteLine("plain: " + plain);


String encrypted = Encrypt(plain);
Console.WriteLine("encrypted: " + encrypted);
// "zQPZgQHpjxR+41Bc6+2Bvqo7+pQAxBBVN+0V1tRXcOc="

String decripted = Decrypt(encrypted);
Console.WriteLine("decripted: " + decripted); 
// "userNameHere:passwordHere"
¿Fue útil?

Solución

El código sigue, pero primero unas pocas notas.

  1. Se debe elegir un vector de inicialización diferente para cada mensaje. Codificar el vector de inicialización no tiene sentido. El IV debe enviarse junto con el texto cifrado al destinatario del mensaje (no es secreto).
  2. Usé mi propia clase de utilidad para la codificación de base 64. En su lugar, puede usar sun.misc.BASE64Encoder y sun.misc.BASE64Decoder , usar una biblioteca de terceros como BouncyCastle o escribir la suya propia.
  3. Está utilizando un DES triple de 2 teclas, donde la primera y la tercera son las mismas. Modifiqué sharedkey para reflejar esto, ya que el cifrado Java DESede siempre requiere una clave de 192 bits; depende del generador de claves manejar la opción de codificación.
  4. Un CBC IV tiene solo 64 bits. Solo he usado los primeros 64 bits de sharedvector .

Esta clase debe interactuar con la versión de C #.

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Encryption
{

  private static byte[] sharedkey = {
    0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11, 
    0x12, 0x11, 0x0D, 0x0B, 0x07, 0x02, 0x04, 0x08, 
    0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11
  };

  private static byte[] sharedvector = {
    0x01, 0x02, 0x03, 0x05, 0x07, 0x0B, 0x0D, 0x11
  };

  public static void main(String... argv)
    throws Exception
  {
    String plaintext = "userNameHere:passwordHere";
    String ciphertext = encrypt(plaintext);
    System.out.println(ciphertext);
    System.out.println(decrypt(ciphertext));
  }

  public static String encrypt(String plaintext)
    throws Exception
  {
    Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new IvParameterSpec(sharedvector));
    byte[] encrypted = c.doFinal(plaintext.getBytes("UTF-8"));
    return Base64.encode(encrypted);
  }

  public static String decrypt(String ciphertext)
    throws Exception
  {
    Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sharedkey, "DESede"), new IvParameterSpec(sharedvector));
    byte[] decrypted = c.doFinal(Base64.decode(ciphertext));
    return new String(decrypted, "UTF-8");
  }

}

Salida:

  

zQPZgQHpjxR + 41Bc6 + 2Bvqo7 + pQAxBBVN + 0V1tRXcOc =

     

userNameHere: passwordHere

Otros consejos

Tienes algunos problemas,

  1. Su clave debe ser de 24 bytes si desea generar los mismos materiales clave en .NET y Java.
  2. El IV debe tener un tamaño de bloque, que es de 8 bytes para Triple DES.
  3. En Java, debe especificar el modo predeterminado y el relleno, que es "DESede / CBC / NoPadding".

Una vez que realice estos cambios, debería poder descifrarlos en el lado de Java.

¿Se ha asegurado de que el código .NET use el mismo relleno que el código Java? No veo ningún relleno especificado en el código .NET, por eso pregunto.

¿Tiene la fuente del código Java? Le ayudará a encontrar errores.

Pruebe lo siguiente. Para uso real, obtendría una biblioteca base64 como el códec commons o usaría el códec que viene con BouncyCastle

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

public class Encryption {

    private static SecretKey sharedkey;
    private static byte [] sharedvector;

    static {
        int keySize = 168;
        int ivSize = 8;
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            keyGenerator.init(keySize);
            sharedkey = keyGenerator.generateKey();

            sharedvector = new byte [ivSize];
            byte [] data = sharedkey.getEncoded();

            int half = ivSize / 2;
            System.arraycopy(data, data.length-half, sharedvector, 0, half);
            System.arraycopy(sharedvector, 0, sharedvector, half, half);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static void main(String [] args) throws Exception {
        System.out.println(Decrypt(Encrypt("Hello World")));

    }

    public static String Encrypt(String val) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));

        return new sun.misc.BASE64Encoder().encode(cipher.doFinal(val.getBytes()));
    }

    public static String Decrypt(String val) throws GeneralSecurityException, IOException {
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, sharedkey, new IvParameterSpec(sharedvector));

        return new String(cipher.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(val)));
    }

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top