How to get fixed size key from user input - c#

Just want to know, If I use TripleDES encryption (keysize (168)192bits) and ask the key from the user and the user gives a key which might be more or less in size compare to actual size of the cipher then what should I do? Should I just add 0s or 1s using String.PadLeft or String.PadRight to the key? Is there any built in methods/idea/library/tricky codes to add random strings to the key? If so, then is it possible to reverse the process?
I was hoping to use hashing algorithm but .Net doesn't support any hashing algorithm with output size 192bits. So is there any solution to this?
This simple code is to make it more clear: (encryption part only)
static void Main(string[] args)
{
Console.WriteLine("Enter Plain Text: ");
string original = Console.ReadLine();
Console.WriteLine("Enter The Key: ");
string keyString = Console.ReadLine();
byte[] data = Encoding.UTF8.GetBytes(original);
byte[] key = Encoding.UTF8.GetBytes(keyString);
TripleDESCryptoServiceProvider myTripleDES = new TripleDESCryptoServiceProvider();
byte[] encrypted = EncryptString(data, key, myTripleDES.IV);
string encrypt = Convert.ToBase64String(encrypted);
string decrypted = DecryptStringFromBytes(encrypted, key, myTripleDES.IV);
Console.WriteLine("encryted: " + encrypt);
Console.WriteLine("decrypted: " + decrypted);
Console.ReadLine();
}
static byte[] EncryptString(byte[] data, byte[] Key, byte[] IV)
{
TripleDESCryptoServiceProvider tdsAlg = new TripleDESCryptoServiceProvider();
tdsAlg.BlockSize = 64;
tdsAlg.KeySize = 192;
tdsAlg.Padding = PaddingMode.PKCS7;
tdsAlg.Mode = CipherMode.CBC;
tdsAlg.Key = Key;
tdsAlg.IV = IV;
ICryptoTransform encryptor = tdsAlg.CreateEncryptor(tdsAlg.Key, tdsAlg.IV);
byte[] encrypted = encryptor.TransformFinalBlock(data, 0, data.Length);
Console.WriteLine("The Cipher length: " + encrypted.Length);
return encrypted;
}
This code will not work until I give (valid) fixed size key input. And my question is what is the best way to achieve this?

Related

How to fix invalid key size when decrypting data in C# that was encrypted in php

