Encrypting with DES with user input password - c#

I'm still studying cryptography. I'm trying to create a simple static function in C# that encrypts string to DES (with a Base64 ouput). I learned that DES use 8-Byte as its key. I want the user to input string of any length, use it as the key to encrypt the message, then convert it to Base64. Example is in this site.
public static string EncryptDES(string phrase, string key)
{
string encrypted = "";
byte[] phraseBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(phrase);
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key);
System.Security.Cryptography.MD5CryptoServiceProvider hashMD5Provider
= new System.Security.Cryptography.MD5CryptoServiceProvider();
System.Security.Cryptography.DESCryptoServiceProvider provider
= new System.Security.Cryptography.DESCryptoServiceProvider();
provider.Mode = System.Security.Cryptography.CipherMode.CBC;
System.Security.Cryptography.ICryptoTransform transform
= provider.CreateEncryptor(keyBytes, keyBytes);
System.Security.Cryptography.CryptoStreamMode mode
= System.Security.Cryptography.CryptoStreamMode.Write;
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
System.Security.Cryptography.CryptoStream cryptoStream
= new System.Security.Cryptography.CryptoStream(memStream, transform, mode);
cryptoStream.Write(phraseBytes, 0, phraseBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] encryptedMessageBytes = new byte[memStream.Length];
memStream.Position = 0;
memStream.Read(encryptedMessageBytes, 0, encryptedMessageBytes.Length);
encrypted = System.Convert.ToBase64String(encryptedMessageBytes);
return (encrypted);
} // private static string EncryptDES(string phrase, string key) { }
Then call it like this in Main:
SimpleEncryption.EncryptDES("A message regarding some secure 512-bit encryption", "AnUltimatelyVeryVeryLongPassword");
When a user inputs a random number of string length (whether greater than or less than 8 characters), a cryptographic exception always happens in this line:
System.Security.Cryptography.ICryptoTransform transform = provider.CreateEncryptor(keyBytes, keyBytes);
It says Specified key is not a valid size for this algorithm.
Removing parts of the key to fit in the length of 8 characters (with or without hashing) doesn't seems to be a secure solution (there might be a high rate of collision).
How can I implement DES (not 3DES) with a user input string?

You need to generate a hash from the user's password and take only 8 bytes to use as your key.
var fullHash = hashMD5Provider.ComputeHash(System.Text.Encoding.ASCII.GetBytes(key));
var keyBytes = new byte[8];
Array.Copy(fullHash , keyBytes, 8);
Your question expressed concern about hash collisions from throwing away part of the hash; yes, that certainly does increase the risk, but (assuming your hash algorithm is good) you're no worse off than if you just used a hash algorithm that only produced 8 bytes to begin with. A good hash algorithm should distribute the entropy evenly.

Related

What does the output of Rfc2898DeriveBytes depend on and how should the salt be treated?

public string Encrypt(string Code)
{
string result = string.Empty;
byte[] encryptResult = null;
var CodeInByte = Encoding.ASCII.GetBytes(Code);
try
{
using (MemoryStream memo = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = KeySize;
AES.BlockSize = BlockSize;
var key = new Rfc2898DeriveBytes(CodeInByte, salt, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var encrypt = new CryptoStream(memo, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
encrypt.Write(CodeInByte, 0, CodeInByte.Length);
encrypt.Close();
}
encryptResult = memo.ToArray();
}
}
result = Convert.ToBase64String(encryptResult);
return result;
}
catch (Exception err)
{
MsgCode = 99;
MsgDesc = err.Message;
return string.Empty;
}
}
It's just a simple AES encrypting method from string
The point I want to ask, when generating the key, at
var key = new Rfc2898DeriveBytes(CodeInByte, salt, 1000);
is the key generated from inputted string, or it's just a random generated byte array?
and, is the salt needs to be static or not
As the documentation on MSDN suggests:
Rfc2898DeriveBytes takes a password, a salt, and an iteration count, and then generates keys through calls to the GetBytes method.
In other words, it will derive bytes using the input parameters you give it. If you give it different parameters, the derived key will be different. If you give it the same parameters, it will generate the same bytes.
Symmetrical encryption algorithms (such as AES) require a fixed length key - 16 bytes in this case for AES128. However, you don't want to mandate that passwords are fixed length as this makes them much easier to attack. You also might want much longer keys than a feasible password - AES256 would require a 32byte key, for example. Finally, passwords tend to be alphanumeric and perhaps have some symbols, whereas an encryption key is made up of bytes that can range from 0x00-0xFF, if you made the encryption key a 32 character ASCII password, then you'd reduce the range quite considerably as the printable ASCII character range is much smaller than 0x00-0xFF.
For this reason, you want to derive the encryption key from a given password in such a way that you get a strong key of the exact length you require. That's where Rfc2898DeriveBytes comes in.

