所以我有一些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;
}
有问题的主要代码是这样的:
加密
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 字节发送的数据,显然 NewtonsoftJSON 无法通过使用 byte[] 正确反序列化它,因此我使用了 sbyte[]。事情是解密代码需要一个字节[],我尝试通过强制转换和 Convert.ToByte() 将 sbyte[] 转换为字节,但没有一个有效。我得到的最接近的是将 sbyte 转换为 byte 但是在运行 new byte[] 时transform.TransformFinalBlock(cipherText, 0, cipherText.Length)
我得到一个格式错误的填充异常,即使我在两者上都使用 PCKS7 填充(特别是 Java 上的 PCKS5)