Итак, у меня есть код в Java для шифрования и дешифрования объектов, и я пытался сделать то же самое в C#, чтобы мой сервер и клиент могли расшифровывать и шифровать сообщения. Я получил большую часть его для работы, за исключением того, что я пропускаю только ключевые параметры для Java.
@RequiredArgsConstructor
@Getter
public class EncryptedBytes {
private final byte[] data;
private final byte[] params;
private final String paramAlgorithm;
}
/**
* Encrypt object with password
*
* @param data Object to be encrypted
* @param secret Password to use for encryption
* @return Encrypted version of object
*/
public static EncryptedBytes encrypt(String data, SecretKey secret) throws InvalidKeyException {
try {
Cipher cipher = Cipher.getInstance(StaticHandler.AES_CIPHER_TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secret);
// properly encode the complete ciphertext
//logEncrypt(password, object);
byte[] encodedData = cipher.doFinal(data.getBytes(StaticHandler.CHARSET_FOR_STRING));
byte[] params = cipher.getParameters().getEncoded();
String paramAlgorithm = cipher.getParameters().getAlgorithm();
return new EncryptedBytes(encodedData, params, paramAlgorithm);
} catch (InvalidKeyException e) {
throw e;
} catch (NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException | BadPaddingException | IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Decrypt data with secret
*
* @param encryptedBytes Object to be decrypted
* @param secret Password to use for decryption
* @return Decrypted version of object
*/
public static String decrypt(EncryptedBytes encryptedBytes, @NonNull SecretKey secret) throws InvalidKeyException {
try {
// get parameter object for password-based encryption
AlgorithmParameters algParams = AlgorithmParameters.getInstance(encryptedBytes.getParamAlgorithm());
if (algParams == null) throw new IllegalArgumentException("EncryptedBytes.Parameters are not valid");
// initialize with parameter encoding from above
algParams.init(encryptedBytes.getParams());
Cipher cipher = Cipher.getInstance(StaticHandler.AES_CIPHER_TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secret, algParams);
return new String(cipher.doFinal(encryptedBytes.getData()), StaticHandler.CHARSET_FOR_STRING);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | IOException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}
Теперь в C# у меня есть очень близкая реализация к коду Java выше. Я пропускаю только данные параметров для Java.
public class EncryptedBytes
{
public List<byte> data { get; }
[JsonProperty("params")]
[JsonPropertyName("params")]
public List<byte> keyParams { get; }
public string paramAlgorithm { get; }
public EncryptedBytes(IEnumerable<byte> data, IEnumerable<byte> keyParams, string paramAlgorithm)
{
this.data = data.ToList();
this.keyParams = keyParams.ToList();
this.paramAlgorithm = paramAlgorithm;
}
}
public static EncryptedBytes encrypt(AesCryptoServiceProvider aesCryptoServiceProvider, string plainText,
Encoding encoding)
{
if (encoding == null) encoding = StaticHandler.encoding;
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (aesCryptoServiceProvider.Key == null || aesCryptoServiceProvider.Key.Length <= 0)
throw new ArgumentNullException("Key");
if (aesCryptoServiceProvider.IV == null || aesCryptoServiceProvider.IV.Length <= 0)
throw new ArgumentNullException("IV");
ICryptoTransform transform = aesCryptoServiceProvider.CreateEncryptor();
return encrypt(transform, /* find paramater here */, plainText, encoding);
}
public static EncryptedBytes encrypt(ICryptoTransform transform, byte[] par, string plainText, Encoding encoding)
{
if (encoding == null) encoding = StaticHandler.encoding;
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException(nameof(plainText));
var encodedText = encoding.GetBytes(plainText);
var encryptedText =
transform.TransformFinalBlock(encodedText, 0, encodedText.Length);
return new EncryptedBytes(encryptedText, par, "AES");
}
public static string decrypt(EncryptedBytes encryptedBytes, AesCryptoServiceProvider aesCryptoServiceProvider, Encoding? encoding)
{
if (encoding == null) encoding = StaticHandler.encoding;
byte[] cipherText = encryptedBytes.data.ToArray();
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (aesCryptoServiceProvider.Key == null || aesCryptoServiceProvider.Key.Length <= 0)
throw new ArgumentNullException("Key");
if (aesCryptoServiceProvider.IV == null || aesCryptoServiceProvider.IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
ICryptoTransform transform = aesCryptoServiceProvider.CreateDecryptor();
var plaintext = encoding.GetString(transform.TransformFinalBlock(cipherText, 0, cipherText.Length));
return plaintext;
}
Основной код, о котором идет речь:
encrypt
ICryptoTransform transform = aesCryptoServiceProvider.CreateEncryptor();
return encrypt(transform, /* find paramater here */, plainText, encoding);
и расшифровывает
ICryptoTransform transform = aesCryptoServiceProvider.CreateDecryptor();
var plaintext = encoding.GetString(transform.TransformFinalBlock(cipherText, 0, cipherText.Length));
return plaintext;
Мне нужен способ получить ключевые параметры для Java, чтобы использовать их для расшифровки и использовать параметры java для расшифровки в C#, если необходимо.
Редактировать
Хорошо, у меня работает шифрование. Теперь мне нужно, чтобы расшифровка работала. Проблема в том, что для расшифровки используются данные, отправленные Java байтами, и, очевидно, Newtonsoft JSON не может десериализовать их должным образом, используя byte [], поэтому вместо этого я использую sbyte []. Дело в том, что для расшифровки кода требуется байт [], и я попытался привести и преобразовать sbyte [] в байты с помощью приведения и Convert.ToByte (), и ни один из них не сработал. Самое близкое, что я получил, это приведение sbyte к байту, однако при запуске нового байта [] с transform.TransformFinalBlock(cipherText, 0, cipherText.Length)
я получаю исключение искаженного заполнения, даже если я использую заполнение PCKS7 на обоих (а точнее PCKS5 на Java)