Tech Off Thread

7 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Using TripleDES to encrypt 64 bits, and only 64 bits

Back to Forum: Tech Off
  • User profile image
    W3bbo

    I can't seem to figure out how to use the DES or TripleDES classes in .NET. I want to encrypt 64 bits (such that a 64-bit block is returned) but whilst I can get it to encrypt data, it either doesn't decrypt it (in the first example below), or returns 128 bits instead (second example). The third example just causes an exception.

    using System;
    using System.Security.Cryptography;
    using System.Text;
    using System.IO;
    
    namespace EncTest {
        
        public class Program {
            
            private static Int32 _blockSize;
            
            public static void Main(String[] args) {
                
                SymmetricAlgorithm algo = 
    //                DES.Create();
    //                Rijndael.Create();
                    TripleDES.Create();
                
                Console.WriteLine("Using: {0}", algo.GetType().Name );
                
                algo.GenerateKey();
                algo.GenerateIV();
                
                Console.WriteLine("Key: {0}\nIV: {1}", Convert.ToBase64String( algo.Key ), Convert.ToBase64String( algo.IV ) );
                
                _blockSize = algo.LegalBlockSizes[0].MaxSize / 8;
                
                Console.WriteLine("Encrypt this:");
                Byte[] inputBytes = GetBlock(_blockSize);
                
                Encrypt1( algo, inputBytes ); Console.WriteLine("----------------");
                Encrypt2( algo, inputBytes ); Console.WriteLine("----------------");
                Encrypt3( algo, inputBytes );
                
                Console.ReadLine();
            }
            
            private static void Encrypt1(SymmetricAlgorithm algo, Byte[] clearInput) {
                
                ICryptoTransform enc = algo.CreateEncryptor();
                ICryptoTransform dec = algo.CreateDecryptor();
                
                Byte[] encryptedBytes = new Byte[_blockSize];
                int m = enc.TransformBlock( clearInput, 0, clearInput.Length, encryptedBytes, 0 );
                Console.WriteLine("Encrypted in {0,2} bytes as \"{1}\"", m, Convert.ToBase64String( encryptedBytes ) );
                
                Byte[] decryptedBytes = new Byte[_blockSize];
                m = dec.TransformBlock( encryptedBytes, 0, encryptedBytes.Length, decryptedBytes, 0 );
                Console.WriteLine("Decrypted in {0,2} bytes as \"{1}\"", m, Encoding.UTF8.GetString( decryptedBytes ) );
            }
            
            private static void Encrypt2(SymmetricAlgorithm algo, Byte[] clearInput) {
                
                ICryptoTransform enc = algo.CreateEncryptor();
                ICryptoTransform dec = algo.CreateDecryptor();
                
                Byte[] encryptedBytes = enc.TransformFinalBlock( clearInput, 0, clearInput.Length );
                
                Console.WriteLine("Encrypted in {0,2} bytes as \"{1}\"", encryptedBytes.Length, Convert.ToBase64String( encryptedBytes ) );
                
                Byte[] decryptedBytes = dec.TransformFinalBlock( encryptedBytes, 0, encryptedBytes.Length );
                
                Console.WriteLine("Decrypted in {0,2} bytes as \"{1}\"", decryptedBytes.Length, Encoding.UTF8.GetString( decryptedBytes ) );
            }
            
            private static void Encrypt3(SymmetricAlgorithm algo, Byte[] clearInput) {
                
                ICryptoTransform enc = algo.CreateEncryptor();
                ICryptoTransform dec = algo.CreateDecryptor();
                
                MemoryStream ms  = new MemoryStream();
                CryptoStream csw = new CryptoStream( ms, enc, CryptoStreamMode.Write );
                
                csw.Write( clearInput, 0, clearInput.Length );
                csw.Flush(); // at this point, 'ms' reports 8 bytes were written
                csw.Close();
                
                Byte[] encdata = ms.ToArray();
                ms = new MemoryStream( encdata );
                
                Console.WriteLine("Encrypted in {0,2} bytes as \"{1}\"", encdata.Length, Convert.ToBase64String( encdata ) );
                
                Byte[] decryptedBytes = new Byte[ _blockSize ];
                
                CryptoStream csr = new CryptoStream( ms, dec, CryptoStreamMode.Read );
                int br = csr.Read( decryptedBytes, 0, decryptedBytes.Length ); // TODO: "Bad Data" exception thrown here
                csr.Close();
                
                Console.WriteLine("Decrypted in {0,2} bytes as \"{1}\" ({2} bytes read)", decryptedBytes.Length, Encoding.UTF8.GetString( decryptedBytes ), br );
            }
            
            private static Byte[] GetBlock(int blockSize) {
                
                while(true) {
                    
                    String input = Console.ReadLine();
                    Byte[] inputBytes = Encoding.UTF8.GetBytes( input );
                    if( inputBytes.Length > blockSize ) continue;
                    
                    Byte[] ret = new Byte[blockSize];
                    Array.Copy( inputBytes, ret, input.Length );
                    return ret;
                }
                
            }
            
        }
    }
    

    This code should compile with .NET 2.0 or later (maybe even 1.1 too). Can anyone tell me where I'm going wrong?

    Ta

  • User profile image
    Dexter

    The first case doesn't work because you don't call TransformFinalBlock.

    The second case works fine for me, I get 8 bytes, that is 64 bits.

    The third case doesn't work because you flush the write stream but you should close it instead.

  • User profile image
    W3bbo

    ,Dexter wrote

    The first case doesn't work because you don't call TransformFinalBlock.

    The second case works fine for me, I get 8 bytes, that is 64 bits.

    The third case doesn't work because you flush the write stream but you should close it instead.

    I fixed the bug in the third case.

    But when I run it I get 16 bytes (128 buts) for both the second and third cases.

     

  • User profile image
    Dexter

    Well, I tested again, this time on .NET 2 (previously I used 4). I get 8 bytes in both cases.

    How do you know how many bytes have been returned? Your sample code doesn't show that and in the 3rd cases it's impossible to get more than 8 bytes unless the block size is > 8.

    Btw, in the 3rd case you should check the value returned by Read.

  • User profile image
    W3bbo

    @Dexter:Weird.

    I've updated my OP with the newer source code. When I run it I get these results in console:

    Using: TripleDESCryptoServiceProvider
    Key: I7Oahhupbb64UE/M+ex7r/JG08GXXIdd
    IV: nXDMTEnbbj8=
    Encrypt this:
    123
    Encrypted in 8 bytes as "IrhKcDMCixU="
    Decrypted in 0 bytes as " "
    ----------------
    Encrypted in 16 bytes as "IrhKcDMCixXFhW3UMfsnIA=="
    Decrypted in 8 bytes as "123 "
    ----------------
    Encrypted in 16 bytes as "IrhKcDMCixXFhW3UMfsnIA=="
    Decrypted in 8 bytes as "123 " (8 bytes read)
  • User profile image
    Dexter

    Yay, you were talking about encrypted size and I was talking about the decrypted size. That's because of the padding. If you set PaddingMode to None you'll get 8 bytes if you really need that.

  • User profile image
    W3bbo

    ,Dexter wrote

    Yay, you were talking about encrypted size and I was talking about the decrypted size. That's because of the padding. If you set PaddingMode to None you'll get 8 bytes if you really need that.

    huzzah, thank you!

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.