a problem with encryption

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • crawlerxp

    #1

    a problem with encryption

    This is the problem: I do not get the output I need when encoding and
    decoding data using rijndael alghoritm.
    Look at the code and see what the problem is actually:

    Please paste this code into your Visual Studio and compile it + run it; so
    you can see what the actual problem is.

    Thanks.

    code:

    using System;
    using System.IO;
    using System.Text;
    using System.Security .Cryptography;
    namespace ConsoleApplicat ion1
    {
    class MyMainClass
    {
    public static void Main()
    {
    string original = "Original string";
    string roundtrip;
    ASCIIEncoding textConverter = new ASCIIEncoding() ;
    RijndaelManaged myRijndael = new RijndaelManaged ();
    byte[] fromEncrypt;
    byte[] encrypted;
    byte[] toEncrypt;
    byte[] key;
    byte[] IV;
    //Create a new key and initialization vector.
    myRijndael.Gene rateKey();
    myRijndael.Gene rateIV();
    //Get the key and IV.
    key = myRijndael.Key;
    IV = myRijndael.IV;
    //Get an encryptor.
    ICryptoTransfor m encryptor = myRijndael.Crea teEncryptor(key , IV);
    //Encrypt the data.
    MemoryStream msEncrypt = new MemoryStream();
    CryptoStream csEncrypt = new CryptoStream(ms Encrypt, encryptor,
    CryptoStreamMod e.Write);
    //Convert the data to a byte array.
    toEncrypt = textConverter.G etBytes(origina l);
    //Write all data to the crypto stream and flush it.
    csEncrypt.Write (toEncrypt, 0, toEncrypt.Lengt h);
    csEncrypt.Flush FinalBlock();
    //Get encrypted array of bytes.
    encrypted = msEncrypt.ToArr ay();

    //Here I send data trough network stream
    //create byte array to be sent trough tcp network
    byte[] finalized = new byte[key.Length+IV.L ength+encrypted .Length];
    //merge all values into single byte array
    key.CopyTo(fina lized,0);
    IV.CopyTo(final ized,32);
    encrypted.CopyT o(finalized,48) ;
    //here goes tcp code with sending the array trough network. it works fine,
    and is no problem.
    //For simplicitiy's sake, here i'll just simulate a new application that
    uses values it got from the first application.
    //SIMULATED NEW APPLICATION
    //Create values that will be used in decryption process and that are passed
    trough network
    byte[] key1 = new byte[32];
    byte[] IV1 = new byte[16];
    byte[] encrypted1 = new byte[finalized.Lengt h-48];
    //read all values from the passed byte array and divid those correctly.
    for (int i=0; i<32; i++)
    {
    key1[i]=finalized[i];
    }
    for (int i=32; i<48; i++)
    {
    IV1[i-32]=finalized[i];
    }
    for (int i=48; i<finalized.Len gth; i++)
    {
    encrypted1[i-48]=finalized[i];
    }
    //now use values to get the result:
    //Get a decryptor that uses the same key and IV as the encryptor.
    ICryptoTransfor m decryptor = myRijndael.Crea teDecryptor(key 1, IV1);
    //Now decrypt the previously encrypted message using the decryptor
    MemoryStream msDecrypt = new MemoryStream(en crypted1);
    CryptoStream csDecrypt = new CryptoStream(ms Decrypt, decryptor,
    CryptoStreamMod e.Read);
    fromEncrypt = new byte[encrypted1.Leng th];
    //Read the data out of the crypto stream.
    csDecrypt.Read( fromEncrypt, 0, fromEncrypt.Len gth);
    //Convert the byte array back into a string.
    roundtrip = textConverter.G etString(fromEn crypt);
    //Display the original data and the decrypted data to see where the actual
    problem is:
    Console.WriteLi ne("Original string: {0}", original + "_");
    Console.WriteLi ne("String I got to another application: {0}", roundtrip +
    "_");
    //Guess what! The result string has some dummy stuff at the end and it is
    //just not the data I encoded. It is actually there, but I really don't want
    //that sh*t at the end. I placed "_" sign just to see that there is a
    problem with data I got.
    }
    }
    }


  • Jon Skeet [C# MVP]

    #2
    Re: a problem with encryption

    crawlerxp <nytrogen@email .htnet.hr> wrote:[color=blue]
    > This is the problem: I do not get the output I need when encoding and
    > decoding data using rijndael alghoritm.
    > Look at the code and see what the problem is actually:
    >
    > Please paste this code into your Visual Studio and compile it + run it; so
    > you can see what the actual problem is.[/color]

    <snip>

    The problem is that you're assuming the decrypted size will be the same
    as the encrypted size - it's not. You're only actually reading 15 bytes
    (and moreover, you're assuming they'll all be read in one go, which is
    a bad idea) but passing the encoding a buffer 16 bytes long.

    *Always* use the return value of Stream.Read.

    --
    Jon Skeet - <skeet@pobox.co m>
    Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

    If replying to the group, please do not mail me too

    Comment

    • Tonci Jukic

      #3
      Re: a problem with encryption

      >The problem is that you're assuming the decrypted size will be the same
      as the encrypted size - it's not. You're only actually reading 15 bytes
      (and moreover, you're assuming they'll all be read in one go, which is a
      bad idea) but passing the encoding a buffer 16 bytes long.[color=blue]
      >*Always* use the return value of Stream.Read.[/color]

      Well, the problem was not in network operations and data send. It was in
      decrypted data.
      The problem was I did always get n to 16 bytes filled with zeros.

      So I've just swapped line:

      roundtrip = textConverter.G etString(fromEn crypt);

      with:

      roundtrip =
      textConverter.G etString(fromEn crypt).TrimEnd( Convert.ToChar( 0));

      That way I always get the original data I've encrypted.

      Thanks btw.

      I have another question:
      When I'm sending this data trough network stream from client to server,
      I always create byte type array big enough to accept possible data from
      the client application.
      Do I have to always create it big enough to support any possible data
      size, or I can read everything in blocks and then merge it to a single
      byte array for example.

      This is how it is done by now:

      client code:
      (this is a connection thread code cut from the main code:)

      try
      {
      this.hostName = this.textBox2.T ext;
      TcpClient client = new TcpClient(hostN ame, portNum);

      NetworkStream ns = client.GetStrea m();

      //size of response buffer
      byte[] bytes = new byte[1024];

      //using custom encryption class to encrypt given data
      bit256_Rijndael EnCryptorC enkripted = new bit256_Rijndael EnCryptorC();

      //encrypt string from the textbox
      encrypted.EnCry pt(this.textBox 1.Text);

      //create data-to-be-sent buffer
      byte[] byteTime = new byte[encrypted.Relea seEnCrypted).Le ngth];

      //fill it
      byteTime = encrypted.Relea seEnCrypted();

      //write it trough stream
      ns.Write(byteTi me, 0, byteTime.Length );

      //receive a response
      int bytesRead = ns.Read(bytes, 0, bytes.Length);

      client.Close();

      }

      server code:

      TcpClient client = listener.Accept TcpClient();

      NetworkStream ns = client.GetStrea m();

      //buffer for incoming data
      byte[] bytes = new byte[4096];

      //read data from the ns
      int bytesRead = ns.Read(bytes, 0, bytes.Length);

      //input data in a work buffer
      byte[] returned = new byte[bytesRead];

      for (int u=0; u<bytesRead; u++)
      {
      returned[u]=bytes[u];
      }

      //create data variables to be used in encryption process
      byte[] key = new byte[32];
      byte[] IV = new byte[16];
      byte[] encrypted = new byte[returned.Length-48];

      //strip usable data from the incoming stream
      for (int i=0; i<32; i++)
      {
      key[i]=returned[i];
      }
      for (int i=32; i<48; i++)
      {
      IV[i-32]=returned[i];
      }
      for (int i=48; i<returned.Leng th; i++)
      {
      encrypted[i-48]=returned[i];
      }

      //create a custom encryption (this time decryption) class
      bit256_Rijndael EnCryptorC dekripted = new
      bit256_Rijndael EnCryptorC(key, IV,encrypted);
      encrypted.DeCry pt();

      string result = encrypted.Relea seDeCrypted();

      byte[] byteTime = Encoding.ASCII. GetBytes("serve r performed
      operations!");

      try
      {
      ns.Write(byteTi me, 0, byteTime.Length );
      ns.Close();
      }
      client.Close();

      *** Sent via Developersdex http://www.developersdex.com ***
      Don't just participate in USENET...get rewarded for it!

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: a problem with encryption

        Tonci Jukic <nytrogen@email .htnet.hr> wrote:[color=blue][color=green]
        > >The problem is that you're assuming the decrypted size will be the same[/color]
        > as the encrypted size - it's not. You're only actually reading 15 bytes
        > (and moreover, you're assuming they'll all be read in one go, which is a
        > bad idea) but passing the encoding a buffer 16 bytes long.[color=green]
        > >*Always* use the return value of Stream.Read.[/color]
        >
        > Well, the problem was not in network operations and data send. It was in
        > decrypted data.[/color]

        I didn't say it *was* in the network operations.
        [color=blue]
        > The problem was I did always get n to 16 bytes filled with zeros.[/color]

        That's because you ignored the fact that Read wasn't returning 16
        bytes.
        [color=blue]
        > So I've just swapped line:
        >
        > roundtrip = textConverter.G etString(fromEn crypt);
        >
        > with:
        >
        > roundtrip =
        > textConverter.G etString(fromEn crypt).TrimEnd( Convert.ToChar( 0));
        >
        > That way I always get the original data I've encrypted.[/color]

        That's a bad way of doing things. Just use the return value of Read to
        find out how much real data you've got, and use the form of GetString
        that lets you specify how much to decode.
        [color=blue]
        > Thanks btw.
        >
        > I have another question:
        > When I'm sending this data trough network stream from client to server,
        > I always create byte type array big enough to accept possible data from
        > the client application.
        > Do I have to always create it big enough to support any possible data
        > size, or I can read everything in blocks and then merge it to a single
        > byte array for example.[/color]

        Yes. That's much more robust - relying on a single call to Read as you
        are at the moment is a very bad idea.

        See http://www.pobox.com/~skeet/csharp/readbinary.html
        [color=blue]
        > This is how it is done by now:[/color]

        <snip>
        [color=blue]
        > byte[] encrypted = new byte[returned.Length-48];[/color]

        <snip>
        [color=blue]
        > encrypted.DeCry pt();[/color]

        That's not your actual code, is it? Byte arrays don't have a DeCrypt
        method. Please always post your *actual* code.

        --
        Jon Skeet - <skeet@pobox.co m>
        Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

        If replying to the group, please do not mail me too

        Comment

        • Tonci Jukic

          #5
          Re: a problem with encryption

          > So I've just swapped line:[color=blue]
          >
          > roundtrip = textConverter.G etString(fromEn crypt);
          >
          > with:
          >
          > roundtrip =
          > textConverter.G etString(fromEn crypt).TrimEnd( Convert.ToChar( 0));
          >
          > That way I always get the original data I've encrypted.[/color]
          [color=blue]
          >That's a bad way of doing things. Just use the return value of Read to[/color]
          find out how much real data you've got, and use the form of GetString
          that lets you specify how much to decode.

          Well. I really don't know a way to know how long the string I send to
          the server app can be. As you could see in the code, I send key, IV and
          encrypted data in a byte array trough network stream. I really don't
          know how to send the length of the string I encrypted to the server by
          which the server would know how much to decrypt.
          The only way I could think of was to trim encrypted byte array at the
          very start before sending data trough network.
          [color=blue]
          >Yes. That's much more robust - relying on a single call to Read as you[/color]
          are at the moment is a very bad idea.

          How could I possible use multiple read calls? What would it give to me?
          [color=blue]
          >That's not your actual code, is it? Byte arrays don't have a DeCrypt[/color]
          method. Please always post your *actual* code.

          Well. We've got a slight problem here:)

          I tried to cut\paste and edit my code here. I've translated variables
          into english as I thought it would be easier for you to understand the
          code.

          Too bad attachments are not possible here, but here is almost the
          complete code I've been using.

          (I'm totally green in C# and .NET (although I've been using C++ till
          now) so please don't laugh at my code. I woul appreciate any comments
          and suggestions about it.)




          *** Sent via Developersdex http://www.developersdex.com ***
          Don't just participate in USENET...get rewarded for it!

          Comment

          • Jon Skeet [C# MVP]

            #6
            Re: a problem with encryption

            Tonci Jukic <nytrogen@email .htnet.hr> wrote:[color=blue][color=green]
            > > roundtrip =
            > > textConverter.G etString(fromEn crypt).TrimEnd( Convert.ToChar( 0));
            > >
            > > That way I always get the original data I've encrypted.[/color]
            >[color=green]
            > >That's a bad way of doing things. Just use the return value of Read to[/color]
            > find out how much real data you've got, and use the form of GetString
            > that lets you specify how much to decode.
            >
            > Well. I really don't know a way to know how long the string I send to
            > the server app can be. As you could see in the code, I send key, IV and
            > encrypted data in a byte array trough network stream. I really don't
            > know how to send the length of the string I encrypted to the server by
            > which the server would know how much to decrypt.
            > The only way I could think of was to trim encrypted byte array at the
            > very start before sending data trough network.[/color]

            You don't need to trim anything. Just take note of how much decrypted
            data you're actually receiving. From your original sample, all you've
            got to change is:

            csDecrypt.Read( fromEncrypt, 0, fromEncrypt.Len gth);
            //Convert the byte array back into a string.
            roundtrip = textConverter.G etString(fromEn crypt);

            to

            int bytesRead = csDecrypt.Read( fromEncrypt, 0, fromEncrypt.Len gth);
            //Convert the byte array back into a string.
            roundtrip = textConverter.G etString(fromEn crypt, 0, bytesRead);

            (It doesn't deal with the situation where there's more data to read
            than you expect, or a single call to Read doesn't return all the data.)
            [color=blue][color=green]
            > >Yes. That's much more robust - relying on a single call to Read as you[/color]
            > are at the moment is a very bad idea.
            >
            > How could I possible use multiple read calls? What would it give to me?[/color]

            It would mean that if you send more data than the decrypting code wants
            to decrypt in one call, your code would still work.
            [color=blue][color=green]
            > >That's not your actual code, is it? Byte arrays don't have a DeCrypt[/color]
            > method. Please always post your *actual* code.
            >
            > Well. We've got a slight problem here:)
            >
            > I tried to cut\paste and edit my code here. I've translated variables
            > into english as I thought it would be easier for you to understand the
            > code.
            >
            > Too bad attachments are not possible here, but here is almost the
            > complete code I've been using.
            >
            > (I'm totally green in C# and .NET (although I've been using C++ till
            > now) so please don't laugh at my code. I woul appreciate any comments
            > and suggestions about it.)
            >
            > http://www.dg.disorange.com/download/code.zip[/color]

            Ah. The problem is that you changed variable names half way through -
            you wrote (in your previous message) encrypted.DeCry pt() instead of
            dekripted.DeCry pt(). It's always worth trying to compile the code
            you're about to post. It's also worth posting short and complete code -
            see http://www.pobox.com/~skeet/csharp/complete.html

            --
            Jon Skeet - <skeet@pobox.co m>
            Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

            If replying to the group, please do not mail me too

            Comment

            Working...