开发者

Console.WriteLine Doesnt Display Line After Large Number of Binary Zeros

The program never prints out "test" unless I set a breakpoint on it and step over myself. I don't understand what's happening. Appreciate any help.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        string testKey = "lkirwf897+22#bbtrm8814z5qq=498j5";
        string testIv = "741952hheeyy66#cs!9hjv887mxx7@8y";
        string testValue = "random";

        string encryptedText = EncryptRJ256(testKey, testIv, testValue);
        string decryptedText = DecryptRJ256(testKey, testIv, encryptedText);

        Console.WriteLine("encrypted: " + encryptedText);
        Console.WriteLine("decrypted: " + decryptedText);
        Console.WriteLine("test");
    }

    public static string DecryptRJ256(string key, string iv, string text)
    {

        string sEncryptedString = text;

        RijndaelManaged myRijndael = new RijndaelManaged();
        myRijndael.Padding = PaddingMode.Zeros;
        myRijndael.Mode = CipherMode.CBC;
        myRijndael.KeySize = 256;
        myRijndael.BlockSize = 256;

        byte[] keyByte = System.Text.Encoding.ASCII.GetBytes(key);
        byte[] IVByte = System.Text.Encoding.ASCII.GetBytes(iv);

        ICryptoTransform decryptor = myRijndael.CreateDecryptor(keyByte, IVByte);

        byte[] sEncrypted = Convert.FromBase64String(sEncryptedString);

        byte[] fromEncrypt = new byte[sEncrypted.Length + 1];

        MemoryStream msDecrypt = new MemoryStream(sEncrypted);
        CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);

        csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);

        return Encoding.ASCII.GetString(fromEncrypt);

    }


    public static string EncryptRJ256(string key, string iv, string text)
    {

        string sToEncrypt = text;

        RijndaelManaged myRijndael = new RijndaelManaged();
        myRijndael.Padding = PaddingMode.Zeros;
        myRijndael.Mode = CipherMode.CBC;
        myRijndael.KeySize = 256;
        myRijndael.BlockSize = 256;


        byte[] keyByte = Encoding.ASCII.GetBytes(key);
        byte[] IVByte = Encoding.ASCII.GetBytes(iv);

        ICryptoTransform encryptor = myRijndael.CreateEncryptor(keyByte, IVByte);

        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

        byte[] toEncrypt = System.Text.Encoding.ASCII.GetBytes(sToEncrypt);

        csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
        csEncrypt.FlushFinal开发者_如何学JAVABlock();

        byte[] encrypted = msEncrypt.ToArray();

        return Convert.ToBase64String(encrypted);

    }
}

edit:

Tried Debug.WriteLine

        Debug.WriteLine("encrypted: " + encryptedText);
        Debug.WriteLine("decrypted: " + decryptedText);
        Debug.WriteLine("test");

Output:

encrypted: T4hdAcpP5MROmKLeziLvl7couD0o+6EuB/Kx29RPm9w=

decrypted: randomtest

Not sure why it's not printing the line terminator.


        myRijndael.Padding = PaddingMode.Zeros;
        myRijndael.BlockSize = 256;

This is the source of the problem, the data you encrypt gets padded with zeros to get a block size that's a multiple of 32 bytes (32 x 8 = 256). You get those binary zeros back in the decrypted value. Tricky about them is that the debugger cannot display them. Which is okayish, you expect the value to roundtrip through ASCII, you can remove the zeros again after decrypting. The decrypting code needs some work too, you assume too much about the size of the decrypted data. Fix:

        MemoryStream fromEncrypt = new MemoryStream();
        MemoryStream msDecrypt = new MemoryStream(sEncrypted);
        CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);

        byte[] buffer = new byte[4096];
        for (; ; ) {
            int len = csDecrypt.Read(buffer, 0, buffer.Length);
            if (len == 0) break;
            fromEncrypt.Write(buffer, 0, len);
        }

        var result = Encoding.ASCII.GetString(fromEncrypt.GetBuffer(), 0, (int)fromEncrypt.Length);
        return result.Trim('\0');

You ought to dispose the streams btw, use the using statement.


There is one issue in your encryption/decryption code: Since you are using PaddingMode.Zeros, after the decryption, you are not able to say where the original data ended, and you receive “random” followed by zero bytes. If you would switch to e.g. PaddingMode.PKCS7, and properly use the return value of the CryptoStream.Read call, you would receive just the original text, i.e. “random”:

var decryptedSize = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return Encoding.ASCII.GetString(fromEncrypt, 0, decryptedSize);

Even though I think it shouldn’t be a problem to write NUL bytes to the console, I’d definitely try to remove them first, especially when seeing such strange behavior.


While this works for me using Mono on Linux, I do observe that decryptedText is 33 characters long - it consists of the characters 'r', 'a', 'n', 'd', 'o', 'm' followed 27 NUL characters. (I previously speculated that the padding bytes might be uninitialized, but looking at the code it looks like it is well-defined.) I would speculate that the console output window in Visual Studio interprets a NUL character as the end of output and thus stops printing anything else after that - including both the line terminator from WriteLine and the "test" string. I don't have Visual Studio here to test it, but I think you should be able to verify or disprove that easily enough.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