Вопрос

Пожалуйста, только не спрашивай меня почему.У меня просто есть этот код в .NET, который шифрует / расшифровывает строки данных.Теперь мне нужно сделать "точно" такую же функциональность в java.Я попробовал несколько примеров для DESede crypt, но ни один из них не дает таких же результатов, как этот класс в .net.

Я даже думал о создании .net webserbvice за ssl для обслуживания этих двух методов, написанных на .net, но это просто слишком глупо делать, не исчерпав все возможности.

Возможно, кто-то из вас, java-специалистов, которые больше разбираются в этой области, знает, как это сделать.

Спасибо!!!

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

Одинаковый ввод/вывод

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"
Это было полезно?

Решение

Далее следует код, но сначала несколько замечаний.

  1. Для каждого сообщения должен быть выбран другой вектор инициализации.Жестко кодировать вектор инициализации не имеет смысла.Капельница должна быть отправлена вместе с зашифрованным текстом получателю сообщения (оно не является секретным).
  2. Я использовал свой собственный служебный класс для кодирования base-64.Вы можете использовать sun.misc.BASE64Encoder и sun.misc.BASE64Decoder вместо этого используйте стороннюю библиотеку, такую как BouncyCastle, или напишите свою собственную.
  3. Вы используете двухклавишный triple DES, где первая клавиша и третья клавиша одинаковы.Я изменил sharedkey чтобы отразить это, поскольку шифр Java DESede всегда требует 192-битного ключа;обрабатывать опцию ввода ключа должен генератор ключей.
  4. CBC IV состоит всего из 64 бит.Я использовал только первые 64 бита sharedvector.

Этот класс должен взаимодействовать с версией 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");
  }

}

Выходной сигнал:

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

Имя пользователя здесь: Пароль здесь

Другие советы

У тебя есть несколько проблем,

  1. Ваш ключ должен быть размером 24 байта, если вы хотите сгенерировать одинаковые ключевые материалы для обоих.NET и Java.
  2. IV должен иметь размер блока, равный 8 байтам для Triple DES.
  3. В Java вам нужно указать режим по умолчанию и заполнение, которое является "DESede /CBC/NoPadding".

Как только вы внесете эти изменения, вы сможете расшифровать их на стороне Java.

Вы убедились, что в коде .NET используется то же заполнение, что и в коде Java?Я не вижу отступов , указанных в .ЧИСТЫЙ код, вот почему я спрашиваю.

У вас случайно нет исходного кода Java, это поможет найти ошибки.

Попробуйте следующее.Для реального использования я бы получил библиотеку base64, такую как commons codec, или использовал кодек, который поставляется с 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)));
    }

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top