Error in C# encrypt code when decrypting! - c#

A bit more background info as suggested:
I'm finsihing of an Intranet CMS web app where I have to use the products API (ASP.NET based). Because of time constraints and issues with Windows authen' I need another way to ensure staff do not need to re login everytime they visit the site to view personalised content. The way it works is that once a user logs in (username/password), a Session ID storing a new different Security context value is generated that is used to display the personalised content. The API login method called uses the username and password as parameters. The only way I can think of automatically logging in the next time the staff visits the site is by storing the password in a enrypted cookie and checking of its existing when the site is visited and then calling the API login method using the username and decrypted password cookie values.
Any other ideas as an alternative welcomed.
Mo
Hi,
I'm using some code found on the web to encrypt and decrypt a password string. It encrypts fine but when it calls the code below to decrypt the string it throws the error "Length of the data to decrypt is invalid" How can I resolve this?
Thanks in advance.
Mo
System.Text.Encoding enc = System.Text.Encoding.ASCII;
byte[] myByteArray = enc.GetBytes(_pword);
SymmetricAlgorithm sa = DES.Create();
MemoryStream msDecrypt = new MemoryStream(myByteArray);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(), CryptoStreamMode.Read);
byte[] decryptedTextBytes = new Byte[myByteArray.Length];
csDecrypt.Read(decryptedTextBytes, 0, myByteArray.Length);
csDecrypt.Close();
msDecrypt.Close();
string decryptedTextString = (new UnicodeEncoding()).GetString(decryptedTextBytes);

A couple of things here...
You shouldn't encrypt passwords usually. You should hash them.
If you decide to continue down the road of encryption..
You are using the DES algorithm. This is considered insecure and flawed. I'd recommend looking at the AES algorithm.
Depending on how much data you are working with, the CryptoStream might be overkill.
Using the ASCII encoding can cause loss of data that isn't ASCII, like Cyrillic letters. The recommended fix is to use something else, like UTF8.
Here is an example:
string text = "Hello";
using (var aes = new AesManaged())
{
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
byte[] encryptedBytes;
using (var encrypt = aes.CreateEncryptor())
{
encryptedBytes = encrypt.TransformFinalBlock(bytes, 0, bytes.Length);
}
byte[] decryptedBytes;
using (var decrypt = aes.CreateDecryptor())
{
decryptedBytes = decrypt.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
}
var decryptedText = System.Text.Encoding.UTF8.GetString(decryptedBytes);
Console.Out.WriteLine("decryptedText = {0}", decryptedText);
}
This will use a random key every time. It is likely that you will need to encrypt some data, then decrypt it at a later time. When you create the AesManaged object, you can store the Key and IV property. You can re-use the same Key if you'd like, but different data should always be encrypted with a different IV (Initialization Vector). Where you store that key, is up to you. That's why hashing might be a better alternative: there is no key, and no need to worry about storing the key safely.
If you want to go down the hashing route, here is a small example:
var textToHash = "hello";
using (SHA1 sha = new SHA1Managed())
{
var bytesToHash = System.Text.Encoding.UTF8.GetBytes(textToHash);
var hash = sha.ComputeHash(bytesToHash);
string base64hash = Convert.ToBase64String(hash);
}
This uses the SHA1 algorithm, which should work fine for passwords, however you may want to consider SHA256.
The concept is simple: a hash will produce a (mostly) unique output for an input, however the output cannot be converted back to the input - it's destructive. Whenever you want to check if a user should be authenticated, check hash the password they gave you, and check it against the hash of the correct password. That way you aren't storing anything sensitive.

I've actually had this error before and it took me 3 days to figure out the solution. The issue will be the fact that the machine key you need for descryption needs to be registered on your machine itself.
Read fully up on DES encryption, it works by an application key, and a machine-level key. The error you're getting is likely because of the machine key missing.

