Save Data generated by PCLCRYPTO - c#

I'm using PCLCRYPTO. I need to save the information in a text file in Windows to be retrieved on Android and Windows Phone.
The Encrypt function returns in Bytes and I would like to save the information in a text file to be retrieved on the other devices.
Would anyone know how to turn the bytes into text and what to write to the file to be recovered from the other devices?
The functions are:
public static byte[] EncryptAes(string data, string password, byte[] salt)
{
byte[] key = CreateDerivedKey(password, salt);
ISymmetricKeyAlgorithmProvider aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
ICryptographicKey symetricKey = aes.CreateSymmetricKey(key);
var bytes = WinRTCrypto.CryptographicEngine.Encrypt(symetricKey, Encoding.UTF8.GetBytes(data));
return bytes;
}
public static string DecryptAes(byte[] data, string password, byte[] salt)
{
byte[] key = CreateDerivedKey(password, salt);
ISymmetricKeyAlgorithmProvider aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
ICryptographicKey symetricKey = aes.CreateSymmetricKey(key);
var bytes = WinRTCrypto.CryptographicEngine.Decrypt(symetricKey, data);
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}

The same way you get a string in the decrypt method.
Encoding.UTF8.GetString(bytes, 0, bytes.Length)
Just save the string you get from the bytes in a text file.

Related

When merging two arrays, the first array gets shorter by 1