How to encrypt a guid into equal length string in C#?

I need to encrypt a guid and the encrypted string length should be 32 char max, not more than that. Please suggest me an encryption method available in C# for that.
I was using AES in CFB mode, as in Code Project, but that is producing 64 char long.
Well, a GUID is inherently 16 bytes of data... so that's what you should encrypt. That's a single block in AES. As per Reid's comment, the exact size of the output will depend on how you've configured things, but to convert the result into text, you'll probably want to use base64 if you need ASCII text with a fairly minimal size.
Base64 allows you to use 24 bytes to produce a 32 character result - so you should try different padding/cipher modes until you find one where the output is 24 bytes or less, if this 32 character requirement is a "hard" one (and you need ASCII; if you don't need ASCII then there's a lot more room to play...)
If a GUID is 16 bytes (I'll take that as a given) then you can simply do a single AES ECB mode encrypt without padding of the plaintext (i.e. the GUID). You can then convert to hexadecimals. That will with 100% certainty result in a 32 character result.
Note that ECB does not use an IV, which means that you can distinguish different GUID's from each other (as each GUID will be mapped to exactly one ciphertext). But the ciphertext should otherwise simply be identical to the security of the used block cipher and key.
public class EncryptGUI
{
private Aes aes;
public EncryptGUI (byte[] key)
{
aes = Aes.Create ();
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
aes.Key = key;
}
public String encryptUID (byte[] guid)
{
ICryptoTransform aesDecryptor = aes.CreateDecryptor ();
byte[] result = aesDecryptor.TransformFinalBlock (guid, 0, guid.Length);
return ToHex (result);
}
public static string ToHex (byte[] data)
{
StringBuilder hex = new StringBuilder (data.Length * 2);
foreach (byte b in data)
hex.AppendFormat ("{0:x2}", b);
return hex.ToString ();
}
public static void Main (string[] args)
{
byte[] key = new byte[16];
EncryptGUI main = new EncryptGUI (key);
byte[] guid = new byte[16];
Console.Out.WriteLine (main.encryptUID (guid));
}
}

MD5 encode and decode [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a function md5_encode
public string MD5_encode(string str_encode)
{
MD5 md5Hash = MD5.Create();
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(str_encode));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
i can't decode it. I search in internet and found something like that
public static string Encrypt(string toEncrypt, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
// Get the key from config file
string key = (string)settingsReader.GetValue("SecurityKey", typeof(String));
//System.Windows.Forms.MessageBox.Show(key);
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
hashmd5.Clear();
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
tdes.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
but i don't know that code work, Someone help me, decode function MD5_encode(string str_encode) or show me detail about different MD5_encode(string str_encode) and Encrypt(string toEncrypt, bool useHashing)
tks a lot for any help :)
MD5_encode uses MD5 (a cryptographic hash function) to generate a hash. The name is misleading as it isn't an encoding. A hash generate a value of a fixed size independent of the input, and cryptographic hash are especially designed not to be reversible.
Encrypt uses Triple DES to encrypt the input using as key either a value stored in the settings or the hash of this value.
You can decrypt the result of Encrypt using tdes.CreateDecryptor after removing the Base64 encoding.
PS: 3DES is old, you should use something more recent like AES
PS: ECB is insecure in a lot of cases, you should at least use CBC with a random IV.
Although MD5 is susceptible to a number of attacks that prove otherwise, MD5 is a hashing method. Hashes are designed to be one-way only. Just imagine if all of the hashing algorithms in the world today allowed anyone to easily get the original data from the hash data! Eeeeek!

How to retrieve IV from an Encrypted string, then decrypt that string using AES128

I know very little about Encryption, but my goal is to essentially decrypt strings. I have been given the AES(128) key.
However, I must retrieve the IV from the Encrypted string, which is the first 16 bits.
Heres the doc for salesforce for more information (if what i explained was incorrect)
Encrypts the blob clearText using the specified algorithm and private
key. Use this method when you want Salesforce to generate the
initialization vector for you. It is stored as the first 128 bits (16
bytes) of the encrypted blob
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_crypto.htm (encryptWithManagedIV)
For Retrieving the IV I've tried something like this (I don't believe it's right though):
public string retrieveIv()
{
string iv = "";
string input = "bwZ6nKpBEsuAKM8lDTYH1Yl69KkHN1i3XehALbfgUqY=";
byte[] bytesToEncode = Encoding.UTF8.GetBytes(input);
for(int i = 0; i <= 15; i++){
iv += bytesToEncode[i].ToString(); ;
}
return iv;
}
(Just ignore the fact that the input is hardcoded and not parameterized; easier for testing purposes)
Then use the Best answer from this question to decrypt the string
The IV shouldn't be expressed as a string - it should be as a byte array, as per the AesManaged.IV property.
Also, using Encoding.UTF8 is almost certainly wrong. I suspect you want:
public static byte[] RetrieveIv(string encryptedBase64)
{
// We don't need to base64-decode everything... just 16 bytes-worth
encryptedBase64 = encryptedBase64.Substring(0, 24);
// This will be 18 bytes long (4 characters per 3 bytes)
byte[] encryptedBinary = Convert.FromBase64String(encryptedBase64);
byte[] iv = new byte[16];
Array.Copy(encryptedBinary, 0, iv, 0, 16);
return iv;
}

Get the length of a CryptoStream in .Net

I'm working on software which encrypts/decrypts files.
I would like to be able to guess the length of the data after the encryption but I can't use CryptoStream.Length (It throws a NotSupportedException).
Is there any way to guess it ?
I'm using RijndaelManaged (.Net Framework 4.0)
This says it much better than I can
http://www.obviex.com/Articles/CiphertextSize.aspx
From there:
In the most generic case, the size of the ciphertext can be calculated as:
CipherText = PlainText + Block - (PlainText MOD Block)
where CipherText, PlainText, and Block indicate the sizes of the ciphertext, plaintext, and encryption block respectively. Basically, the resulting ciphertext size is computed as the size of the plaintext extended to the next block. If padding is used and the size of the plaintext is an exact multiple of the block size, one extra block containing padding information will be added.
Let's say that you want to encrypt a nine-digit Social Security Number (SSN) using the Rijndael encryption algorithm with the 128-bit (16-byte) block size and PKCS #7 padding. (For the purpose of the illustration, assume that dashes are removed from the SSN value before the encryption, so that "123-45-6789" becomes "123456789", and the value is treated as a string, not as a number.) If the digits in the SSN are defined as ASCII characters, the size of the ciphertext can be calculated as:
CipherText = 9 + 16 - (9 MOD 16) = 9 + 16 - 9 = 16 (bytes)
Notice that if the size of the plaintext value is the exact multiple of the block size, an extra block containing padding information will be appended to the ciphertext. For example, if you are to encrypt a 16-digit credit card number (defined as a 16-character ASCII string), the size of the ciphertext will be:
CipherText = 16 + 16 - (16 MOD 16) = 16 + 16 - 0 = 32 (bytes)
That depends on the cipher you use... usually the length is the same as the length of the original stream... worstcase is that it gets padded to a multiple of the block length of the cipher
This is my code with RijndaelManaged:
MemoryStream textBytes = new MemoryStream();
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsInput = new FileStream(#"C:\myEncryptFile.txt", FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsInput, RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
cs.CopyTo(textBytes);
cs.Close();
fsInput.Close();
string myDecriptText = Encoding.UTF8.GetString(textBytes.ToArray());
You can use this function to get both length and data.
public static int GetLength(CryptoStream cs, out byte[] data)
{
var bytes = new List<byte>();
int b;
while ((b = cs.ReadByte()) != -1)
bytes.Add((byte)b);
data = bytes.ToArray();
return data.Length;
}

Categories

Resources