Compare the bytes used to create the _pword string (in the encryption method) to the bytes retrieved with GetBytes. Probably you will notice a change in the data there.
To store the encrypted bytes, I think you should use Convert.ToBase64String and Convert.FromBase64String turn the encrypted password to/from a string.
I also do not see the code where you set the Key and IV. So I guess you are using a different key to encrypt and decrypt the password.
If the current Key property is null,
the GenerateKey method is called to
create a new random Key. If the
current IV property is null, the
GenerateIV method is called to create
a new random IV.

DES is a block based cipher - only certain lengths of buffers are valid. If I remember correctly, the block size for DES is 64 bits, so you need to ensure that your byte array is a multiple of 8 bytes long.
(That should fix your immediate problem, but I'd reference other peoples advice here - you really ought not to be using DES for any new code, and for passwords it's usually more appropriate to hash than to encrypt).

Related

Key, salt and IV when using Rijndael encryption

I'm working on a website, where users are able to upload files. I want to encrypt these files, in case there is some kind of security breach where access is granted to them.
When the user wants to download their files, I decrypt directly to the HTTP(S) output stream.
The files are placed on disc, and a record for each is inserted in the website database with some additional data (file name, size, file path, IV and such).
I only have a basic understanding of how to use encryption and therefore have some questions.
I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?
Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?
Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.
I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?
This is my code for encryption. Any obvious security flaws?
const int bufferSize = 1024 * 128;
Guid guid = Guid.NewGuid();
string encryptedFilePath = Path.Combine(FILE_PATH, guid.ToString());
byte[] rgbIV;
using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes("PASSWORD HERE", Encoding.ASCII.GetBytes("SALT HERE")))
{
byte[] rgbKey = deriveBytes.GetBytes(256 / 8);
using (FileStream decryptedFileStream = File.OpenRead(decryptedFilePath))
using (FileStream encryptedFileStream = File.OpenWrite(encryptedFilePath))
using (RijndaelManaged algorithm = new RijndaelManaged() { KeySize = 256, BlockSize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 })
{
algorithm.GenerateIV();
rgbIV = algorithm.IV;
using (ICryptoTransform encryptor = algorithm.CreateEncryptor(rgbKey, rgbIV))
using (CryptoStream cryptoStream = new CryptoStream(encryptedFileStream, encryptor, CryptoStreamMode.Write))
{
int read;
byte[] buffer = new byte[bufferSize];
while ((read = decryptedFileStream.Read(buffer, 0, bufferSize)) > 0)
cryptoStream.Write(buffer, 0, read);
cryptoStream.FlushFinalBlock();
}
}
}
I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?
The recent efficient breakage of SHA-1 really only impacts collision resistance which is not needed for PBKDF2 (the algorithm behind Rfc2898DeriveBytes). See: Is PBKDF2-HMAC-SHA1 really broken?
Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?
Maybe it will give additional security, but it certainly won't hurt to do this except if you add a bug. Source: Need for salt with IV
Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.
Usually, a storage system has checks and procedures to prevent and fix data corruption. If you don't have that, then a MAC is a good way to check if the data was corrupted even if this didn't happen maliciously.
If the end user is supposed to receive the data, they can check the MAC themselves and make sure that nobody altered the ciphertext.
I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?
As I understand, you actually want to hold the encryption/decryption key. Anything that you can do is really obfuscation and doesn't provide any actual security. An attacker might just use the same connection to the data storage as your usual code. At best, the attacker will be slowed down a little bit. At worst, they don't even notice that the data was encrypted, because the decryption happened transparently.
It is best to make sure that an attacker cannot get in. Go through the OWASP top 10 and try to follow the advice. Then you can do some security scanning with Nikto or hire a professional penetration tester.
This is my code for encryption. Any obvious security flaws?
Using PaddingMode.ISO10126 doesn't seem like a good idea. You should go with PKCS#7 padding. Source: Why was ISO10126 Padding Withdrawn?
Rfc2898DeriveBytes is essentially PBKDF2 which is NIST recommended.
IF you randomize the salt (a good security practice) would will have top supply it for decryption. A common way is to prefix the encrypted data with the salt and IV.
Yes, you should be using a Mac over the encrypted data and any prepended information such as above.
In order to provide suggestions on securing the encryption key more information on how the the encryption will be used.
Use PKCS#7 padding, sometimes the option is named PKCS#5 for historical reasons.

