0

所以我有一些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)

4

0 回答 0