C#Rijndael解密返回额外的问号字符 [英] C# Rijndael decryption returns extra question mark character

查看:90
本文介绍了C#Rijndael解密返回额外的问号字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在组织一个类中的一些非常基本的对称加密/解密代码,以备将来使用.我能够成功加密和解密...只有一个小问题.

I am organizing some very basic symmetric encryption/decryption codes in a class for future use. I am able to encrypt and decrypt successfully... only with a small problem.

这是我的代码,该代码从一个流中读取并加密/解密到另一个流:

Here is my code that reads in from a stream and en/decrypt to another stream:

public void Encrypt(Stream input, Stream output) {
    byte[] key = Encoding.UTF8.GetBytes(_pw);
    byte[] iv = Encoding.UTF8.GetBytes(GenerateInitVector());
    RijndaelManaged rm = new RijndaelManaged();
    CryptoStream cs = new CryptoStream(
        output,
        rm.CreateEncryptor(key, iv),
        CryptoStreamMode.Write);
    int data;
    while ((data = input.ReadByte()) != -1)
        cs.WriteByte((byte) data);
    cs.Close();
}

public void Decrypt(Stream input, Stream output) {
    byte[] key = Encoding.UTF8.GetBytes(_pw);
    byte[] iv = Encoding.UTF8.GetBytes(GenerateInitVector());
    RijndaelManaged rm = new RijndaelManaged();
    CryptoStream cs = new CryptoStream(
        input,
        rm.CreateDecryptor(key, iv),
        CryptoStreamMode.Read);
    int data;
    while ((data = cs.ReadByte()) != -1)
        output.WriteByte((byte) data);
    cs.Close();
}

为您提供信息,方法GenerateInitVector()始终返回相同的值.

For your information, the method GenerateInitVector() always returns the same value.

这是我的测试文件.

hello
world
this
is
a
word
list

当我尝试从FileStream到FileStream进行加密/解密时,使用以下方法,一切正常:

When I try to en/decrypt from FileStream to FileStream, everything works fine, using these methods:

public void Encrypt(string inputPath, string outputPath) {
    FileStream input = new FileStream(inputPath, FileMode.Open);
    FileStream output = new FileStream(outputPath, FileMode.Create);
    Encrypt(input, output);
    output.Close();
    input.Close();
}

public void Decrypt(string inputPath, string outputPath) {
    FileStream input = new FileStream(inputPath, FileMode.Open);
    FileStream output = new FileStream(outputPath, FileMode.Create);
    Decrypt(input, output);
    output.Close();
    input.Close();
}

当我尝试将文件解密为MemoryStream,然后将字节转换为chars的数组加载到StringBuilder中,最后将其作为字符串打印输出到控制台时,我进入了控制台:

When I try to decrypt the file into a MemoryStream and then load the bytes-converted-to-chars array into a StringBuilder and finally print it out to console as a string, I get in the console:

?hello
world
this
is
a
word
list

我所有文字前面都有一个额外的问号.这是我的解密方法:

There is an extra question mark in front of all my text. Here is my decryption method:

public StringBuilder Decrypt(string inputPath) {
    FileStream input = new FileStream(inputPath, FileMode.Open);
    byte[] buffer = new byte[4096];
    MemoryStream output = new MemoryStream(buffer);
    Decrypt(input, output);
    StringBuilder sb = new StringBuilder(4096);
    sb.Append(Encoding.UTF8.GetChars(buffer, 0, (int) output.Position));
    input.Close();
    output.Close();
    return sb;
}

我在这里已经阅读过类似的内容,涉及BOM和C#悄悄将未知内容写为'?'字符:

I have read something similar here regarding BOM and C# quietly writing unknown stuff as the '?' character:

RSA加密/解密的结果带有3个问号

因此,我双重确定我使用的是UTF-8编码.不过,我看到了这个额外的问号.为了完整起见,我还编写了此方法将StringBuilder中的内容加密到文件中:

Therefore I have made doubly sure that I am using UTF-8 encoding. Still, I am seeing this extra question mark. For the sake of completeness, I have also written this method to encrypt contents inside a StringBuilder to a file:

public void Encrypt(string outputPath, StringBuilder builder) {
    char[] buffer = new char[builder.Length];
    builder.CopyTo(0, buffer, 0, builder.Length);
    byte[] buf = Encoding.UTF8.GetBytes(buffer);
    MemoryStream input = new MemoryStream(buf);
    FileStream output = new FileStream(outputPath, FileMode.Create);
    Encrypt(input, output);
    output.Close();
    input.Close();
}

然后我通过以下方法进行交叉检查:

Then I cross-check by doing:

var builder = new StringBuilder();
builder.Append("Hello world.");
Encrypt("test.txt.enc", builder);
Decrypt("test.txt.enc", "test.txt");
builder = Decrypt("test.txt.enc");
Console.WriteLine(builder.ToString());

对于文件test.txt,一切正常.不过奇怪的是,对于在控制台上打印的文字,我在前面加了额外的问号:

For the file test.txt, things are fine. Strangely though, for the text printed on console, I get NO extra question mark in front:

Hello world.

整个过程有什么问题?

推荐答案

问号是 BOM UTF8的(字节顺序标记)为0xef 0xbb 0xbf 该字节写在以UTF8编码的文件的开头.

The Questionmark is the BOM (Byte Order Mark) of UTF8 is 0xef 0xbb 0xbf This bytes are written at the beginning of your files encoded in UTF8.

因为FileStream读取文件为字节,而不将其解释为UTF8文本文件,所以BOM包含在加密中,因此,如果解密并将其保存到文件中,则在TextEditor中看起来一切正常,但是如果将其转储以控制台BOM也被打印,因为控制台不知道它是某种控制顺序/标记

Because FileStream reads the files as bytes and doesnt intepret it as UTF8 Textfile the BOM is included in your encryption so if you decrypt it and save it to file it looks all fine in a TextEditor but if you dump it to console the BOM is also printed cause the Console doesnt know it is some kind of control sequence/marker

这是获取不带BOM的字符串的解决方案.

And here is the solution to get the string without the BOM.

    public static string Decrypt(string inputPath)
    {
        FileStream input = new FileStream(inputPath, FileMode.Open);
        MemoryStream output = new MemoryStream();
        Decrypt(input, output);
        StreamReader reader = new StreamReader(output, new UTF8Encoding()); //Read with encoding
        output.Seek(0, SeekOrigin.Begin); //Set stream Position to beginning
        string result = reader.ReadToEnd(); //read to string
        reader.Close();
        input.Close();
        output.Close();
        return result;
    }

这篇关于C#Rijndael解密返回额外的问号字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