Rijndael Cryptography Function - Key/IV/Salt Setup

I'm working on a simple utility to encrypt files as a learning experience.
Everything seems to be working fine, but I'm wondering if I have setup the Key/IV/Salt data securely.
I have noticed that when it comes to cryptography most people seem to envision a working environment that is loaded with malware manned by a wizard remotely ready to dive through the memory of a running application/page file to get at these secure files.
Let's pretend that you're on a clean machine and you encrypt some files and turn off your computer.
What I want to know is whether or not someone can take your hard drive and retrieve the contents of the files using the code I have proposed.
The attack vector I am most concerned with is ensuring that the page files/file caches are inaccessible.
I also want to make sure that the Key/IV system used is not going to make a rainbow table/hash based attack feasible.
Entering the Password:
The password is entered using a text box with the passwordchar value set to true.
I'm not really concerned with the string being in memory as long as it is properly removed after the encryption. I read that using SecureString is kind of pointless at this point because if you have malware on your computer already, you could just as easily have a keylogger on there which renders everything else useless.
private static string salt = "02341235XadfaDADFexA8932F7Dz3J3X";
I salt the password using a hard coded 32 character string.
(The above string is just an example.)
To get at it, it will require someone to decompile/view the .exe file itself with a hex editor (something that I know if very easy to do, but an extra step nonetheless).
I have considered making this salt editable, but I'm not sure how I could securely store it. I think it's a little ridiculous to encrypt your salt because then you will have the same issue etc, so just leaving it as a hard coded string inside the exe itself seems to make the most sense to me.
The way this works is if you decide to make your password "thepassword", it is actually saved as "thepasswordfaDADFexA8932F7Dz3J3X".
The main key here is that you always have a 32 character password, regardless of what you enter.
The Key and IV:
The Key and IV are also salted as follows.
This is what I wanted to get some input on, because to be honest I'm not entirely sure what it's doing:
UnicodeEncoding UE = new UnicodeEncoding();
byte[] keysalt = UE.GetBytes("Xjafe231x42X423XadXCadfkhjeAdS"); //Another string of random characters hard coded in the exe
byte[] IVSodium = UE.GetBytes("83Xkda7l78Dkx85KdJazppoqq6SaxDs"); //Another string of random characters hard coded in the exe
byte[] key = new Rfc2898DeriveBytes(password, keysalt).GetBytes(32); //Derive the key using the password and salt
byte[] IV = new Rfc2898DeriveBytes(password, IVSodium).GetBytes(16); //Derive the IV using the password and salt
My main concern here is that the IV is based on the key. Again, I'm not sure if this will cause any issues and I was hoping you guys could let me know if there are issues, what they are.
Also, is this another scenario where hard coding the salt is a bad practice? Should this be stored in the encrypted file, and if so, does it really make it more secure? Should I make this editable as well?
The crypto streams are setup using the using keyword:
using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create))
{
using (RijndaelManaged RMCrypto = new RijndaelManaged())
{
using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
byte[] buffer = new byte[4096]; //4096 is kind of arbitrary - better idea?
int data;
long bytesRead = 0;
while((data = fsIn.Read(buffer, 0, buffer.Length)) > 0)
{
bytesRead += data;
/////////////////////////////////////////
// Handle Aborts and Update Progress Bar
/////////////////////////////////////////
if (!caller.isClosing)
caller.Invoke((MethodInvoker)delegate {
caller.fileProgressBar.Value = ((int)(((double)bytesRead / totalBytes) * 100));
});
else
return false; //Encryption Aborted
/////////////////////////////////////////
cs.Write(buffer, 0, data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
return true;
}
}
}
}
}
Thanks for your time and please let me know if there is a better way to setup the Key/IV/Salt.
I think that it is most likely secure enough as long as there is not a mathematical issue with the IV and Key containing similar characters. If so, should I use a hard coded IV as well? That seems weird.
Note that I'm not saving a hash of the password or anything like that. The password is not saved anywhere. It is just used to generate the Key and the IV.
Thanks for your time.
Edit: Here are the changes recommended for anyone looking in the future.
Note that this is not using a pepper - just a random salt, although it would be easy enough to add
byte[] salt = new byte[32]; //Create a 32 byte salt
rand.NextBytes(salt); //Fill it with random values (use RandomNumberGenerator rand = new RNGCryptoServiceProvider(); to be safe
byte[] IV = new byte[16]; //Create a 16 byte IV
rand.NextBytes(IV); //Fill it with random numbers
byte[] key = new Rfc2898DeriveBytes(password, salt).GetBytes(32); //Derive our Key by mixing our password with the salt
using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create))
{
using (RijndaelManaged RMCrypto = new RijndaelManaged())
{
using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
fsCrypt.Write(salt, 0, salt.Length); //Write our salt to the file
fsCrypt.Write(IV, 0, IV.Length); //Write our IV to the file
fsIn.CopyTo(cs); //Encrypt and Write
}
}
}
}
The salt is used for two purposes:
to prevent rainbow table attacks (and it does if applied correctly);
to prevent identical passwords to generate the same password hash.
To do this the salt needs to be 8 to 16 bytes (not characters) of random data, stored with the password hash. Using a static hash as you do defeats both purposes of the hash.
If you need strings, use base 64 to encode the salt and password hash. If you want you can add static data (sometimes called "pepper") to the salt before calling the password hash function. This may add some security if the program data cannot be easily read by an attacker.
You should never directly mix the salt and the password yourself; the Rfc2898DeriveBytes (which is an implementation of PBKDF2) already mixes the two. You should also never store the password, nor should you have to append any data to it. PBKDF2 can handle any size of input, so it doesn't add any functionality.
Now the IV can be taken from the PBKDF2 function (using GetBytes). There is however a problem, it's likely that this will double the initial amount of iterations of PBKDF2 function, which costs CPU time and reduces the advantage over an attacker. It's probably better to just generate a random IV and prefix it to the ciphertext.
So in the end you should store salt | IV | ciphertext, then use salt | pepper as salt and calculate your key, then encrypt/decrypt using the calculated key and IV.
As far as I know,
IV/Salt does not need to be private. It can be stored in plain-text on the hard drive. In fact, salt must be in plain-text, otherwise you cannot generate the same output with it.
It is not a good idea to use your key information for generating the IV as it may leak your key information.
There is no way you can prevent attacks like rainbow. But with salt, rainbow attack becomes expensive as the talbes only work with this salt value.
There is a standard of key derivation fucntion that may useful to you (http://en.wikipedia.org/wiki/PBKDF2).

pbkdf2 computation not consistent between C# and JavaScript

Hi my question is I've Encrypted a password with crypto.pbkdf2 on windows azure server side Javascript I'm pretty sure that there is a public library which you can look up. The problem is I'm trying to encrypt the same password in C# on my system because I want the credentials to be universal but despite using Rfc2898DeriveBytes and the salt generated the first time I'm not able to get back to the same hashed password.
Thank you for your help :)
function hash(text, salt, callback) {
crypto.pbkdf2(text, salt, iterations, bytes, function(err, derivedKey){
if (err) { callback(err); }
else {
var h = new Buffer(derivedKey).toString('base64');
callback(null, h);
}
});
}
And the C# code:
byte[] salt = Convert.FromBase64String(user.salt);
using (var deriveBytes = new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt, 1000))
{
byte[] newKey = deriveBytes.GetBytes(32);
// user is the user object drawn from the database in existence
if (Convert.ToBase64String(newKey).Equals(user.password))
{
FormsAuthentication.RedirectFromLoginPage(Request.Form["username"], false);
}
}
hex generated by C# = 3lRSQF5ImYlQg20CGFy2iGUpWfdP5TD0eq2cTHhLono=
hex generated by JS = w4PDh8K6YMKGwr3DgcObRsOsFFUgDMOJw5PCnkdAwrTCgcOOV8OCKMKFdcKRwrLCqMK2VA==
Salt generated by JS and used at both = /Ij0hgDsvAC1DevM7xkdGUVlozdCxXVd0lgfK2xEh2A=
All the above info is in base64 format
Another thing that might be useful
item.salt = new Buffer(crypto.randomBytes(bytes)).toString('base64'); crypto.pbkdf2(text, salt, iterations, bytes, function(err, derivedKey){
which means the JS function accepts a string
I want the credentials to be universal but despite using Rfc2898DeriveBytes and the salt generated the first time I'm not able to get back to the same hashed password.
The obvious stuff is hash algorithm, salt, and iteration count. Can you confirm (for both languages):
the hash algorithm
the salt
the iteration count
The non-obvious is the encoding of the password and possibly salt. I included the salt because its often stored as a string.
To keep it portable among languages, you should use UTF-8. That's because you could encounter a default encoding, a UTF16-BE, UTF16-LE or any number of other encoding.
In C#, the setup would be:
byte[] utf8_salt = Encoding.UTF8.GetBytes(salt);
byte[] utf8_pass = Encoding.UTF8.GetBytes(password);
You would then pass utf8_salt and utf8_pass to the PBKDF2 function.
I don't know how to do the same in Javascript.
Alright kids daddy has figured out the answer.. took long enough..
Buffer(encodedPassword, 'binary').toString('base64')
on Javascript side will suffice now the tutorial I looked at was clearly not accurate.. the 'binary' was missing.
Thank you all for the help :)
and happy new year

AesCryptoServiceProvider behaviour when trying to decrypt with the wrong key

I'm using AesCryptoServiceProvider and CryptoStream to encrypt some data and it seems to be working OK when I use the same key for decryption. However, If I try to decrypt it with the wrong key, I don't get an exception, just junk data. I can't find anything in the .Net documentation which says what is supposed to happen but according to this:
http://books.google.co.uk/books?id=_Y0rWd-Q2xkC&pg=PA631
and this:
Why does a bad password cause "Padding is invalid and cannot be removed"?
I should be getting a CryptographicException. Am I doing it wrong? my function is this:
public static byte[] Encrypt(byte[] data, string password, string salt, bool decrypt)
{
SymmetricAlgorithm aes = new AesCryptoServiceProvider();
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);
aes.Key = rfc2898.GetBytes(256 / 8);
ICryptoTransform enc;
if (decrypt) {
enc = aes.CreateDecryptor();
} else {
enc = aes.CreateEncryptor();
}
using (enc) {
using (MemoryStream ms = new MemoryStream()) {
using (CryptoStream cs = new CryptoStream(ms, enc, CryptoStreamMode.Write)) {
cs.Write(data, 0, data.Length);
return ms.ToArray();
}
}
}
Relying on padding errors is not a good way to determine if a key is correct or not. You should really consider using Authenticated Encryption for this purpose.
I have a public domain snip-it that works in C# for this Modern Examples of Symmetric Authenticated Encryption of a string. that I try to keep up to date and reviewed.
P.S. Also it's not clear if your salt is per domain, per user, or per ciphertext from your sample, but if it's not per ciphertext in your code the IV will be predictable and the same for many ciphertexts which is not good for AES-CBC. Implementing crypto is hard.
I've also worked on a highlevel encryption library , a C# port of Google Keyczar. But that may not work very well for you, it only supports randomly generate keys and keysets, and those keysets can then be password encrypted, but only the keysets. High level encryption frameworks are the best practice for encyption.
If you have no padding set on decryption then the decryption method won't be able to recognise junk. Set padding to PKCS#7 for both encryption and encryption and the decryption method will probably be able to recognise junk.
For full assurance, you will need authentication, as jbtule says. To include authentication and encryption in the one data pass use GCM mode. For separate authentication use HMAC.
I'm going to have to put my hands up here and say False Alarm.
I have no idea what was happening on Friday but now I'm getting what I would expect - most of the time the CryptographicException happens as expected. I've no idea whether I was just hugely unlucky with my test data or whether there was a bug in my test harness which I inadvertently fixed, but it's all behaving as expected now.
Incidentally I did a quick empirical test which validates rossum's 1/256 number but that's acceptable for my purposes. In the general case I completely accept the other comments here about HMACs etc, but what I'm doing is for a test tool

C#, how to check if value is encrypted using MD5 passphrase?

I have the following code to encrypt a value (listed below). Now I would like to write a bool isEncrypted() method. Is there a fool proof and reliable way to check if a value has been encrypted using this function. I have the decrypt routine and can control the pass phrase, but not sure if that will help.
The reason is - when the app first runs, values in a configuration file are not encrypted, in this case the app should auto encrypt these values. On 2nd run I don't want to encrypt again because obviously that would cause havoc. Lastly I don't want to have to add an isEncrypted attribute to the config value. I want it to work and look as dynamic as possible.
So far I am leaning towards using the len (128) as deciding factor, but there is always a remote chance of the unencrypted value also being this length.
Thanks in advance.
public static string encrypt(string text)
{
// Locals
var passphrase = "5ab394ed-3920-4932-8d70-9c1b08f4ba4e";
byte[] results;
var utf8 = new 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
var hashProvider = new MD5CryptoServiceProvider();
var tdesKey = hashProvider.ComputeHash(utf8.GetBytes(passphrase));
// Step 2. Create a new TripleDESCryptoServiceProvider object
// Step 3. Setup the encoder
var tdesAlgorithm = new TripleDESCryptoServiceProvider
{
Key = tdesKey,
Mode = CipherMode.ECB,
Padding = PaddingMode.PKCS7
};
// Step 4. Convert the input string to a byte[]
var dataToEncrypt = utf8.GetBytes(text);
// Step 5. Attempt to encrypt the string
try
{
var 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);
}
What you could do in the isEncrypted method is to try to decrypt the message.
Since you are using PKCS7 padding most likely an unencrypted message will fail to decrypt since the padding does not conform to the set padding mode.
The decryption will throw an exception and you'll have to catch this and return false in this case.
There is a remote chance that the decryption will go through (when the message is not encrypted) if the data conforms to the padding mode. This is however most unlikely.
What I would do in this case would be to add some kind of flag in the encrypted data or append some data to encrypted message since I can then remove it in the decryption. This would be the most foolproof way.
First, as a serious issue, it's an exceedingly poor idea to use cryptographic primitives on your own. You've chosen to use the Electronic Codebook mode of encryption, which has the property that identical plaintext blocks produce identical cyphertext blocks. Check out the example at Wikipedia.
That said, a simple solution is to prepend a token such as 'ENC:' to the encrypted password. If you need to worry about malicious tampering with the config file, you should proceed to use a message authentication code, such as HMAC.
As your function returns a string there's no reason you can't add a plaintext code to the beginning of the encrypted data that the IsEncrypted function can look for, say "MD5ENC"+ [ciphertext].
The disadvantage of this is that it will let anyone who has the raw string know what algorithm was used for encryption. But as we keep getting reminded security through obscurity is no security at all. Anyone should be allowed to know how something was encrypted and have no easy way of breaking that encryption.
Note my use of the word should.
Anyhow, to return to my original suggestion. The advantage of this is that the longer your introductory code on the string the more vanishingly tiny the chances of it being generated by accident in another unrelated Base64 encrypted string becomes.
Should the ciphertext need decrypting just snip off your standard length encryption ident code and away you go...

Categories