I'm having a bit of an issue encrypting / decrypting cross languages.
Here is my python code to encrypt some text:
class AESCipher:
def __init__( self, key, iv ):
self.key = base64.b64decode(key)
self.iv = base64.b64decode(iv)
def encrypt( self, raw ):
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
raw = pad(raw)
cipher = AES.new( self.key, AES.MODE_CBC, self.iv)
res = self.iv + cipher.encrypt( raw )
return base64.b64encode(res)
def decrypt( self, enc ):
enc = base64.b64decode(enc)
unpad = lambda s : s[:-ord(s[len(s)-1:])]
cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
return unpad(cipher.decrypt( enc[16:] ))
crypt = AESCipher("key", "iv")
print "{0}".format(crypt.encrypt("Hallow"))
And C# Decrypting:
public static string DecryptStringFromBase64(string base64String)
{
byte[] bytes = Decrypt(Convert.FromBase64String(base64String));
var utf8 = Encoding.UTF8.GetString(bytes);
return utf8;
}
public static byte[] Decrypt(byte[] bytes)
{
AesManaged algorithm = new AesManaged();
algorithm.IV = Convert.FromBase64String("IV");
algorithm.Key = Convert.FromBase64String("KEY");
byte[] ret = null;
using (var decryptor = algorithm.CreateDecryptor())
{
using (MemoryStream msDecrypted = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msDecrypted, decryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(bytes, 0, bytes.Length);
}
ret = msDecrypted.ToArray();
}
}
return ret;
}
However the decrypted value always comes out incorrectly like this:
I think this has something to do with the padding, can anybody suggest how to get around this?
The problem is not the padding. It's the IV that you haven't sliced off. The IV doesn't have to be secret, but it should be randomly generated for each encryption. Since you're already including the IV into the ciphertext in Python, you have to use it in C# during decryption (of course the decryption should be done on the actual ciphertext excluding the IV):
C#
public static string DecryptStringFromBase64(string base64String)
{
byte[] bytes = Decrypt(Convert.FromBase64String(base64String));
var utf8 = Encoding.UTF8.GetString(bytes);
return utf8;
}
public static byte[] Decrypt(byte[] bytes)
{
byte[] iv = new byte[16]; // change
Array.copy(bytes, iv, 16); // change
AesManaged algorithm = new AesManaged();
algorithm.IV = iv; // change
algorithm.Key = Convert.FromBase64String("KEY");
byte[] ret = null;
using (var decryptor = algorithm.CreateDecryptor())
{
using (MemoryStream msDecrypted = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msDecrypted, decryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(bytes, 16, bytes.Length - 16); // change
}
ret = msDecrypted.ToArray();
}
}
return ret;
}
The Python code is also not without its issues. You don't need to pass in the IV, because you're putting it into the ciphertext. So you can just create a new random IV. Additionally, the unpad function is not correct (or at least needlessly complicated).
class AESCipher:
def __init__( self, key):
self.key = base64.b64decode(key)
def encrypt( self, raw ):
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
raw = pad(raw)
iv = Random.new().read(BS)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
res = iv + cipher.encrypt( raw )
return base64.b64encode(res)
def decrypt( self, enc ):
enc = base64.b64decode(enc)
BS = 16
iv = enc[:BS]
unpad = lambda s : s[:-ord(s[-1])]
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc[BS:] ))
crypt = AESCipher("key", "iv")
print "{0}".format(crypt.encrypt("Hallow"))
Don't forget to authenticate your ciphertexts. Otherwise, a padding oracle attack might be launched against your system which enables an attack to decrypt every ciphertext with multiple online queries.
You can use an authenticated modes like GCM or EAX, or employ an encrypt-then-MAC scheme with a strong MAC like HMAC-SHA256.
Related
I'm trying to decrypt AES-128 CBC strings in C# but with no success (tried every decrypt method I found on internet for this type of encryption).
The only way I got a result was decrypting those strings in PHP using this code:
<?php
$crypto_data = hex2bin($crypto_data_hex);
$real_data = openssl_decrypt($crypto_data,
'AES-128-CBC',
'23d854ce7364b4f7',
OPENSSL_RAW_DATA,
'23d854ce7364b4f7');
?>
So, is there a way to run this PHP code in .NET (using a PHP.dll library or something similar) ? Or is there a real equivalent method for this operation in .NET C# ?
Thank you
The question seems to boil down to writing C# function that is equivalent to PHP function.
Try this code:
public class Program
{
public static byte[] HexToBytes(string hex)
{
int numberChars = hex.Length;
byte[] bytes = new byte[numberChars / 2];
for (int i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
{
string plaintext;
AesManaged aes = new AesManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
BlockSize = 128,
Key = key,
IV = iv
};
using (aes)
{
ICryptoTransform decryptor = aes.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd();
}
}
}
}
return plaintext;
}
public static void Main()
{
string crypto_data_hex = "00965fa56e761b11d37b887f98e6bcc2"; // paste $crypto_data_hex value here
string sKey = "23d854ce7364b4f7";
string sIv = "23d854ce7364b4f7";
byte[] encrypted = HexToBytes(crypto_data_hex);
byte[] key = Encoding.ASCII.GetBytes(sKey);
byte[] iv = Encoding.ASCII.GetBytes(sIv);
string decrypted = Decrypt(encrypted, key, iv);
Console.WriteLine(decrypted);
}
}
I encrypt password in postgres
and i want to decrypt it in c#, but two ways can not matching
.How can i do that?
private static byte[] TruncateHash(string key, int length)
{
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
// Hash the key.
byte[] keyBytes = System.Text.Encoding.Unicode.GetBytes(key);
byte[] hash = sha1.ComputeHash(keyBytes);
// Truncate or pad the hash.
Array.Resize(ref hash, length);
return hash;
}
public static string EncryptString(string plaintext, string Passphrase)
{
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
// Initialize the crypto provider.
tripleDes.Key = TruncateHash(Passphrase, tripleDes.KeySize / 8);
tripleDes.IV = TruncateHash("", tripleDes.BlockSize / 8);
// Convert the plaintext string to a byte array.
byte[] plaintextBytes = System.Text.Encoding.Unicode.GetBytes(plaintext);
// Create the stream.
System.IO.MemoryStream ms = new System.IO.MemoryStream();
// Create the encoder to write to the stream.
CryptoStream encStream = new CryptoStream(ms, tripleDes.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write);
// Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length);
encStream.FlushFinalBlock();
// Convert the encrypted stream to a printable string.
return Convert.ToBase64String(ms.ToArray());
}
public static string DecryptString(string encryptedtext, string Passphrase)
{
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
// Initialize the crypto provider.
tripleDes.Key = TruncateHash(Passphrase, tripleDes.KeySize / 8);
tripleDes.IV = TruncateHash("", tripleDes.BlockSize / 8);
// Convert the encrypted text string to a byte array.
byte[] encryptedBytes = Convert.FromBase64String(encryptedtext);
// Create the stream.
System.IO.MemoryStream ms = new System.IO.MemoryStream();
// Create the decoder to write to the stream.
CryptoStream decStream = new CryptoStream(ms, tripleDes.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write);
// Use the crypto stream to write the byte array to the stream.
decStream.Write(encryptedBytes, 0, encryptedBytes.Length);
decStream.FlushFinalBlock();
// Convert the plaintext stream to a string.
return System.Text.Encoding.Unicode.GetString(ms.ToArray());
}
I found a way to encrypt in postgres using pgcrypto.
And below is encrypt and decrypt in postgres.
SELECT encode(encrypt_iv('ABCDE121212','Key123', '','3des'), 'base64');
select decrypt_iv(decode('jEI4V5q6h5/p12NRJm666g==','base64'),'Key123','','3des')
What's wrong in my code, c# and postgres can't not matching.
I want to keep c# code and change postgres code to matching
Source Url
Encrypt function:
public static String AES_encrypt(String input, string key, string Iv, int keyLength)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = keyLength;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = mkey(key,keyLength);
aes.IV = mkey(Iv,128);
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
{
byte[] xXml = Encoding.UTF8.GetBytes(input);
cs.Write(xXml, 0, xXml.Length);
cs.FlushFinalBlock();
}
xBuff = ms.ToArray();
}
return Convert.ToBase64String(xBuff,Base64FormattingOptions.None);
}
Decrypt function:
public static String AES_decrypt(String Input, string key, string Iv, int keyLength)
{
try
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = keyLength;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = mkey(key,keyLength);
aes.IV = mkey(Iv,128);
var decrypt = aes.CreateDecryptor();
byte[] encryptedStr = Convert.FromBase64String(Input);
string Plain_Text;
using (var ms = new MemoryStream(encryptedStr))
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
Plain_Text = reader.ReadToEnd();
}
}
}
return Plain_Text;
}
catch (Exception ex)
{
return null;
}
}
Helper function:
private static byte[] mkey(string skey, int keyLength)
{
int length = keyLength / 8;
byte[] key = Encoding.UTF8.GetBytes(skey);
byte[] k = GenerateEmptyArray(length);
for (int i = 0; i < key.Length; i++)
{
//k[i % 16] = (byte)(k[i % 16] ^ key[i]);
k[i] = key[i];
if(i == length-1)
break;
}
return k;
}
Variables:
input = "Hello World"
key = "NBJ42RKQ2vQoYFZO"
Iv = "j1C83921vHExVhVp"
keyLength = 128
Info about variables:
input - string that is not encrypted or encrypted. If it's encrypted it will be in Base64 format
key - Any Unicode character that will match the AES key size(in this example it's 128). I have written a function that will extract the specific length of characters and add them to a byte array
Code:
public static string PasswordFixer(string skey,int keyLength)
{
int length = keyLength / 8;
byte[] key = Encoding.UTF8.GetBytes(skey);
byte[] k = GenerateEmptyArray(length);
for (int i = 0; i < key.Length; i++)
{
k[i] = key[i];
if(i == length-1)
break;
}
return Encoding.UTF8.GetString(k);
}
Iv - it's always 128bit long meaning 16bytes. you can ignore Iv if you want, in PostgreSQL if you planing to use `encrypt` function then you can ignore the Iv by hard coding like this `aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };`
keylength-
This is the AES key length in this example we use 128bit meaning 16 bytes. whatever the characters that you use as the Key need to match the length of 16 bytes.
PostgreSQL
The equivalent SQL statement for the encryption and decryption is this
encrypt_iv,decrypt_iv
select convert_from(decrypt_iv(decode(tbl1.encrypted,'base64')::bytea ,'NBJ42RKQ2vQoYFZO','j1C83921vHExVhVp', 'aes-cbc/pad:pkcs'), 'UTF-8') as decrypted,tbl1.encrypted from (select encode(encrypt_iv('Hello World', 'NBJ42RKQ2vQoYFZO','j1C83921vHExVhVp', 'aes-cbc/pad:pkcs'), 'base64') as encrypted) as tbl1
encrypt,decrypt
select convert_from(decrypt(decode(tbl1.encrypted,'base64')::bytea ,'NBJ42RKQ2vQoYFZO', 'aes-cbc/pad:pkcs'), 'UTF-8') as decrypted,tbl1.encrypted from (select encode(encrypt('Hello World', 'NBJ42RKQ2vQoYFZO', 'aes-cbc/pad:pkcs'), 'base64') as encrypted) as tbl1
I want to make an encrypted communication system with a dynamic key exchange between C# and PHP. At the moment I have a working encrypt/decrypt PHP <-> PHP and C# <-> C# but it's not working PHP <-> C# for some reason. The problem is that the C# code decrypted string generates a longer output than the PHP would expect, but the data is the same when viewing the output as a simple string. E.g a string "daa" sent from C# to PHP, decrypted length is 28, which is not what is supposed to be. Same goes with the string sent from PHP to C#, I get a compiler error ArgumentException: length
C# code:
public static string EncryptTest(string input)
{
string key = "256 bit key (32 char)";
input = Md5Sum(input).Substring(0, 4) + input;
var encoding = new UTF8Encoding();
var Key = encoding.GetBytes(key);
byte[] encrypted;
byte[] result;
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.PKCS7;
rj.Mode = CipherMode.CBC;
rj.KeySize = 256;
rj.BlockSize = 256;
rj.Key = Key;
rj.GenerateIV();
using (ICryptoTransform encryptor = rj.CreateEncryptor())
{
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(cs))
{
writer.Write(input);
}
}
encrypted = ms.ToArray();
result = new byte[rj.BlockSize / 8 + encrypted.Length];
// Result is built as: IV (plain text) + Encrypted(data)
Array.Copy(rj.IV, result, rj.BlockSize / 8);
Array.Copy(encrypted, 0, result, rj.BlockSize / 8, encrypted.Length);
}
}
}
finally
{
rj.Clear();
}
}
return Convert.ToBase64String(result);
}
public static string DecryptTest(string input)
{
string key = "256 bit key (32 char)";
byte[] data = Convert.FromBase64String(input);
if (data.Length < 32)
return null;
var encoding = new UTF8Encoding();
var Key = encoding.GetBytes(key);
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Key = Key;
// Extract the IV from the data first.
byte[] iv = new byte[aes.BlockSize / 8];
Array.Copy(data, iv, iv.Length);
aes.IV = iv;
// The remainder of the data is the encrypted data we care about.
byte[] encryptedData = new byte[data.Length - iv.Length];
Array.Copy(data, iv.Length, encryptedData, 0, encryptedData.Length);
using (ICryptoTransform decryptor = aes.CreateDecryptor())
{
using (MemoryStream ms = new MemoryStream(encryptedData))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
string output = reader.ReadToEnd();
if (output.Length < 4)
return null;
string dataHash = output.Substring(0, 4);
string dataInput = output.Substring(4);
string dataInputHash = Md5Sum(dataInput).Substring(0, 4);
if (dataHash != dataInputHash)
return null;
return dataInput;
}
}
}
}
}
}
private static string Md5Sum(string strToEncrypt)
{
UTF8Encoding ue = new UTF8Encoding();
byte[] bytes = ue.GetBytes(strToEncrypt);
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(bytes);
string hashString = "";
for (int i = 0; i < hashBytes.Length; i++)
{
hashString += Convert.ToString(hashBytes[i], 16).PadLeft(2, '0');
}
return hashString.PadLeft(32, '0');
}
PHP code:
$key = "256 bit key (32 char)";
function iv()
{
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
return mcrypt_create_iv($iv_size, MCRYPT_RAND);
}
function encrypt($data, $key32)
{
# Prepend 4-chars data hash to the data itself for validation after decryption
$data = substr(md5($data), 0, 4).$data;
# Prepend $iv to decrypted data
$iv = iv();
$enc = $iv.mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key32, $data, MCRYPT_MODE_CBC, $iv);
return base64_encode($enc);
}
function decrypt($data, $key32)
{
$data = base64_decode($data);
if ($data === false || strlen($data) < 32)
return null;
$iv = substr($data, 0, 32);
$encrypted = substr($data, 32);
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key32, $encrypted, MCRYPT_MODE_CBC, $iv), "\0");
if ($decrypted === false || is_null($decrypted) || strlen($decrypted) < 4)
return null;
$dataHash = substr($decrypted, 0, 4);
$data = substr($decrypted, 4);
if (substr(md5($data), 0, 4) !== $dataHash)
return null; // it breaks here, md5 sum is not correct because of the length
return $data;
}
PHP / mcrypt is not using PKCS#7 padding, it uses zero padding of 0..n bytes where n is the block size.
To PKCS#7-pad the plaintext before encryption, use:
$pad = $blockSize - (strlen($data) % $blockSize);
$pdata = $data . str_repeat(chr($pad), $pad);
to unpad the plaintext after decryption simply perform:
$pad = ord($pdata[strlen($pdata) - 1]);
$data = substr($pdata, 0, strlen($pdata) - $pad);
PKCS#7 is now the ad hoc standard for padding. Zero padding is non-deterministic; it may alter the plaintext if the plaintext ends with zero's itself.
I have a problem. I have a method to encrypt a password in php and in C# but i cannot get the same results with both algorithms. Someone can help me?
PhP
<?php
$password = 'MySecretPass';
$secret = '65rgt85k89xrDAr3';
$iv = 'AAAAAAAAAAAAAAAA';
$td = mcrypt_module_open('rijndael-128', '', 'cfb','');
mcrypt_generic_init($td, $secret, $iv);
$password = mcrypt_generic($td, $password);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$password=base64_encode($password);
echo $password;
?>
C#
var password = padString("MySecretPass");
txtEncrypt.Text = Convert.ToBase64String(EncryptStringToBytes(password,
Encoding.UTF8.GetBytes("65rgt85k89xrDAr3"),
Encoding.UTF8.GetBytes("AAAAAAAAAAAAAAAA"), PaddingMode.None));
txtEncrypt.Text = txtEncrypt.Text;
static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv, PaddingMode mode)
{
byte[] encrypted;
using (var rijAlg = new RijndaelManaged { Mode = CipherMode.CFB, BlockSize = 128, Padding = mode })
{
rijAlg.Key = key;
rijAlg.IV = iv;
var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
private static String padString(String source)
{
char paddingChar = ' ';
int size = 16;
int x = source.Length % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
The results for PhP is "/KNlzi/fZOERWL79", but for c# is /J643dvAR4/Gh0aYHdshNw==. I don't know why my results are different. In addition, I have wrote the code in Java and I get the same result than in C#.
Thanks in advance.
It's probably that Encoding.GetBytes(string) returns "Unicode encoding". That's an encoding that actually does not exist, but it returns UTF-16. On the other hand you treat your key and IV as ASCII characters.
So whichever encoding PHP is using at the time, there will be a mismatch. You should explicitly define which encoding should be used when converting textual strings to bytes, both in the PHP code as in your C# code.
I am attempting to integrate Desk.com's Multipass SSO into my website, and am having trouble generating the correct HMAC-SHA1 signature (so say the error logs). Here are the directions from Desk.com's website:
Build a SHA1 HMAC using your multipass API key and your finished multipass token.
Base64 encode the resulting HMAC.
According to the logs, my multipass token appears to be correct. First, the code in PHP that works perfectly:
// Build an HMAC-SHA1 signature using the multipass string and your API key
$signature = hash_hmac("sha1", $multipass, $api_key, true);
// Base64 encode the signature
$signature = base64_encode($signature);
^ note that hash_hmac's 'true' value is outputting information in raw binary - I'm not sure if this is the case in my C# code
Next, my C# code that is not working correctly:
protected string getSignature(string multipass)
{
string api_key = "my_key_goes_here";
HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(api_key));
hmac.Initialize();
byte[] buffer = Encoding.ASCII.GetBytes(multipass);
string signature = BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower();
return Convert.ToBase64String(Encoding.ASCII.GetBytes(signature));
}
This is the result of (literally) hours of searching and trying multiple different ways. I would be very grateful if I could get this figured out.
If you need a reference, check out this page by Desk.com: http://dev.desk.com/docs/portal/multipass. It has code examples and outlines the instructions for completing the code.
Edit: here is my multipass generation code.
protected string getMultipass(UserData user_data)
{
// Encode the data into a JSON object
JavaScriptSerializer s = new JavaScriptSerializer();
string json_data = s.Serialize(user_data);
// Acquire the Web.config appSettings
string site_key = "my_site_here";
string api_key = "my_key_here";
string iv = "OpenSSL for Ruby";
// Using byte arrays now instead of strings
byte[] encrypted = null;
byte[] bIV = Encoding.ASCII.GetBytes(iv);
byte[] data = Encoding.ASCII.GetBytes(json_data);
// XOR the first block (16 bytes)
// once before the full XOR
// so it gets double XORed
for (var i = 0; i < 16; i++)
data[i] = (byte)(data[i] ^ bIV[i]);
// Pad using block size of 16 bytes
int pad = 16 - (data.Length % 16);
Array.Resize(ref data, data.Length + pad);
for (var i = 0; i < pad; i++)
data[data.Length - pad + i] = (byte)pad;
// Use the AesManaged object to do the encryption
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.IV = bIV;
aesAlg.KeySize = 128;
// Create the 16-byte salted hash
SHA1 sha1 = SHA1.Create();
byte[] saltedHash = sha1.ComputeHash(Encoding.UTF8.GetBytes(api_key + site_key), 0, (api_key + site_key).Length);
Array.Resize(ref saltedHash, 16);
aesAlg.Key = saltedHash;
// Encrypt using the AES managed object
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
csEncrypt.FlushFinalBlock();
}
encrypted = msEncrypt.ToArray();
}
}
// Return the Base64-encoded encrypted data
return Convert.ToBase64String(encrypted, Base64FormattingOptions.None)
.TrimEnd("=".ToCharArray()) // Remove trailing "=" characters
.Replace("+", "-") // Change "+" to "-"
.Replace("/", "_"); // Change "/" to "_"
}
You can see the following code that works:
static string create(string userDetails) {
string accountKey = "YOUR_ACCOUNT_KEY";
string apiKey = "YOUR_API_KEY";
string initVector = "OpenSSL for Ruby"; // DO NOT CHANGE
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] keyBytesLong;
using( SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider() ) {
keyBytesLong = sha.ComputeHash( Encoding.UTF8.GetBytes( apiKey + accountKey ) );
}
byte[] keyBytes = new byte[16];
Array.Copy(keyBytesLong, keyBytes, 16);
byte[] textBytes = Encoding.UTF8.GetBytes(userDetails);
for (int i = 0; i < 16; i++) {
textBytes[i] ^= initVectorBytes[i];
}
// Encrypt the string to an array of bytes
byte[] encrypted = encryptStringToBytes_AES(textBytes, keyBytes, initVectorBytes);
string encoded = Convert.ToBase64String(encrypted);
return HttpUtility.UrlEncode(encoded);
}
static byte[] encryptStringToBytes_AES(byte[] textBytes, byte[] Key, byte[] IV) {
// Declare the stream used to encrypt to an in memory
// array of bytes and the RijndaelManaged object
// used to encrypt the data.
using( MemoryStream msEncrypt = new MemoryStream() )
using( RijndaelManaged aesAlg = new RijndaelManaged() )
{
// Provide the RijndaelManaged object with the specified key and IV.
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.KeySize = 128;
aesAlg.BlockSize = 128;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor();
// Create the streams used for encryption.
using( CryptoStream csEncrypt = new CryptoStream( msEncrypt, encryptor, CryptoStreamMode.Write ) ) {
csEncrypt.Write( textBytes, 0, textBytes.Length );
csEncrypt.FlushFinalBlock();
}
byte[] encrypted = msEncrypt.ToArray();
// Return the encrypted bytes from the memory stream.
return encrypted;
}
}
I hope it works for you.