Эквивалент .NET TripleDESCryptoServiceProvider в Java
-
05-07-2019 - |
Вопрос
Пожалуйста, только не спрашивай меня почему.У меня просто есть этот код в .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"
Решение
Далее следует код, но сначала несколько замечаний.
- Для каждого сообщения должен быть выбран другой вектор инициализации.Жестко кодировать вектор инициализации не имеет смысла.Капельница должна быть отправлена вместе с зашифрованным текстом получателю сообщения (оно не является секретным).
- Я использовал свой собственный служебный класс для кодирования base-64.Вы можете использовать
sun.misc.BASE64Encoder
иsun.misc.BASE64Decoder
вместо этого используйте стороннюю библиотеку, такую как BouncyCastle, или напишите свою собственную. - Вы используете двухклавишный triple DES, где первая клавиша и третья клавиша одинаковы.Я изменил
sharedkey
чтобы отразить это, поскольку шифр Java DESede всегда требует 192-битного ключа;обрабатывать опцию ввода ключа должен генератор ключей. - 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=
Имя пользователя здесь: Пароль здесь
Другие советы
У тебя есть несколько проблем,
- Ваш ключ должен быть размером 24 байта, если вы хотите сгенерировать одинаковые ключевые материалы для обоих.NET и Java.
- IV должен иметь размер блока, равный 8 байтам для Triple DES.
- В 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)));
}
}