0

Good evening!

I'm trying to implement an encrypter using Rijndael algorithm and Rijndael class in c#. I tried to follow (not doing exactly the same code) the link bellow, but the problem is given a string to be encrypted I'm not getting any result. I'm no getting any error message too.

https://learn.microsoft.com/pt-br/dotnet/api/system.security.cryptography.rijndael?view=netframework-4.8

CryptDecrypt.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace RijndaelAlgorithm {
    public class CryptDecrypt {
        private Byte[] iv;
        private Byte[] key; 

        public CryptDecrypt(String key) {
            iv = new Byte[] {21, 10, 21, 251, 132, 76, 121, 27, 210, 81, 215, 99, 14, 235, 11, 75};
            this.key = Encoding.ASCII.GetBytes(key);
        }

        public String encryptMsg(String originalMsg) {
            byte[] encryptedMsg;

            Rijndael rijAlg = Rijndael.Create();
            rijAlg.Key = formatKey();
            rijAlg.IV = iv;

            MemoryStream msEncrypt = new MemoryStream();
            ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
            CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

            StreamWriter swEncrypt = new StreamWriter(csEncrypt);
            swEncrypt.Write(originalMsg);

            encryptedMsg = msEncrypt.ToArray();
            Console.WriteLine("encryptedMsg.Length: " + encryptedMsg.Length);

            return Convert.ToBase64String(encryptedMsg, 0, encryptedMsg.Length);
        }

        private Byte[] formatKey() {
            int len = key.Length;

            String strKey = System.Text.Encoding.UTF8.GetString(key);
            String fillKey = "";
            String strFormatedKey = "";

            Byte[] formatedKeyByte;

            if (len < 16)
                fillKey = new String('X',(16 - len));

            strFormatedKey = String.Concat(strKey, fillKey);
            formatedKeyByte = Encoding.ASCII.GetBytes(strFormatedKey);

            return formatedKeyByte;
        }
    }
}

Menu.cs

using System;

namespace RijndaelAlgorithm {
    public class Menu {
        private CryptDecrypt r;

        public Menu() {
            r = new CryptDecrypt("123654");
        }

        public void showMenu() {
            Console.WriteLine("the encrypted message is: " + r.encryptMsg("isjustatest"));
        }
    }
}
Roger_88
  • 477
  • 8
  • 19
  • Can you create a [mcve], in a separate project or on .net fiddle with only the encryption part of your problem – TheGeneral Jun 10 '19 at 00:55
  • I did what I could. The RijndaelAlgorithm class has only two methods and maybe the problem is in formatKey(). Probably not, but I don't know. And Menu class is where I define the key and the message to be encrypted. – Roger_88 Jun 10 '19 at 01:17
  • Why did you get rid of the using() constructs? Since they are gone you now have to manually call `swEncrypt.Flush();` and then `csEncrypt.FlushFinalBlock()` after the Write. – President James K. Polk Jun 10 '19 at 01:20
  • Because I'm newbie in c# and this synthax is very ugly and unusual for me. I added swEncrypt.Flush(); and then csEncrypt.FlushFinalBlock() after the swEncrypt.Write(originalMsg); and now is working fine. Apparently. The thing is I tried encrypt the same message in http://crypt-online.ru/en/crypts/aes/ and I got another thing. I choose 256bit for key size and "123654" for key and I got for Encode: U2FsdGVkX1+IVWR60YK3F6fN7F3a7SKPSpPDvF6ZXlA= and using my code I got GlIhsK3UihG+nlmBZHgHYg== Why? – Roger_88 Jun 10 '19 at 01:44
  • 1
    Your code uses a 128 bit key, not 256. Also, padding with `'X'` is highly unusual and not likely to be done by that online tool. Use a password based key derivation function such as Argon2 or PBKDF2 to turn low entropy keys into proper encryption keys. And do not reuse IVs for any given key. – Peter Jun 10 '19 at 08:45

1 Answers1

0

You seem to want to encrypt a message with your .NET application and want to get the same encrypted bytes as a particular online service that you mention in one of your comments.

Parameter

One parameter for an encryption is the initialization vector (IV). It should be random and used only once. So if two apps are correctly implemented (with different random IVs), the encrypted bytes are different.

This service returns a different result every time you press the key, even if you use the same input.

However, if you generally take the different encrypted results and decrypt them with the same key, you will get the original bytes back.

The next problem with testing with this specific service is, that they delivering always the same prefix base64 sequence 'U2FsdGVkX1'. This is not standard AES output (if you decode this base64 sequence you get 'Salted_P'). So it makes sense to use a different online service for tests.

So if two AES-256 encoding implementations are using the same parameters, we will get the same encoded result. We need for it:

  • Key (32 bytes, not 16 for AES-256)
  • IV (16 bytes)

Speaking of key length: As others mentioned in the comments, you should not simply add "X" or something similar, but use a standard cryptographic mechanism to derive a good key.

Convenient for tests are methods that convert hex strings to byte arrays and back, e.g. see StringToByteArray and ByteArrayToString methods in this cool answer: https://stackoverflow.com/a/311179

Let's give it a try. If we take your message 'isjustatest' which has the hex string'69736a7573746174657374374', we need a 32-byte key for AES-256 and 16 bytes IV.

As others mentioned in the comments, you need to flush and close the stream (or better yet, use a 'using' statement).

Taking your code and change the key and iv assignment and output the encrypted message to the console:

rijAlg.Key = StringToByteArray("519C7C3402A943D8AF83746C1548E475319EBDA6A38046059F83B21709BD6A5B"); //32 bytes
rijAlg.IV =  StringToByteArray("0D024CF947CE4C288880D0B34D29BFA5"); // 16 bytes
...
swEncrypt.Write(originalMsg);
swEncrypt.Flush();
swEncrypt.Close();
...
Console.WriteLine("encrypted bytes: '" + ByteArrayToString(encryptedMsg) + "'");

This results in the output of '419536f27da3406625b2d07f43833aab' in the debug console.

So now we can use an online service, e.g. https://cryptii.com/pipes/aes-encryption where we can enter input data, select the encryption algorithm, supply key and IV bytes and then we get the same result as in your program, see screenshot here:

enter image description here

As mentioned above, don't forget to use different random IVs when using it in a real application.

Community
  • 1
  • 1
Stephan Schlecht
  • 26,556
  • 1
  • 33
  • 47