简体   繁体   English

.Net AES在Java上解密后加密不匹配

[英].Net AES encrypt mismatch after decrypt on Java

I have to send the AES encrypted json as content to web server.我必须将 AES 加密的 json 作为内容发送到 Web 服务器。 But after decryption, the content has extra trash symbols appeared at the beggining of the line.但解密后,内容有多余的垃圾符号出现在行首。

My test method creates the object that is serialized and being send:我的测试方法创建了被序列化并被发送的对象:

[TestMethod]
        public void SendModeChangeWorksAsExpected()
        {
            var snpashot2Send = new ModeChangedReport
            {
                
                ControlWorkMode = ModeEnumeration.Stopped,
                //Controls
                ControlDate = DateTime.Now,
                IsSent = false,
                SentTime = null,
                ReportType = ReportType.ModeChanged,

                Line = new Line
                {
                    AgencyId = "a799eb4f-86da-4af1-a221-9ed8b741b5ce"
                }
            };

            //Создаём шифрованное значение
            var encryptedString = _agencyReportEncriptingTranslator.ConvertModeChange2CypheredString(snpashot2Send);
            //Отправляем в Агентство и получаем результат
            var value = _agencyClient.SendModeChangeReport(encryptedString);
        }

Here are the serialization and encrypt methods:以下是序列化和加密方法:

public string ConvertModeChange2CypheredString(ModeChangedReport report)
        {
            if (report == null) throw new ArgumentNullException(nameof(report));

            //obj to json
            var json = new ModeChangedReportJson
            {
                LineId = report.Line.AgencyId,
                Mode = CreateModeFromIktToUzbekistan(report.ControlWorkMode),
                ActionDate = ConvertDateToAgencyString(report.ControlDate)
            };

            //Serialization
            var retString = _agencyJsonSerializer.SerializeReport2Json(json);

            //Шифруем сериализованный json
            var cypheredValue = _encryptionService.EncryptString(retString);
            return cypheredValue;
        }

Encrypt method:加密方法:

public string EncryptString(string plaintext)
        {
            var plainTextBytes = Encoding.UTF8.GetBytes(plaintext);
            var cypheredTextBytes = Encrypt(plainTextBytes);
            var converted2Base64Value = Convert.ToBase64String(cypheredTextBytes);
            return converted2Base64Value;
        }

private byte[] Encrypt(byte[] bytes)
        {
            #region Args Validation

            if (bytes == null || bytes.Length < 1)
            {
                throw new ArgumentException("Invalid bytes to encrypt");
            }

            if (_key == null || _key.Length < 1)
            {
                throw new InvalidOperationException("Invalid encryption key");
            }


            #endregion

            byte[] encrypted;

            try
            {
                using (AesManaged aes = new AesManaged())
                {
                    aes.Key = _key;
                    aes.IV = _iv;
                    aes.Padding = PaddingMode.PKCS7;
                    aes.Mode = CipherMode.CBC;

                    ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, _iv);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        ms.Write(aes.IV, 0, aes.IV.Length);
                        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                        {
                            cs.Write(bytes, 0, bytes.Length);
                        }
                        encrypted = ms.ToArray();
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }

            return encrypted;
        }

Http client send method: Http客户端发送方法:

public bool SendModeChangeReport(string cypheredValue)
        {
            var token = GetAccessToken();

            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AuthorizationToken);
                client.DefaultRequestHeaders.Add("DEVICE_ID", _agencyAppSettings.DeviceId);

                var content2Post = new StringContent(cypheredValue, Encoding.UTF8, "application/json");
                using (var response = client.PostAsync(_agencyAppSettings.SendModeChangedReportUrl, content2Post).Result)
                {
                    string tokenResponse = null;
                    try
                    {
                        tokenResponse = response.Content.ReadAsStringAsync().Result;
                        response.EnsureSuccessStatusCode();
                        return true;
                    }
                    catch (Exception ex)
                    {
                        _eventLogManager.LogError("При попытке отправить отчёт о смене режима, произошла ошибка: "
                            + $"Код: {response.StatusCode}. Контент: {tokenResponse}. Ошибка: {ex.Message}.");
                        return false;
                    }
                }
            }
        }

But after decryption on receiving server, the string grows with extra trash characters at the begining, like G���h R��EQ�Z {"lineid":"a799eb4f-86da-4af1-a221-9ed8b741b5ce"...但是在接收服务器上解密后,字符串在开始时会增加额外的垃圾字符,例如 G���h R��EQ�Z {"lineid":"a799eb4f-86da-4af1-a221-9ed8b741b5ce"...

The decrypt method of the server (Java):服务端解密方法(Java):

在此处输入图像描述

I think that the problem is the padding difference: PKCS7 on my side, and PKCS5 on server.我认为问题在于填充差异:我这边的 PKCS7 和服务器上的 PKCS5。

How can I solve this problem with the extra chars appear on server side?如何在服务器端出现额外的字符来解决这个问题?

Those aren't trash characters, they're the Unicode Replacement Character returned when bytes are decoded into text using the wrong character set.这些不是垃圾字符,它们是使用错误字符集将字节解码为文本时返回的Unicode 替换字符

The very fact you got readable text means decrypting succeeded.您获得可读文本这一事实意味着解密成功。 It's decoding the bytes into text that failed.它将字节解码为失败的文本。

The bug is in the Java code.该错误在 Java 代码中。 It's using the String(byte[]) which, according to the docs:它使用String(byte[]) ,根据文档:

Constructs a new String by decoding the specified array of bytes using the platform's default charset.通过使用平台的默认字符集解码指定的字节数组来构造一个新的字符串。

That's obviously not UTF8.那显然不是UTF8。 The String​(byte[] bytes,Charset charset) or String​(byte[] bytes,String charsetName) constructors should be used instead, passing the correct character set, eg :应该使用String​(byte[] bytes,Charset charset)String​(byte[] bytes,String charsetName)构造函数,传递正确的字符集,例如:

byte[] decryptedBytes = cipher.doFinal(....);
return new String(decryptedBytes, StandardCharsets.UTF_8);

The hacky alternative is to change the remote server's default character set to UTF8. hacky 的替代方法是将远程服务器的默认字符集更改为 UTF8。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM