2

我正在尝试在 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 字符?

4

3 回答 3

5

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

a[i] -= (char)(i + 1);

发生的事情是你的空间la mer是字符串的第 34 个位置,一个空间的等效整数值是 0x20 = 32。这意味着当你减去时(i+1)你得到 -2。但是您将结果存储在 a 中char,这是一个无符号类型,因此它实际上变为 0xFFFE = 65534。然后当您测试时,a[i] < '!'您会得到错误,因为a[i]现在是一个很大的正数。

相反,你应该做的(如果你真的想实现这个算法)是将结果存储在一个有符号类型中,并在你正在做的时候对其进行操作,然后在最后将它转换为一个字符。

    int value = (int)a[i] - (i + 1);
    if (value < (int)'!')
    {
        value += i + 20;
    }
    a[i] = (char)value;

(用于强调的额外类型转换。)

可能没有必要,但我建议在Decrypt方法中也使用相同的模式。通常更容易推理适用于临时变量的代码,而不是就地编辑内容。

于 2015-06-10T00:46:13.460 回答
1

这是一个漂亮的一周加密,您的问题是加密算法输出的 ASCII 值无法以可查看的格式打印出来。

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

提示一下,大多数现代加密算法都使用 XOR 运算符来加密数据。我用 CBC chaning 模式给你写了一个简单的异或密码,只是为了指出这与安全算法相去甚远,但它比你的项目安全得多。

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

于 2015-06-10T00:35:05.880 回答
1

一般来说,现代加密我们不关注字符(我们甚至可能没有,我们可能正在加密图片或声音文件),我们关注字节。

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

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

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

于 2015-06-10T03:23:38.550 回答