I am trying to solve an encryption issue I am having between php and c#.
I have encrypted data using the following php and openssl operation.
$encrypt_method = "AES-256-CBC";
$secret_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$secret_iv = 'XXXXXXXXXXXXXXXX';
$key = hash ('sha256', $secret_key);
$iv = substr (hash ('sha256', $secret_iv), 0, 16);
$output = openssl_encrypt ($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode ($output);
I have tried a couple of methods in C# to decrypt but this is what I am trying now.
public string Encrypt_Decrypt(string action, string value) {
string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string secretIV = "XXXXXXXXXXXXXXXX";
string key = Hash(secretKey);
string iv = Hash(secretIV).Substring(0,16);
string retValue = "";
if (action == "encrypt") {
retValue = EncryptString(value, key, iv);
}
else if (action == "decrypt") {
retValue = DecryptString(value, key, iv);
}
}
// Hash to match php hash function
public static string Hash(string unhashedString) {
return BitConverter.ToString(new SHA256CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(unhashedString))).Replace("-", String.Empty).ToLower();
}
public static string DecryptString(string cipherData, string keyString, string ivString) {
byte[] key = Encoding.UTF8.GetBytes(keyString);
Console.WriteLine(key.Length);
byte[] iv = Encoding.UTF8.GetBytes(ivString);
Console.WriteLine(iv.Length);
byte[] cipherCrypt = Convert.FromBase64String(cipherData);
for (int i = 0; i < cipherCrypt.Length; i++) {
Console.Write(cipherCrypt[i] + " ");
}
try {
RijndaelManaged crypto = new RijndaelManaged();
crypto.Key = key;
crypto.IV = iv;
crypto.Mode = CipherMode.CBC;
crypto.KeySize = 256;
crypto.BlockSize = 128;
crypto.Padding = PaddingMode.None;
ICryptoTransform decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV);
using (MemoryStream memStream = new MemoryStream(cipherCrypt)) {
using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) {
using (StreamReader streamReader = new StreamReader(cryptoStream)) {
return streamReader.ReadToEnd();
}
}
}
}
catch (CryptographicException e) {
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
I have tried a couple different encoding types when getting the byte[] for the operation.
I keep getting the following error:
Specified key is not a valid size for this algorithm.
Not sure what I am missing. Any help is appreciated.
Also, I already read through this and tried what the solution suggestion recommended. I got the same resulting error.
UPDATE - 01
I have updated the code here to reflect the code I have changed.
The key length is 32,
The iv length is 16,
The data coming in at "cipherData" is length 32,
When "cipherData" goes through "FromBase64String(cipherData)" it comes out as a 24 byte array. This is causing an issue for the decryptor which wants a 32 byte array.
There are obviously problems with the key size. The code between PHP and C# seem to match. The problem seems to be that the code is wrong in both cases.
Let's see how long the key actually is:
Start with a 32 byte key (non-encoded).
Hash the key with SHA-256: 32 bytes (non-encoded).
Encode to hex (integrated into PHP's hash() function by default): 64 bytes.
AES only supports the following key sizes: 16, 24 and 32 bytes. openssl_encrypt() will only use the first 32 bytes of the hex key silently. So, you need to use the first 32 bytes in C#.
Note that openssl_encrypt() takes an options argument which denotes that the output is Base64 when OPENSSL_RAW_DATA is not set. It means that the PHP output was encoded twice with Base64. So you need to decode it twice in C#.

Restricting rijndaelmanaged algorithm key size?

I am using rijndaelmanaged algoritham for password encryption
Is there a way to restrict the size of the encrypted text key?
eg:1, ABC - Encrypted key size 10
2, ABCDHGF - Encrypted key size 10
Means Fixed size !!
If you do not need to have password back from encrypted data, you can use hash algorithms. First compute the hash value for the password and then encrypt this hash value. Since hash values have fixed length your encrypted data will have a fixed length. When you need to check a password, decrypt the encrypted value and recalculate hash value from entered password then check if they match.
For example on a sign up page
var encryptedPwd = Encrypt(ComputeHash(txtPassword.Text));
Save(txtUsername.Text, encryptedPwd);
And on a login page
var encryptedPwd = SelectPwd(txtUsername.Text);
var pwdHash1 = Decrypt(encryptedPwd);
var pwdHash2 = ComputeHash(txtPassword.Text);
if (AreEqual(pwdHash1, pwdHash2))
// Login OK!
else
// Login fail
Another option could be making a custom padding. Say your passwords will have max length of 16 characters. Then you can pad every password to 16 chars with some fixed char. Then encrypt this padded password. It would be easier for validation but using hash is a bit more secure.
Sign up
var encryptedPwd = Encrypt(txtPassword.Text.PadRight(16, 'X'));
Save(txtUsername.Text, encryptedPwd);
Login
var encryptedPwd = SelectPwd(txtUsername.Text);
var pwd1 = Decrypt(encryptedPwd);
var pwd2 = txtPassword.Text.PadRight(16, 'X');
if (AreEqual(pwd1, pwd2))
// Login OK!
else
// Login fail
Instead of using a simple hash, it's suggested to use a password-strengthening algorithm, like the one specified in Rfc2898
string password = "P#$$w0rd";
byte[] salt = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; // this is fixed... It would be better you used something different for each user
// You can raise 1000 to greater numbers... more cycles = more security. Try
// balancing speed with security.
Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(password, salt, 1000);
// generate key and iv
byte[] key = pwdGen.GetBytes(16);
byte[] iv = pwdGen.GetBytes(16);
byte[] encrypted;
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Key = key;
rijndaelCipher.IV = iv;
// Or your data
byte[] data = System.Text.Encoding.UTF8.GetBytes("hello world");
var encryptor = rijndaelCipher.CreateEncryptor();
encrypted = encryptor.TransformFinalBlock(data, 0, data.Length);
}
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Key = key;
rijndaelCipher.IV = iv;
var decryptor = rijndaelCipher.CreateDecryptor();
byte[] decrypted = decryptor.TransformFinalBlock(encrypted, 0, encrypted.Length);
// this if you are encrypting text, otherwise decrypted is already your data
string text = System.Text.Encoding.UTF8.GetString(decrypted);
}

