我是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#Code ::
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 ]
是问题所在。但我对此并不太确定。
任何帮助都非常感谢!
答案 0 :(得分:2)
根据Donal Fellow暗示看看我的clearTextBytes,问题很明显。 TCL不使用Unicode而是使用UTF-8。所以我需要在加密前将C#文本转换为UTF8,并在解密后将其转换回来:
byte[] clearTextBytes = Encoding.UTF8.GetBytes(clearText);
和
decryptedString = Encoding.UTF8.GetString(ms.ToArray());
感谢提示!