加密包含unicode的字符串会导致无法识别的字符
本文关键字:识别 字符 包含 unicode 字符串 加密 | 更新日期: 2023-09-27 17:55:06
我正在尝试加密c#中的字符串:
static public string Encrypt(char[] a)
{
for (int i = 0; i < a.Length; i++)
{
a[i] -= (char)(i + 1);
if (a[i] < '!')
{
a[i] += (char)(i + 20);
}
}
return new string(a);
}
现在,当我输入这个字符串:
"Qui habite dans un ananas sous la mer?".
加密结果为:
`Psf3c[[ak[3XT`d3d'3MYKWIZ3XSXU3L@?JAMR`
在@后面有一个无法识别的字符。我不知道它怎么会在那里,我也不知道为什么。
如果我尝试解密它(使用此方法:)
static public string Decrypt(char[] a)
{
for (int i = 0; i < a.Length; i++)
{
a[i] += (char)(i + 1);
if ((a[i] - 20) - i <= '!')
{
a[i] -= (char)(i + 20);
}
}
return new string(a);
}
这是(不正确的)输出:
Qui habidans unananas sous laamerx.
如何允许加密例程访问unicode字符?
你得到一个不可打印字符的原因是这一行:
a[i] -= (char)(i + 1);
la mer
中的空格是字符串的第34个位置,空格的等效整数值是0x20 = 32。这意味着减去(i+1)
得到-2。但是你将结果存储在char
中,这是一种无符号类型,所以这实际上变成了0xFFFE = 65534。然后当你测试a[i] < '!'
时,你得到假,因为a[i]
现在是一个大的正数。
相反,你应该做的(如果你真的想实现这个算法)是将结果存储在一个有符号类型中,并像你这样操作它,然后在最后将其转换为char。
int value = (int)a[i] - (i + 1);
if (value < (int)'!')
{
value += i + 20;
}
a[i] = (char)value;
(额外的类型强制转换以强调)
这可能不是必要的,但我建议在Decrypt
方法中也使用相同的模式。一般来说,理解代码在临时变量上工作比在适当的地方编辑要容易得多。
这是一个漂亮的周加密,你的问题是加密算法输出的ASCII值是不可能以可见格式打印出来的。
一种解决方案是以某种方式对数据进行编码,要么将其打印为带有分隔符的小数列表,要么使用某种编码算法,如base64或radix64。
只是一个提示,大多数现代加密算法使用异或运算符来加密数据。我写了一个简单的xor密码与CBC改变模式给你,只是为了指出这是一个远离安全的算法,但它比你的项目更安全。
public char [ ] encryptCBC ( char [ ] plain, char [ ] password, char [ ] iv )
{
char [ ] ciphertext = new char [ 8 ];
for ( int i = 0; i < 8; i ++ )
{
ciphertext [ i ] = plain ^ iv;
ciphertext [ i ] ^= password;
}
return ciphertext;
}
public char [ ] decryptCBC ( char [ ] ciphertext, char [ ] password, char [ ] iv )
{
char [ ] plaintext = new char [ 8 ];
for ( int i = 0; i < 8; i ++ )
{
plaintext [ i ] = ciphertext ^ password;
plaintext [ i ] ^= iv;
}
return plaintext;
}
这是一个块密码,意味着它为每个循环加密一个块(n个字节),在这个例子中它加密8个字节。所以iv
(初始化向量-随机数据)需要是8字节长,password
也需要是8字节长。被加密的文本必须分成8个字节的块。然后循环函数直到所有数据都被加密,例如,如果你有32字节的数据需要加密,那么它将需要4个循环来完成加密。
编辑:忘了告诉你,你在第一个循环中输入随机数据作为iv
,然后在下一个循环中输入前一个循环的结果作为iv
,以此类推。
通常使用现代加密我们不注意字符(我们甚至可能没有字符,我们可能加密的是图片或声音文件),我们关注的是字节。
你可以采用同样的方法。以特定编码(UTF-8将是一个很好的编码)从文本中获取字节流,然后对其进行加密。
加密后的字节就是你的输出。如果你需要一些可以写下来的东西,你可以使用64进制来生成文本表示。
加密仍然不是很好,因为这是困难的部分,对于实际使用,我们将使用已建立且经过良好测试的加密方案,但是您将有一个可行的方法,不会产生非法的Unicode序列,如非字符或不匹配的代理。