I have a password which I hash with SHA256. Then I have a salt which looks like that:
AAAAAAAAAAAAAAAAAAAAAA==
At the end of the process both of them are byte-arrays which I then merge into a new byte-array.
My PROBLEM is that while merging the password with the salt, my hashed password gets shorter by one character at the end.
Expected output:
uIxnpgdBQpSPJrqwYucIOeyOyqyCv7HbBfd74ovoxjI=AAAAAAAAAAAAAAAAAAAAAAAAA==
Output:
uIxnpgdBQpSPJrqwYucIOeyOyqyCv7HbBfd74ovoxjIAAAAAAAAAAAAAAAAAAAAAAAAA==
As you can see there is a = missing after the l.
My Method:
public static byte[] HashPassword(byte[] passwordToHash)
{
byte[] hInput;
byte[] hSalt = GetSalt();
using(SHA256 sh = SHA256.Create())
{
hInput = sh.ComputeHash(passwordToHash);
}
byte[] SaltedPw = new byte[(hInput.Length+ 1 ) + (hSalt.Length + 3)];
Array.Copy(hInput,0, SaltedPw, 0,hInput.Length);
Array.Copy(hSalt, 0, SaltedPw, hInput.Length, hSalt.Length);
return SaltedPw;
}
public static byte[] GetSalt()
{
byte[] salt = new byte[16];
return salt;
}
How can I prevent the shortening of my password?
You are doing it wrong. You must not add the salt to the hashed password. You must add the salt to the plain password and then hash. The point is to make the hash of a current or short password unrecognizable.
The base 64 encoding is only applied to the final result to allow storing the password hash as string. Therefore, you will never have to merge base 64 strings. Base 64 strings are padded with = at the end to get a length which is a multiple of 4. Therefore you will never see a = in the middle.
public static string GetHashedPassword(string plainPassword, byte[] salt)
{
byte[] passwordBytes = GetBytes(plainPassword);
// Merge the password bytes and the salt bytes
var mergedBytes = new byte[passwordBytes.Length + salt.Length];
Array.Copy(passwordBytes, mergedBytes, passwordBytes.Length);
Array.Copy(salt, 0, mergedBytes, passwordBytes.Length, salt.Length);
// Now hash password + salt
byte[] hash;
using (var sha = SHA256.Create()) {
hash = sha.ComputeHash(mergedBytes);
}
return Base64Encode(hash);
}
You will also need this:
public static string Base64Encode(byte[] bytes)
{
return System.Convert.ToBase64String(bytes);
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
Create random salt bytes for each password and store the salt as a separate piece of information together with the hashed password. Like this, every password gets a different salt. This makes Pre-computed dictionary attack/Rainbow table attack infeasible. The salt does not need to be encrypted. You probably will want to store it as base 64 string as well. To get the salt bytes again you will need Convert.FromBase64String().

My encrypt and decrypt function is not working when passing text with numeric data

when i am passing normal alphabet to my encrypt and decrypt function then it is working as expected but when i am passing alphanumeric text to encrypt and decrypt function then it is not working.
say when i pass encrypt("test1") or decrypt("test1") then it is not working. specially decrypt not working with alphanumeric case.
i want to restructure my encrypt and decrypt function as a result whatever value i pass the function can work. suppose i may pass alpha numeric data with special character. so plerase see the code and come with rectified version.
a small wrapper around encrypt/decrypt
private string encrypt(string message)
{
EncryptClass.EncryptClass ec = new EncryptClass.EncryptClass();
string encryStr = ec.custEncrypt(message);
return encryStr;
}
private string decrypt(string message)
{
EncryptClass.EncryptClass ec = new EncryptClass.EncryptClass();
string decryptStr = message;
return ec.custDecrypt(decryptStr);
}
full code for encrypt ans decrypt
public class EncryptClass
{
DESCryptoServiceProvider rj;
byte[] key = new byte[] { 11, 9, 3, 4, 1, 8, 12, 7 };
byte[] IV = new byte[] { 1, 8, 7, 16, 1, 9, 0, 3 };
public EncryptClass()
{
//
// TODO: Add constructor logic here
//
rj = new DESCryptoServiceProvider();
}
// for encryption
public string custEncrypt(string message)
{
//create a memory stream
MemoryStream ciphertextmem = new MemoryStream();
//create a crypto stream in write mode
CryptoStream crystm = new CryptoStream(ciphertextmem, rj.CreateEncryptor(key, IV), CryptoStreamMode.Write);
//Encode the passed plain text string into Unicode byte stream
Byte[] plaintextbyte = new UnicodeEncoding().GetBytes(message);
//Write the plaintext byte stream to CryptoStream
crystm.Write(plaintextbyte, 0, plaintextbyte.Length);
//don't forget to close the stream
crystm.Close();
//Extract the ciphertext byte stream and close the MemoryStream
Byte[] ciphertextbyte = ciphertextmem.ToArray();
ciphertextmem.Close();
//Encode the ciphertext byte into Unicode string
string ciphertext = new UnicodeEncoding().GetString(ciphertextbyte);
return ciphertext;
//return "encry " + message;
}
// for decryption
public string custDecrypt(string message)
{
//Create a memory stream from which CryptoStream will read the cipher text
MemoryStream ciphertextmem = new MemoryStream(new UnicodeEncoding().GetBytes(message));
//Create a CryptoStream in Read Mode; initialise with the Rijndael's Decryptor ICryptoTransform
CryptoStream crystm = new CryptoStream(ciphertextmem, rj.CreateDecryptor(key, IV), CryptoStreamMode.Read);
//Create a temporary memory stream to which we will copy the
//plaintext byte array from CryptoStream
MemoryStream plaintextmem = new MemoryStream();
do
{
//Create a byte array into which we will read the plaintext
//from CryptoStream
Byte[] buf = new Byte[100];
//read the plaintext from CryptoStream
int actualbytesread = crystm.Read(buf, 0, 100);
//if we have reached the end of stream quit the loop
if (0 == actualbytesread)
break;
//copy the plaintext byte array to MemoryStream
plaintextmem.Write(buf, 0, actualbytesread);
} while (true);
//don't forget to close the streams
crystm.Close();
ciphertextmem.Close();
//Extract the plaintext byte stream and close the MemoryStream
Byte[] plaintextbyte = plaintextmem.ToArray();
plaintextmem.Close();
//Encode the plaintext byte into Unicode string
string plaintext = new UnicodeEncoding().GetString(plaintextbyte);
return plaintext;
//return "decry "+ message;
}
}
please see my code and rectified area as a result it should work if i pass only text or if i pass text with numeric data or alphanumeric with special character.
looking for help.
There are much simpler ways to do that, and there are several serious flaws in your implementation:
Using the same IV and a static key is not much protection at all
The result cannot be expressed as a text string, which may be the core problem making the round trip
You can use a CryptoStream but unless you are outputting to a stream, it just over complicates matters.
I tried to just mend your code, but in the end it was easier to just start fresh:
public class EncryptClass
{
const int hashCount = 21569;
public static string EncryptString(string message, string pass)
{
using (RijndaelManaged rij = new RijndaelManaged())
{
rij.GenerateIV();
rij.Key = HashPassword(pass);
using (ICryptoTransform cryptor = rij.CreateEncryptor())
{
var data = Encoding.Unicode.GetBytes(message);
var buff = cryptor.TransformFinalBlock(data, 0, data.Length);
// concat to the IV for the other side
// crypto data is binary - use Base64 for text encoding
return Convert.ToBase64String(rij.IV.Concat(buff).ToArray());
}
}
}
private static byte[] HashPassword(string thePW)
{
// originally from RNGCryptoServiceProvider.GetRandomBytes
byte[] salt = new byte[] { 96, 248, 204, 72, 177, 214, 251, 82, 174,
90, 82, 90, 111, 76, 146, 172 };
using (var hasher = new Rfc2898DeriveBytes(thePW, salt, hashCount))
{
return hasher.GetBytes(32);
}
}
This uses RijndaelManaged as the crypto provider. As you can see, it is pretty simple. Some key points:
The methods are static
A new IV is generated each time.
The resulting crypto output is concatenated to the IV, so it will be available to the Decryptor. If you were encrypting to a file stream, write them IV bytes to the naked FileStream
This version hashes the password using PBKDF, some initially random salt and a large number of iterations
Since it is just a string, TransformFinalBlock is all you need to encrypt it
The result is encoded as Base64
I'm not sure why you used Unicode encoding, so I left that in. Decrypting is just as easy:
public static string DecryptString(string crypted, string pass)
{
byte[] data = Convert.FromBase64String(crypted);
using (RijndaelManaged rij = new RijndaelManaged())
{
int size = (int)(rij.BlockSize / 8);
byte[] iv = new byte[size];
// copy the iv to the array
Array.Copy(data, 0, iv, 0, size);
rij.IV = iv;
rij.Key = HashPassword(pass);
using (ICryptoTransform cryptor = rij.CreateDecryptor())
{
var buff = cryptor.TransformFinalBlock(data, size, data.Length - size);
return Encoding.Unicode.GetString(buff);
}
}
}
After converting the Base64 string back to bytes, the IV is fetched from the byte array, and TransformFinalBlock is given the offsets into the array to account for the IV. Usage and testing:
string msg = "This is some text 123 1 87 45";
string crypto = EncryptClass.EncryptString(msg, "I Like Pi");
Console.WriteLine(crypto);
string retVal = EncryptClass.DecryptString(crypto, "I Like Pi");
Console.WriteLine(retVal);
Results:
mIfpIkTVC7mI5R1hlIIpVs63N/j4LN+p2pGPuo90eEPWvW+sqSiBIDjto1+E1p0umdI1hDnkxa2droAbuAFwPzuNK3gABrFjsNpi6FXwGOw=
This is some text 123 1 87 45
The top line is the Base64 form of the encrypted data; the second is the decryption output.

myBB Passwords c# client

I'm working on a loader / client where my forum users will use their myBB information to login to my application. I know it's not good to have the database connection in the application. But I am also going to store their hwid on the database so I would need to connect to it anyway.
However, they store the passwords like this:
$hashedpsw = md5(md5($salt).md5($plainpassword));
And my attempt to recreate that passwords looks like this:
string salt = "D4UFUd6U"; // get salt from db
string password = "test!";// get password from user
MD5 md5 = new MD5CryptoServiceProvider();
// Create md5 hash of salt
byte[] saltBytes = Encoding.Default.GetBytes(salt);
byte[] saltHashBytes = md5.ComputeHash(salt);
string saltHash = System.BitConverter.ToString(saltHashBytes);
// Create your md5(password + md5(salt)) hash
byte[] passwordBytes = Encoding.Default.GetBytes(password + saltHash);
byte[] passwordHashBytes = md5.ComputeHash(salt);
string passwordHash = BitConverter.ToString(passwordHashBytes);
But I get the following error:
cannot convert from 'string' to 'System.IO.Stream'
ComputeHash wants an IO.Stream or a Byte[] as input, and as the error specifies, can't convert from your strings to IO.Stream implicitly.
The following is an example of how you can convert a string to a stream (stolen from this answer):
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
This would alter your code to the following:
string salt = "D4UFUd6U"; // get salt from db
string password = "test!";// get password from user
MD5 md5 = new MD5CryptoServiceProvider();
// Create md5 hash of salt
byte[] saltBytes = Encoding.Default.GetBytes(salt);
byte[] saltHashBytes;
using( Stream saltStream = GenerateStreamFromString(salt))
{
salteHashBytes = md5.ComputeHash(saltStream);
}
string saltHash = System.BitConverter.ToString(saltHashBytes);
// Create your md5(password + md5(salt)) hash
byte[] passwordBytes = Encoding.Default.GetBytes(password + saltHash);
byte[] passwordHashBytes;
using( Stream saltStream = GenerateStreamFromString(salt))
{
passwordHashBytes = md5.ComputeHash(saltStream);
}
string passwordHash = BitConverter.ToString(passwordHashBytes);
You use the MD5CryptoServiceProvider class to encrypt using md5 hash algorithm. First add the following namespaces:
using System.Text;
using System.Security.Cryptography;
Second, try a function like this.
public static string Encrypt(string content)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.ASCII.GetBytes(content);
bytes = md5.ComputeHash(data);
string result = Encoding.ASCII.GetString(bytes);
return result;
}

AES decrypt file data and write to disk

I am trying to decrypt file data and write to disk. It's creating the file but it is corrupted. Could you please let me know if there are any suggestions. I am using AES 256 algorithm.
column_data = string_data //base64 encoded string
byte[] data_bytes = Convert.FromBase64String(column_data);
string decodedString = Encoding.UTF8.GetString(data_bytes);
bytes[] decrypted = DecryptAESText(decodedString, secret, iv);
File.WriteAllBytes(#".\file.gif", decrypted );
// DecryptAESText returns the decrypted text, receives text in Base64
public static byte[] DecryptAESText(string cipheredText, byte[] Key, byte[] IV)
{
IBufferedCipher cipher = InitAESCipher(false, Key, IV);
string plainText = string.Empty;
byte[] plainBytes = null;
try
{
byte[] cipheredBytes = Convert.FromBase64String(cipheredText);
plainBytes = new byte[cipher.GetOutputSize(cipheredBytes.Length)];
plainBytes = cipher.DoFinal(cipheredBytes);
}
catch (Exception e)
{
Console.WriteLine(e.ToString() + "Issue in DecryptAESText column Name:");
}
return plainBytes;
}

How to convert and send string in Http Authorization Header?

I am developing a REST API. Client puts it's user name and password in authorization header of HttpClient after encrypting it with public key of Server. Username and password will always consist of alphabets and number which means it can be represented in ASCII.
I am using this code for encryption.
string encrypted = Encrypt (someText, crypto);
public static string Encrypt (string plainText, RSACryptoServiceProvider crypto)
{
var plainData = GetBytes (plainText);
var encryptedData = crypto.Encrypt (plainData, true);
return GetString (encryptedData);
}
public static byte[] GetBytes (string str)
{
var bytes = new byte[str.Length * sizeof (char)];
Buffer.BlockCopy (str.ToCharArray (), 0, bytes, 0, bytes.Length);
return bytes;
}
public static string GetString (byte[] bytes)
{
var chars = new char[bytes.Length / sizeof (char)];
Buffer.BlockCopy (bytes, 0, chars, 0, bytes.Length);
return new string (chars);
}
Problem is that I get this string after encryption
꠨屰欧㼡‫⭮鍴⬎㔾䐛え멩戻덒郝㬭ே䉚ꑰ䵇᷹᷶虣ⱒ̿ঊࠎ飳枹鬭쉦폩��ᤫ槺愐丄裘ډ졽肟䷋ٱ᮷튼쁡鮤붮飦ꃨ◡뉋⭠夏旻浨፛᠏რ
I can't send these Unicode characters in the authorization header. Is there any way to get the encrypted text in ASCII so that it can easily be sent through HttpClient?
You can base64 encode it. Base64 encoding produces a string that is suitable for sending over a transport that supports ASCII strings.
public static string Encrypt (string plainText, RSACryptoServiceProvider crypto)
{
var plainData = GetBytes (plainText);
var encryptedData = crypto.Encrypt (plainData, true);
return Convert.ToBase64String (encryptedData);
}
Btw, I would replace your custom GetBytes method for converting the string to an array of bytes with Encoding.GetBytes; which is the built in and preferred method of doing that. For instance:
var plainData = System.Text.Encoding.UTF8.GetBytes(plainText);

Categories

Resources