I have a C# application that uses the following methods for encrypt and decrypt passwords in a database:
public static string Encrypt(string input, string key)
{
TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
tripleDES.Mode = CipherMode.ECB;
tripleDES.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tripleDES.CreateEncryptor();
byte[] inputArray = UTF8Encoding.UTF8.GetBytes(input);
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);
}
So if I encrypt the password testing with the key 0123456789012345 then the result will be +dc6bsOFg00=.
Now I have to read these passwords from a NodeJS application (using CryptoJS), but I'm not sure how to do it, since in C# the encryption is byte oriented (note that in the code both input and key are converted to byte[]) while in CryptoJS it's more string oriented.
I tried using this JavaScript function with no success:
var CryptoJS = require("crypto-js");
function decrypt(input, key) {
var inputArray = new Buffer(input, 'base64');
var inputString = inputArray.toString();
var resultArray = CryptoJS.TripleDES.decrypt(inputString, key, {'mode': CryptoJS.mode.ECB, 'pad': CryptoJS.pad.Pkcs7});
return resultArray.toString();
}
console.log(decrypt("+dc6bsOFg00=", "0123456789012345"));
Update: I know that encrypting passwords is a bad idea, and that Triple DES is not the best algorithm, but the C# application can't be modified (at least not for now), so I can't change how the password are encrypted, I must read them as they currently are.
(Posted on behalf of the OP).
Thanks for the suggestion, but using inputArray.toString('binary') did not work.
What I finally did solve my problem is to use Edge.js: since I have the code of the C# methods used for encrypt and decrypt, I can use Edge.js to execute these methods from the Node application.
Related
We are in the process of gutting a lot of shared functionality in our system and porting it to PCL libraries. I am having an issue using PCLCrypto. I am taking some existing data in our database, and trying to decrypt it with the same algorithm. I get the value back, but there are 16 extra bytes at the end that are just garbage.
See Code below:
Old Algorithm using System.Security.Cryptography
public static string SymmetricEncrypt(this string plaintext, string key, SymmetricAlgorithm algorithm)
{
byte[] keyBuffer = Convert.FromBase64String(key.Hash(HashAlgorithm.MD5));
byte[] plainTextBuffer = Encoding.UTF8.GetBytes(plaintext);
var symmetricAlgorithm = new AesCryptoServiceProvider();
symmetricAlgorithm.Key = keyBuffer;
symmetricAlgorithm.Mode = CipherMode.ECB;
var encryptor = symmetricAlgorithm.CreateEncryptor();
byte[] cipherBuffer = encryptor.TransformFinalBlock(plainTextBuffer, 0, plainTextBuffer.Length);
symmetricAlgorithm.Clear();
return Convert.ToBase64String(cipherBuffer);
}
public static string SymmetricDecrypt(this string cipherText, string key, SymmetricAlgorithm algorithm)
{
byte[] keyBuffer = Convert.FromBase64String(key.Hash(HashAlgorithm.MD5));
byte[] cipherTextBuffer = Convert.FromBase64String(cipherText);
var symmetricAlgorithm = new AesCryptoServiceProvider();
symmetricAlgorithm.Key = keyBuffer;
symmetricAlgorithm.Mode = CipherMode.ECB;
var decryptor = symmetricAlgorithm.CreateDecryptor();
byte[] plainTextBuffer = decryptor.TransformFinalBlock(cipherTextBuffer, 0, cipherTextBuffer.Length);
symmetricAlgorithm.Clear();
return Encoding.Default.GetString(plainTextBuffer);
}
Decryption using PCLCrypto
public static string SymmetricDecrypt(this string cipherText, string key, SymmetricAlgorithm algorithm) {
byte[] keyBuffer = Convert.FromBase64String(key.Hash(HashAlgorithm.MD5));
byte[] cipherTextBuffer = Convert.FromBase64String(cipherText);
ISymmetricKeyAlgorithmProvider symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(PCLCrypto.SymmetricAlgorithm.AesEcb);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyBuffer);
var decryptor = WinRTCrypto.CryptographicEngine.CreateDecryptor(symmetricKey);
byte[] plainTextBuffer = decryptor.TransformFinalBlock(cipherTextBuffer, 0, cipherTextBuffer.Length);
return UTF8Encoding.UTF8.GetString(plainTextBuffer, 0, plainTextBuffer.Length);
}
Using the old version: plainTextBuffer is 16 bytes, new version it is 32 bytes.
Help!
This sounds like a padding issue.
Looking at the source for the base class SymmetricAlgorithm in .NET, which is the base of the AesCryptoServiceProvider, the default padding is PaddingMode.PKCS7. You don't appear to have defined a padding mode, so I would assume the default still applies.
Whilst I haven't used the PCLCrypto library before, having a quick look at github there are a couple of AesEcb algorithms: AesEcb and AesEcbPkcs7. The absence of a padding mode from the name of AesEcb would imply to me that it has no padding (and thus hasn't removed any padding), which would be the equivalent of PaddingMode.None in the .NET libraries.
Try using the PCLCrypto.SymmetricAlgorithm.AesEcbPkcs7 algorithm in PCLCrypto and see if this removes the padding that you are seeing at the end of the output.
Update
I've just tested this, and it appears to work correctly and remove the padding you would be seeing:
public static string SymmetricDecrypt(this string cipherText, string key, SymmetricAlgorithm algorithm) {
byte[] keyBuffer = Convert.FromBase64String(key.Hash(HashAlgorithm.MD5));
byte[] cipherTextBuffer = Convert.FromBase64String(cipherText);
ISymmetricKeyAlgorithmProvider symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(PCLCrypto.SymmetricAlgorithm.AesEcbPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyBuffer);
var decryptor = WinRTCrypto.CryptographicEngine.CreateDecryptor(symmetricKey);
byte[] plainTextBuffer = decryptor.TransformFinalBlock(cipherTextBuffer, 0, cipherTextBuffer.Length);
return UTF8Encoding.UTF8.GetString(plainTextBuffer, 0, plainTextBuffer.Length);
}
The only change was changing the algorithm from PCLCrypto.SymmetricAlgorithm.AesEcb to PCLCrypto.SymmetricAlgorithm.AesEcbPkcs7
I am busy creating a Javascript application which integrates with our client's existing C# services.
One of the requirements is to send AES encrypted data, which then is decrypted and used on the server.
However, I cannot send "valid" data, the server always responds with "Padding is invalid and cannot be removed."
Here are their C# Encrypt and Decrypt implementations (this cannot be changed, as they have various subsystems dependent on this:
public static string Encrypt(string input, string password)
{
byte[] utfData = Encoding.UTF8.GetBytes(input);
byte[] saltBytes = Encoding.UTF8.GetBytes(password);
string encryptedString = string.Empty;
using (var aes = new AesManaged())
{
var rfc = new Rfc2898DeriveBytes(password, saltBytes);
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize/8);
aes.IV = rfc.GetBytes(aes.BlockSize/8);
using (ICryptoTransform encryptTransform = aes.CreateEncryptor())
{
using (var encryptedStream = new MemoryStream())
{
using (var encryptor =
new CryptoStream(encryptedStream, encryptTransform, CryptoStreamMode.Write))
{
encryptor.Write(utfData, 0, utfData.Length);
encryptor.Flush();
encryptor.Close();
byte[] encryptBytes = encryptedStream.ToArray();
encryptedString = Convert.ToBase64String(encryptBytes);
}
}
}
}
return encryptedString;
}
public static string Decrypt(string input, string password)
{
byte[] encryptedBytes = Convert.FromBase64String(input);
byte[] saltBytes = Encoding.UTF8.GetBytes(password);
string decryptedString = string.Empty;
using (var aes = new AesManaged())
{
var rfc = new Rfc2898DeriveBytes(password, saltBytes);
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize/8);
aes.IV = rfc.GetBytes(aes.BlockSize/8);
using (ICryptoTransform decryptTransform = aes.CreateDecryptor())
{
using (var decryptedStream = new MemoryStream())
{
var decryptor =
new CryptoStream(decryptedStream, decryptTransform, CryptoStreamMode.Write);
decryptor.Write(encryptedBytes, 0, encryptedBytes.Length);
decryptor.Flush();
decryptor.Close();
byte[] decryptBytes = decryptedStream.ToArray();
decryptedString =
Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
}
}
}
return decryptedString;
}
I am using CryptoJS 3.1.2. eg
var encrypted = CryptoJS.AES.encrypt(input, password).toString();
how do I essentially write an equivalent to their "Encrypt()" using CryptoJS
CryptoJS documentation is severely lacking in depth, so it is hard to know what to expect without trying. It is pretty clear though that using the password as salt is not a secure nor standard way to handle salt. So you will have to call the PBKDF2 function yourself, create a key and IV yourself. You also need to create the PBKDF2 in CryptoJS with SHA-1 instead of SHA-256. SHA-256 seems to be the - again undocumented - default in CryptoJS.
The only way to do this is to step through the code, and compare each (binary) value for both the PBKDF2 and AES functions. Please convert to hexadecimals to make a good comparison.
I need to store email passwords which will be used with system.net.mail. These need to be retrieved and sent as plain text but I don't want to store them as plain text. This isn't really about security as its for an intranet and I just don't want the results being displayed in plain text in the CMS.
I've read plenty of articles saying that storing password should be done using SHA1. From what I've read hashing is no good because the plain text cant be retrieved.
I am currently trying this methods:
public static string EncodePasswordToBase64(string password)
{
try
{
byte[] encData_byte = new byte[password.Length];
encData_byte = System.Text.Encoding.UTF8.GetBytes(password);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
}
catch (Exception ex)
{
throw new Exception("Error in base64Encode" + ex.Message);
}
}
and
public static string DecodeFrom64(string encodedData)
{
System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
System.Text.Decoder utf8Decode = encoder.GetDecoder();
byte[] todecode_byte = Convert.FromBase64String(encodedData);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
string result = new String(decoded_char);
return result;
}
but I cant seem to find the correct data type in my database to store the value. Its currently set to nvarchar(MAX).
The cell contents display like this (with spaces between each value):
Q X B j L W V w M X B =
Strangely when I click and enter the cell to copy the data all I get is:
Q
What data type should I use for this column?
You can use something like this..
//For encrypting string.
public static string Encrypt(string toEncrypt, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
string key = "UglyRandomKeyLike-lkj54923c478";
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);
}
// To decrypt string
public static string Decrypt(string cipherString, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = Convert.FromBase64String(cipherString);
string key = "UglyRandomKeyLike-lkj54923c478";
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.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
tdes.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
}
The above mentioned method will encrypt your password and you can store it in varchar field in your database. The second method takes encrypted password and return it in normal string
I hope this is what you are looking for.. I am not able to comment in your question.
Well, you're correct that hashing is not the correct way to go. What you actually want to use is Symmetric Encryption which will allow you to encrypt the data in the DB but then to decrypt it back in your main program.
AES is the recommended standard. Here is an example of how it used in C#.
I'd read a little bit more about how to correctly choose an IV to avoid common pitfalls.
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).
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);
}
}
}