Decrypt TripleDES "Bad Data"

I'm new to encryption/decryption. I'm trying to decrypt an input string that is encrypted and comes out to 44 characters.
This is what I have so far but I keep getting "bad data" when it attempts to execute the "TransformFinalBlock" function.
public static String Decrypt(String input)
{
try{
byte[] inputArray = Convert.FromBase64String(input);
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
tripleDES.KeySize = 128;
tripleDES.Key = UTF8Encoding.UTF8.GetBytes("0123456789ABCDEF");
tripleDES.IV = UTF8Encoding.UTF8.GetBytes("ABCDEFGH");
tripleDES.Mode = CipherMode.ECB;
tripleDES.Padding = PaddingMode.PKCS7;
ICryptoTransform transform = tripleDES.CreateDecryptor();
byte[] resultArray = transform.TransformFinalBlock(inputArray, 0, inputArray.Length);
tripleDES.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
}
catch(Exception except){
Debug.WriteLine(except + "\n\n" + except.StackTrace);
return null;
}
}
If you use an IV, then you should use CipherMode.CBC. ECB does not use any IV.
In addition, your data is not padded at all, it contains exactly 32 bytes. To test decryption, it is common to try without padding first. That way you can determine by eye which padding is used by looking at the resulting plaintext.
The plain data is too corny to print here, so I won't.
I had a very similar issue and i fixed it by changing the PaddingMode to None
My CipherMode is ECB (Electronic code book).

Cryptography - remote SQL Server + desktop app

