加密包含unicode的字符串会导致无法识别的字符

时间:2015-06-09 23:56:55

标签: c# encryption caesar-cipher

我正在尝试在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 habite dans un ananas sous laamerx。

如何允许加密例程访问unicode字符?

3 个答案:

答案 0 :(得分:5)

你得到一个不可打印的角色的原因是这一行:

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方法中使用相同的模式。通常更容易推理出适用于临时变量的代码,而不是编辑适当的东西。

答案 1 :(得分:1)

这是一个非常好的一周加密,你的问题是加密算法输出的ASCII值无法以可视格式打印出来。

解决方案是以某种方式对数据进行编码,或者使用分隔符将其打印为小数列表,或者使用某种编码算法,如base64或radix64。

只是一个提示,大多数现代加密算法都使用XOR运算符来加密数据。我给你写了一个带有CBC编码模式的简单xor密码,只是指出这远远不是安全算法,但它比你的项目安全得多。

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以进行下一个循环,依此类推。

答案 2 :(得分:1)

通常使用现代加密技术,我们不会注意字符(我们可能没有任何字符,我们可能会加密图片或声音文件),我们会注意字节。

你可以采取同样的方法。从特定编码的文本中获取字节流(UTF-8会很好),然后对其进行加密。

然后输出加密的字节。如果你需要有一些可以写下来的东西,你可以使用base-64来产生文本表示。

加密仍然非常好,因为这是困难的部分,对于实际使用我们使用已建立且经过良好测试的加密方案,但您已经拥有一种可行的方法,不会产生非字符或非匹配代理的非法Unicode序列。