【问题标题】:TCL AES <-> C# AES - Tcl encrypted text is ASCIITCL AES <-> C# AES - Tcl 加密文本是 ASCII
【发布时间】:2014-02-04 16:41:08
【问题描述】:

我是 TCL 新手,在这里需要一些帮助。

我编写了一个客户端/服务器应用程序:服务器用 C# (.Net 4.51) 实现,客户端用 TCL 8.2 实现。 基本通信工作正常,现在我需要加密客户端和服务器之间传递的消息。不幸的是,SSL 不是一个选项,因为我无法控制客户端并且没有安装 SSL 库。

我选择 TclLib (1.15) Aes 实现来进行加密。

为了检查两侧的 Aes 是否正确设置,我进行了以下测试:

IV 是:“20140204_1231060” 关键是:“QbPQiCOTmBzLgCc40ElxH2588jmRljmq” 我的测试数据是“Hello World”。

每一方都可以对加密数据进行解密。

这是 TCL 代码:

proc ::orbylonCrypto::encrypt { keyData ivData clearText } {

  set clearText [::aes::Pad $clearText 16];

  set key [::aes::Init cbc $keyData $ivData];  
  set ciphertext [::aes::Encrypt $key $clearText];
  ::aes::Final $key

  return [::aes::Hex $ciphertext];

}

proc ::orbylonCrypto::decrypt { keyData ivData ciphertext } {

  set key [::aes::Init cbc $keyData $ivData];  
  set clearText [::aes::Decrypt $key [ binary format H* $ciphertext ]];
  ::aes::Final $key

  return [ string trimright $clearText \0 ];

}
...

  set clearText {Hello World};
  set iv "20140204_1231060"
  set key "QbPQiCOTmBzLgCc40ElxH2588jmRljmq"

  set encrypted [::orbylonCrypto::encrypt $key $iv $clearText];
  set decrypted [::orbylonCrypto::decrypt $key $iv $encrypted];

并给我这个“加密”的值: "e9455ec1788f5431fd103694c235670f"

这是 C# 代码::

public static string Encrypt(string clearText, string key, string iv)
{
  string encryptedString;
  var keyBytes = getValidatedKey(key);
  var ivBytes = getValidatedIV(iv);

  //byte[] clearTextBytes = Encoding.ASCII.GetBytes(clearText);
  byte[] clearTextBytes = Encoding.Unicode.GetBytes(clearText);
  using (Aes encryptor = Aes.Create())
  {
    initializeAes(encryptor, keyBytes, ivBytes);
    using (MemoryStream ms = new MemoryStream())
    {
      using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
      {
        cs.Write(clearTextBytes, 0, clearTextBytes.Length);
        cs.Close();
      }
      encryptedString = bytesToHexString(ms.ToArray());
    }
  }
  return encryptedString;
}

public static string Decrypt(string encryptedText, string key, string iv)
{
  string encryptedString;
  var keyBytes = getValidatedKey(key);
  var ivBytes = getValidatedIV(iv);

  byte[] encryptedBytes = hexStringToByteArray(encryptedText);
  using (Aes encryptor = Aes.Create())
  {
    initializeAes(encryptor, keyBytes, ivBytes);
    using (MemoryStream ms = new MemoryStream())
    {
      using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
      {
        cs.Write(encryptedBytes, 0, encryptedBytes.Length);
        cs.Close();
      }
      // encryptedString = Encoding.ASCII.GetString(ms.ToArray());
      encryptedString = Encoding.Unicode.GetString(ms.ToArray());
      encryptedString = encryptedString.TrimEnd('\0');
    }
  }
  return encryptedString;
}

private static void initializeAes(Aes aes, byte[] keyBytes, byte[] ivBytes)
{
  aes.Padding = PaddingMode.Zeros;
  aes.BlockSize = 128;
  aes.KeySize = 256;
  aes.Mode = CipherMode.CBC;

  aes.Key = keyBytes;
  aes.IV = ivBytes;
}

private static byte[] getValidatedIV(string iv)
{
  byte[] ivBytes = Encoding.ASCII.GetBytes(iv);
  if (ivBytes.Length != 16)
  {
    throw new ArgumentException("The IV must have a length of 16 bytes.");
  }
  return ivBytes;
}

private static byte[] getValidatedKey(string key)
{
  byte[] keyBytes = Encoding.ASCII.GetBytes(key);
  if (keyBytes.Length != 32)
  {
    throw new ArgumentException("The Key must have a length of 32 bytes.");
  }
  return keyBytes;
}

...

string iv = "20140204_1231060";
string key = "QbPQiCOTmBzLgCc40ElxH2588jmRljmq";

string inClearText = "Hello World";

string encrypted = AesCryption.Encrypt(inClearText, key, iv);
string outClearText = AesCryption.Decrypt(encrypted, key, iv);

并给我这个“加密”的值: “1d080b143641984d7623fce65c8a551853e2d9189413e9895f72065fde17e479”

C#版本的输出是原来的两倍。

如果我在进行加密之前将 c# 端的输入数据转换为 ASCII,我将得到完全相同的输出,并且 TCL 实现能够对其进行解密。 我的理解是 TCL 是 unicode “感知”的,我未加密的消息以纯文本在客户端和服务器之间传递,没有任何编码问题。

我不知道是什么在这里删除了编码。我感觉实现为

的“::aes::Hex”
proc ::aes::Hex {data} {
    binary scan $data H* r
    return $r 
}

[ binary format H* $ciphertext ]

是这里的问题。但我不太确定。

任何帮助都非常感谢!

【问题讨论】:

  • Tcl 8.2?那是古代!我认为已经有 15 年没有更新的软件版本了……
  • 但是说真的,在这种情况下,Tcl 版本似乎并不重要。 aes 包在 8.6.1 中的行为相同(尽管我也可以使用不那么烦人的界面)。我只是不知道 C# 代码中的双倍信息是从哪里来的;编码该消息不应该占用那么多字节! clearTextBytes 的确切值是多少?
  • 此外,FWIW Tcl 代码已根据 AES 标准本身中的测试向量进行验证。 (自己阅读tests。)无论发生什么,我都不相信这是一个 Tcl 问题。

标签: c# encoding tcl aes


【解决方案1】:

根据 Donal Fellow 的提示,看看我的 clearTextBytes,问题很清楚。 TCL 使用的不是 Unicode,而是 UTF-8。所以我需要在加密之前将 C# 文本转换为 UTF8 并在解密后返回:

byte[] clearTextBytes = Encoding.UTF8.GetBytes(clearText);

decryptedString = Encoding.UTF8.GetString(ms.ToArray());

感谢您的提示!

【讨论】:

  • 我在 Tcl 端尝试过,但仍然感到困惑,但我很高兴它似乎对你有用。注意Tcl端的等价操作涉及encoding converttoencoding convertfrom;加密应正确应用于编码形式。
  • @Donal Fellows:感谢 Tcl 编码提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-25
  • 2013-08-12
  • 2013-08-11
  • 2013-01-16
  • 1970-01-01
  • 2016-09-22
相关资源
最近更新 更多