I'm developing a desktop app. that should work over Internet and communicate with remote DB. App's data have to be encrypted wile transfer.
The simplest way is to create the static key and use it while read-write the data from DB. But if I do so I would not be able to change that key. I suppose there are solutions that allow to solve this problem.
Can you tell, please, how do developers operate when they need dynamic encryption in their app's?
Thank you
Copy this code and test it anyway you want.. WPF Console App ect..
using System;
using System.Security.Cryptography;
using System.Text;
public static class DataEncryption
{
public static string Encrypt(string input, string key)
{
byte[] inputArray = UTF8Encoding.UTF8.GetBytes(input);
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
tripleDES.Mode = CipherMode.ECB;
tripleDES.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tripleDES.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
tripleDES.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string Decrypt(string input, string key)
{
byte[] inputArray = Convert.FromBase64String(input);
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
tripleDES.Mode = CipherMode.ECB;
tripleDES.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tripleDES.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
tripleDES.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
}
}
this should give you an idea of what I am talking about.
that should work over Internet and communicate with remote DB
This is one of the things that happens with SSL/TLS. The server and client set up a secure channel that eavesdroppers cannot intercept. I'd recommend reading the book Applied Cryptography to learn how this, and other similar protocols work. PGP is a reasonably familiar application that you may wish to study.
how do developers operate when they need dynamic encryption in their apps?
Generally, previous employers have used self-generated public key certificates. Depending on the business needs, either each version of the software gets a different cert, or each user gets a different cert (this ends up as part of the license key that each user gets). If one is leaked, that individual certificate can be revoked.
If you need to encrypt data for transfer only, then you should use an encrypted (i.e. SSL/TLS) connection. MS SQL Server supports this:
Encrypting Connections to SQL Server
How To Do Simple Encryption
Try this Code as well it also works really well .. basically what ever string you want encrypted just pass that string to the methods you may have to alter the code to work for your project feel fee to consume the code as you please.
using System;
using System.Text;
using System.Security.Cryptography;
namespace EncryptStringSample
{
class MainClass
{
public static string EncryptString(string Message, string Passphrase)
{
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
// Step 1. We hash the passphrase using MD5
// We use the MD5 hash generator as the result is a 128 bit byte array
// which is a valid length for the TripleDES encoder we use below
MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
// Step 2. Create a new TripleDESCryptoServiceProvider object
TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();
// Step 3. Setup the encoder
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
// Step 4. Convert the input string to a byte[]
byte[] DataToEncrypt = UTF8.GetBytes(Message);
// Step 5. Attempt to encrypt the string
try
{
ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
}
finally
{
// Clear the TripleDes and Hashprovider services of any sensitive information
TDESAlgorithm.Clear();
HashProvider.Clear();
}
// Step 6. Return the encrypted string as a base64 encoded string
return Convert.ToBase64String(Results);
}
public static string DecryptString(string Message, string Passphrase)
{
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
// Step 1. We hash the passphrase using MD5
// We use the MD5 hash generator as the result is a 128 bit byte array
// which is a valid length for the TripleDES encoder we use below
MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));
// Step 2. Create a new TripleDESCryptoServiceProvider object
TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();
// Step 3. Setup the decoder
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
// Step 4. Convert the input string to a byte[]
byte[] DataToDecrypt = Convert.FromBase64String(Message);
// Step 5. Attempt to decrypt the string
try
{
ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
}
finally
{
// Clear the TripleDes and Hashprovider services of any sensitive information
TDESAlgorithm.Clear();
HashProvider.Clear();
}
// Step 6. Return the decrypted string in UTF8 format
return UTF8.GetString( Results );
}
public static void Main(string[] args)
{
// The message to encrypt.
string Msg = "This world is round, not flat, don't believe them!";
string Password = "secret";
string EncryptedString = EncryptString(Msg, Password);
string DecryptedString = DecryptString(EncryptedString, Password);
Console.WriteLine("Message: {0}",Msg);
Console.WriteLine("Password: {0}",Password);
Console.WriteLine("Encrypted string: {0}",EncryptedString);
Console.WriteLine("Decrypted string: {0}",DecryptedString);
}
}
}

Create unique encryption

It is use to encrypt a string to create a unique fingerprint like 8FAC-5806-FF54-4174-F89E-43DE-97A6-5648.
How can I convert it back from the 8FAC-5806-FF54-4174-F89E-43DE-97A6-5648 to the string?
MD5 is single encryption, so have to use tripleDES to retrieve it back. but how to create a string like this 8FAC-5806-FF54-4174-F89E-43DE-97A6-5648 using the method below:
public static string Encrypt(string strToEncrypt, string strKey)
{
try
{
TripleDESCryptoServiceProvider objDESCrypto = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider objHashMD5 = new MD5CryptoServiceProvider();
byte[] byteHash, byteBuff;
string strTempKey = strKey;
byteHash = objHashMD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(strTempKey));
objHashMD5 = null;
objDESCrypto.Key = byteHash;
objDESCrypto.Mode = CipherMode.ECB; //CBC, CFB
byteBuff = ASCIIEncoding.ASCII.GetBytes(strToEncrypt);
return Convert.ToBase64String(objDESCrypto.CreateEncryptor().TransformFinalBlock(byteBuff, 0, byteBuff.Length));
}
catch (Exception ex)
{
return "Wrong Input. " + ex.Message;
}
}
The code uses MD5 to generate the fingerprint. MD5 is a one-way hashing algorithm. This means that it's not possible to reverse the algorithm to get the original value back. Hashing is not encryption. If you want to encrypt your string and be able to decrypt it, you need to use an encryption algorithm such as AES.

Categories

Resources