Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[C#] Duel Layer Encryption, with Decrypt

Newbie Spellweaver
Joined
Dec 1, 2010
Messages
28
Reaction score
8
Today, we will be looking at encryption.
Unfortunately, this tutorial won't cover exactly what encryption is, but simply how to implement it.

I have taken 2 types of encryption and merged them, getting a single result. This encryption is unique between 2 PC's (Client and Server), and can only be decrypted using the same hardware.



ORDER:
[Title]
Code:
[Description]
*****************************************************************

[B]Default.aspx.cs[/B]

[QUOTE]
using System;
using System.Globalization;

public partial class _Default : System.Web.UI.Page
{

    protected void Page_Load(object sender, EventArgs e)
    {
        //Set new keys in the Public And Private files.
        Cryptography.AssignNewKey();
    }

    protected void btnEncrypt_Click(object sender, EventArgs e)
    {
        /*
         * Process of Encryption
         * 
         * lblShield
         * lblEncrypt
         * lblShieldEncrypt
         */
        if (txtInput.Text != "")
        {
            //Apply first layer of encryption
            string shield = CryptoShield.EncryptToString(txtInput.Text);
            //Store it on a label
            lblShield.Text = shield;
            //lblShield.Text = StringCompression.Compress(shield);

            //Get the length of the text (Just informational)
            lblLength.Text = txtInput.Text.Length.ToString(CultureInfo.InvariantCulture);
            lblShieldLength.Text = " (" + lblShield.Text.Length.ToString(CultureInfo.InvariantCulture) + ")";

            //Apply second layer of encryption
            string encryptedShield = Cryptography.EncryptData(shield);
            //Display Encryption
            lblShieldEncrypt.Text = encryptedShield;
            
        }

    }
    protected void btnDecrypt_Click(object sender, EventArgs e)
    {
        /*
         * Process of Decryption
         * 
         * lblDeShieldDecrypt
         * lblDeShield
         */

        //Decrypt second layer
        string decryptShield = Cryptography.DecryptData(lblShieldEncrypt.Text);

        //Decrypt first layer
        string deShield = CryptoShield.DecryptString(decryptShield);

        //Display result.
        lblDeShield.Text = deShield;
    }
}

[/QUOTE]

This method will call the tow encryption methods, [Cryptography] and [CryptoShield], to take the plain text string, and format it with the encryption.

The 'Decrypt' button will call the same methods Decrypt procedure, only in reverse.

[B]CryptoShield.cs[/B]

[CODE]
using System;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Text;

/// <summary>
/// [CryptoShield.cs]
/// [Darren Whitfield]
/// [10/02/2012]
///  
/// This provides the first layer of Encryption for a string,
/// and the last layer of Decryption.
/// </summary>
public class CryptoShield
{
    private readonly byte[] _key = { Byte.Parse(GenerateEncryptionKey().ToString()), Byte.Parse(GenerateEncryptionKey().ToString()), Byte.Parse(GenerateEncryptionKey().ToString()), Byte.Parse(GenerateEncryptionKey().ToString()), Byte.Parse(GenerateEncryptionKey().ToString()), Byte.Parse(GenerateEncryptionKey().ToString()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //Replace 0's with your own numbers.
    private readonly byte[] _vector = { Byte.Parse(GenerateEncryptionVector().ToString()), Byte.Parse(GenerateEncryptionVector().ToString()), Byte.Parse(GenerateEncryptionVector().ToString()), Byte.Parse(GenerateEncryptionVector().ToString()), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //Replace 0's with your own numbers.

    private static int stringlength = 0;

    public CryptoShield()
    {
        //This is our encryption method
        var rm = new RijndaelManaged();

        //Create an encryptor and a decryptor using our encryption method, key, and vector.
        rm.CreateEncryptor(_key, _vector);
        rm.CreateDecryptor(_key, _vector);
    }


    /// -------------- Two Utility Methods (not used but may be useful) -----------
    /// Generates an encryption key.
    static private byte[] GenerateEncryptionKey()
    {
        //Generate a Key.
        var rm = new RijndaelManaged();
        rm.GenerateKey();
        return rm.Key;
    }

    /// Generates a unique encryption vector
    static private byte[] GenerateEncryptionVector()
    {
        //Generate a Vector
        var rm = new RijndaelManaged();
        rm.GenerateIV();
        return rm.IV;
    }


    /// ----------- The commonly used methods ------------------------------    
    /// Encrypt some text and return a string suitable for passing in a URL.
    public static string EncryptToString(string textValue)
    {
        stringlength = textValue.Length;
        return ByteArrToString(Encrypt(textValue + "Saltified"));
    }
    
    /// Encrypt some text and return an encrypted byte array.
    public static byte[] Encrypt(string textValue)
    {
        Encoding utfEncoder = new UTF8Encoding();
        ICryptoTransform icrypt = new ToBase64Transform();

        //Translates our text value into a byte array.
        Byte[] bytes = utfEncoder.GetBytes(textValue);

        //Used to stream the data in and out of the CryptoStream.
        var memoryStream = new MemoryStream();

        /*
         * We will have to write the unencrypted bytes to the stream,
         * then read the encrypted result back from the stream.
         */
        #region Write the decrypted value to the encryption stream
        var cs = new CryptoStream(memoryStream, icrypt, CryptoStreamMode.Write);
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
        #endregion

        #region Read encrypted value back out of the stream
        memoryStream.Position = 0;
        var encrypted = new byte[memoryStream.Length];
        memoryStream.Read(encrypted, 0, encrypted.Length);
        #endregion

        //Clean up.
        cs.Close();
        memoryStream.Close();

        return encrypted;
    }

    /// The other side: Decryption methods
    public static string DecryptString(string encryptedString)
    {
        return Decrypt(StrToByteArray(encryptedString)).Remove(stringlength, 9);
    }

    /// Decryption when working with byte arrays.    
    public static string Decrypt(byte[] encryptedValue)
    {
        Encoding utfEncoder = new ASCIIEncoding();
        ICryptoTransform icrypt = new FromBase64Transform();

        #region Write the encrypted value to the decryption stream
        var encryptedStream = new MemoryStream();
        var decryptStream = new CryptoStream(encryptedStream, icrypt, CryptoStreamMode.Write);
        decryptStream.Write(encryptedValue, 0, encryptedValue.Length);
        decryptStream.FlushFinalBlock();
        #endregion

        #region Read the decrypted value from the stream.
        encryptedStream.Position = 0;
        var decryptedBytes = new Byte[encryptedStream.Length];
        encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
        encryptedStream.Close();
        #endregion
        return utfEncoder.GetString(decryptedBytes);
    }

    /// Convert a string to a byte array.  NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so).
    //      System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    //      return encoding.GetBytes(str);
    // However, this results in character values that cannot be passed in a URL.  So, instead, I just
    // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100).
    public static byte[] StrToByteArray(string str)
    {
        if (str.Length == 0)
            throw new Exception("Invalid string value in StrToByteArray");

        var byteArr = new byte[str.Length / 3];
        int i = 0;
        int j = 0;
        do
        {
            byte val = byte.Parse(str.Substring(i, 3));
            byteArr[j++] = val;
            i += 3;
        }
        while (i < str.Length);
        return byteArr;
    }

    // Same comment as above.  Normally the conversion would use an ASCII encoding in the other direction:
    //      System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    //      return enc.GetString(byteArr);    
    public static string ByteArrToString(byte[] byteArr)
    {
        string tempStr = "";
        for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
        {
            byte val = byteArr[i];
            if (val < 10)
                tempStr += "00" + val.ToString(CultureInfo.InvariantCulture);
            else if (val < 100)
                tempStr += "0" + val.ToString(CultureInfo.InvariantCulture);
            else
                tempStr += val.ToString(CultureInfo.InvariantCulture);
        }
        return tempStr;
    }
}

The first layer of encryption, last layer of decryption.

Cryptography.cs

Code:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Web;

/// <summary>
/// [Cryptography.cs]
/// [Darren Whitfield]
/// [10/02/2012]
/// 
/// This is the last level of Encryption,
/// and the first level of Decryption.
/// </summary>
public class Cryptography
{
    public static RSACryptoServiceProvider Rsa;

    /// <summary>
    /// Allow us to use re-use previously created keys.
    /// </summary>
    public static void AssignParameter()
    {
        const int providerRsaFull = 1;
        const string containerName = "SpiderContainer";

        var cspParams = new CspParameters(providerRsaFull)
                            {
                                KeyContainerName = containerName,
                                Flags = CspProviderFlags.UseMachineKeyStore,
                                ProviderName = "Microsoft Strong Cryptographic Provider"
                            };

        Rsa = new RSACryptoServiceProvider(cspParams);
    }

    /// <summary>
    /// Encrypt data using Public Key.
    /// </summary>
    /// <param name="dataToEncrypt"></param>
    /// <returns></returns>
    public static string EncryptData(string dataToEncrypt)
    {
        AssignParameter();

        var reader = new StreamReader(HttpContext.Current.Server.MapPath("~") + "/publickey.xml");
        string publicOnlyKeyXML = reader.ReadToEnd();
        Rsa.FromXmlString(publicOnlyKeyXML);
        reader.Close();

        //read in plaintext, encrypt it to clipboard
        byte[] plainBytes = System.Text.Encoding.UTF8.GetBytes(dataToEncrypt);
        byte[] cipherBytes = Rsa.Encrypt(plainBytes, false);
        return Convert.ToBase64String(cipherBytes);
    }

    /// <summary>
    /// Get new Public and Private Keys
    /// </summary>
    public static void AssignNewKey()
    {
        AssignParameter();

        //provide public and private RSA params
        var writer = new StreamWriter(HttpContext.Current.Server.MapPath("~") + "/privatekey.xml");
        string publicPrivateKeyXML = Rsa.ToXmlString(true);
        writer.Write(publicPrivateKeyXML);
        writer.Close();

        //provide public only RSA params
        writer = new StreamWriter(HttpContext.Current.Server.MapPath("~") + "/publickey.xml");
        string publicOnlyKeyXML = Rsa.ToXmlString(false);
        writer.Write(publicOnlyKeyXML);
        writer.Close();
    }

    /// <summary>
    /// Decrypt data using Private Key
    /// </summary>
    /// <param name="dataToDecrypt"></param>
    /// <returns></returns>
    public static string DecryptData(string dataToDecrypt)
    {
        AssignParameter();

        byte[] getpassword = Convert.FromBase64String(dataToDecrypt);

        var reader = new StreamReader(HttpContext.Current.Server.MapPath("~") + "/privatekey.xml");
        string publicPrivateKeyXML = reader.ReadToEnd();
        Rsa.FromXmlString(publicPrivateKeyXML);
        reader.Close();

        //read ciphertext, decrypt it to plaintext
        byte[] plain = Rsa.Decrypt(getpassword, false);
        return System.Text.Encoding.UTF8.GetString(plain);
    }
}

The last layer of encryption, first layer of decryption.
 
JavaScript Is Best Script
Joined
Dec 13, 2010
Messages
631
Reaction score
131
Code:
     static private byte[] GenerateEncryptionKey()
    {
        //Generate a Key.
        var rm = new RijndaelManaged();
        rm.GenerateKey();
        return rm.Key;
    }

    /// Generates a unique encryption vector
    static private byte[] GenerateEncryptionVector()
    {
        //Generate a Vector
        var rm = new RijndaelManaged();
        rm.GenerateIV();
        return rm.IV;
    }

AFAIK, GenerateIV() and GenerateKey() uses System.Security.Cryptography.RandomNumberGenerator.GenerateBytes() so you could just use the latter without the need to explicitly initialize a RijndaelManaged object.

Secondly,
Code:
        var cs = new CryptoStream(memoryStream, icrypt, CryptoStreamMode.Write);
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
        .
        .
        .
        cs.Close();

Secondly, you are trying to dispose the cryptostream. Well you should and you must, but i think that the better way to dispose an IDisposable object (such as Stream objects), is as follows :

Code:
using (var cs = new CryptoStream(memoryStream, icrypt, CryptoStreamMode.Write))
{
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
}

It is important to note that cs.FlushFinalBlock() is part of the Dispose() procedure for CryptoStream and so is Close(), it may be the only procedure but it may not be as well. Furthurmore, the correct sequence they are carried out may differ from the sequence you are carrying them out, so you should let the CryptoStream implementation of the Stream handle the disposing itself.
 
Last edited:
Back
Top