First of all I read this Hashing a password using SHA256 and .NET/Node.js and it didn't help me.
I have to verify passwords hashes created in ASP.NET in node.js environment. I was told that passwords are generated using this algorithm: What is default hash algorithm that ASP.NET membership uses?.
I have example password hash and salt (first line is password and second line is salt):
"Password": "jj/rf7OxXM263rPgvLan4M6Is7o=",
"PasswordSalt": "/Eju9rmaJp03e3+z1v5s+A==",
I know that hash algorithm is SHA1 and I know that above hash is generated for input test123. However I can't reproduce hashing algorithm to get same hash for this input. What I tried:
Password = "jj/rf7OxXM263rPgvLan4M6Is7o="
PasswordSalt = "/Eju9rmaJp03e3+z1v5s+A=="
crypto = require("crypto")
sha1 = crypto.createHash("sha1")
PasswordSalt = new Buffer(PasswordSalt, 'base64').toString('utf8')
sha1.update(PasswordSalt+"test123", "utf8")
result = sha1.digest("base64")
console.log(Password)
console.log(result)
Result is:
jj/rf7OxXM263rPgvLan4M6Is7o=
xIjxRod4+HVYzlHZ9xomGGGY6d8=
I was able to get working C# algorithm:
using System.IO;
using System;
using System.Text;
using System.Security.Cryptography;
class Program
{
static string EncodePassword(string pass, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] src = Convert.FromBase64String(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
static void Main()
{
string pass = "test123";
string salt = "/Eju9rmaJp03e3+z1v5s+A==";
string hash = Program.EncodePassword(pass,salt);
Console.WriteLine(hash);
// outputs jj/rf7OxXM263rPgvLan4M6Is7o=
}
}
So now it is just a matter of porting this algorithm to node.js. The problem is that c# somehow magically operates on bytes and I don't know how to do it in node. Consider following code (it does not use any salt - it just creates base64 sha1 from password:
crypto = require("crypto")
pass = 'test123'
sha1 = crypto.createHash("sha1")
buf = new Buffer( pass, 'utf8')
sha1.update(buf)
result = sha1.digest("base64")
console.log(result)
// outputs cojt0Pw//L6ToM8G41aOKFIWh7w=
And in c#
using System.Text;
using System.Security.Cryptography;
string pass = "test123";
byte[] bytes = Encoding.Unicode.GetBytes(pass);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(bytes);
string hash = Convert.ToBase64String(inArray);
Console.WriteLine(hash);
// outputs Oc/baVMs/zM28IqDqsQlJPQc1uk=
I need code in node.js that will return same value as code in c#. Any ideas?
I finally found the right answer here: https://gist.github.com/PalmerEk/1191651 (with little change from 'ucs2' to 'utf16le'):
function dotnet_membership_password_hash(pass, salt)
{
var bytes = new Buffer(pass || '', 'utf16le');
var src = new Buffer(salt || '', 'base64');
var dst = new Buffer(src.length + bytes.length);
src.copy(dst, 0, 0, src.length);
bytes.copy(dst, src.length, 0, bytes.length);
return crypto.createHash('sha1').update(dst).digest('base64');
}
there is a nodejs module which does all the magic for you. No function on stackoverflow worked in my case, but this module works:
https://www.npmjs.com/package/aspnet-identity-pw
var passwordHasher = require('aspnet-identity-pw');
var hashedPassword = passwordHasher.hashPassword('SomePassword');
var isValid = passwordHasher.validatePassword('SomePassword', hashedPassword);
Changing the encoding of the buffer to utf16le works for both examples you provided here.
This is confirmed by the following StackOverflow Answer.
This is further documented at the relevant .Net Framework documentation
Related
I'm trying to write the C# equivalent for the following Java code:
protected static final String DES_ECB_PKCS5PADDING = "DESede/ECB/PKCS5Padding";
public static String decryptValueDirect(String value, String key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
GeneralSecurityException, IllegalBlockSizeException,
BadPaddingException {
byte[] bytes = Base64.decodeBase64(value);
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5PADDING);
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey(key.getBytes()));
byte[] decryptedValue = cipher.doFinal(bytes);
String nstr = new String(decryptedValue);
return nstr;
}
protected static SecretKey convertSecretKey(byte[] encryptionKey) throws GeneralSecurityException {
if (encryptionKey == null || encryptionKey.length == 0)
throw new IllegalArgumentException("Encryption key must be specified");
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(TRIPLEDES);
KeySpec keySpec = new DESedeKeySpec(encryptionKey);
return keyFactory.generateSecret(keySpec);
}
The source text is a base64 encoded, then encrypted and then base64 encoded for transport on a rabbit queue. Our vendor who handles the encryption provided the above for decryption in Java, but has no idea about C#.
The only input on the encryption side is a key, a random string. We use the same string for encryption/decryption 012345678901234567890123456789 in our dev env. That is the only input, no salt, hashing (that i see) or pw iterations. The only requirement is that it is at least 24 chars long.
My C# code is below and a fiddle of my attempt is here.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
//Message Data value
//We are using encrypted multibyte.
string myData = #"ROE8oYeV7B6faUsvfIx0Xe55vSs9IR5DlWGRbSM+lmKmLcaJsA13VudwWlAEYtLUD8+nMXShky0grSxsk0Z9cQe5V45XnAIfUhnyzI9a0jtMFC8XnIZ5dbclPO/V73QnieIZDkbNV5cPo3BM+l79ai96KB/gkF3xuerFPxvWejtPyWbOyO+FfNyFps4gAYDITsYIAEH39VP4eipmQ5zc18BA39lajQ3UaVewSxz7H+x3Ooe2SzJT/TQWRkioJSEFwexqzkHiLOQ0MOCIVD9xTWpLYnsL3LMwyF6H8f0PY4Fc57LVGhvUZ7dsB9NWUAnmG3uqbsonNFVhuXyvJTWNyFOHwFzOMx6XDLJJFHGZhaHg2VrescfnpUtonQY08RgojBngyJNRqK8URAvI3bqKq8Y7F/9HmEtMIIQe6KuuTmU=";
string myKey = "012345678901234567890123456789";//Development Env Key.
Console.WriteLine("Decrypt1:");
string s = Decrypt1(myData, myKey);
Console.ReadLine();
}
public static string Decrypt1(string value, string decryptionKey)
{
string decryptString = "";
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashMD5Provider = new MD5CryptoServiceProvider();
try
{
byte[] decodedData = Convert.FromBase64String(value);
tDESalg.Mode = CipherMode.ECB;
tDESalg.Padding = PaddingMode.PKCS7;//According to MS, same as PKCS5PADDING
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
//byte[] IV = tDESalg.IV;
byte[] IV = new byte[tDESalg.BlockSize / 8]; //The size of the IV property must be the same as the BlockSize property divided by 8
var memoryStream = new MemoryStream(decodedData);
var cryptoStream = new CryptoStream(memoryStream, tDESalg.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
var reader = new StreamReader(cryptoStream);
decryptString = reader.ReadToEnd();
byte[] decryptData = Convert.FromBase64String(decryptString);
}
catch (Exception e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message + e.StackTrace);
return null;
}
return decryptString;
}
}
Searching seems to point to the same answer, the key, encoding, ... all must be the same. I just don't know what that would be the equivalent for the Java source provided. :) Any suggestions will be helpful.
MD5 has a 16-byte output, Triple DES (3DES) requires a 24-byte key. There is a key size mis-match.
The C# and Java key derivations are substantially different:
C#:
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
returns 16-bytes.
Java:
SecretKeyFactory.getInstance(TRIPLEDES)
returns 24-bytes.
There is a key option (2TDEA) where a 16-byte key is used and the first 8-bytes will be duplicated to create the last 8-bytes. NIST has deprecated this option.
Some implementations will accept a 16-byte key and extend the key to 24-bytes and some will not. You should provide all 24-bytes to 3DES, do not rely on an implementation to create the 24-byte key.
Note: The question was updated so it is not clear that the the actual encrytpion key is derived.
Recently I began developing a new MVC app and needed to take an older existing asp.net membership database and convert it into the new(er) Identity system.
If you've found yourself in a similar situation, then likely you've come upon this helpful post from microsoft which gives you great guidance and scripts on converting the database over to the new schema, including the passwords.
To handle the differences in hashing/encryption of passwords between the two systems, they include a custom password hasher, SqlPasswordHasher, which parses the password field (which has been combined into Password|PasswordFormat|Salt) and attempts to duplicate the logic found inside SqlMembershipProvider to compare the incoming password with the stored version.
However, as I (and another commenter on that post) noticed, this handy hasher they provided doesn't handle Encrypted passwords (despite the confusing lingo they use in the post that seems to indicate that it does). It seems like it should, considering they do bring across the password format into the database, but then curiously the code doesn't use it, instead having
int passwordformat = 1;
which is for hashed passwords. What I needed was one that would handle my scenario which is encrypted passwords using the System.Web/MachineKey configuration element's decryptionKey.
If you also are in such a predicament, and are using the AES algorithm (as defined in the decryption property of the machineKey) then my answer below should come to your rescue.
First, let's talk real quick about what the SqlMembershipProvider is doing under the hood. The provider combines the salt, converted to a byte[] with the password, encoded as a unicode byte array, into a single larger byte array, by concatenating the two together. Pretty straightforward. Then it passes this off, through an abstraction (MembershipAdapter) to the MachineKeySection where the real work is done.
The important part about that handoff is that it instructs the MachineKeySection to use an empty IV (intialization vector) and also to perform no signing. That empty IV is the real lynchpin, because the machineKey element has no IV property, so if you've scratched your head and wondered how the providers were handling this aspect, that's how. Once you know that (from digging around the source code) then you can distill down the encryption code in the MachineKeySection code and combine it with the membership provider's code to arrive at a more complete hasher. Full source:
public class SQLPasswordHasher : PasswordHasher
{
public override string HashPassword(string password)
{
return base.HashPassword(password);
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
string[] passwordProperties = hashedPassword.Split('|');
if (passwordProperties.Length != 3)
{
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
else
{
string passwordHash = passwordProperties[0];
int passwordformat = int.Parse(passwordProperties[1]);
string salt = passwordProperties[2];
if (String.Equals(EncryptPassword(providedPassword, passwordformat, salt), passwordHash, StringComparison.CurrentCultureIgnoreCase))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
else
{
return PasswordVerificationResult.Failed;
}
}
}
//This is copied from the existing SQL providers and is provided only for back-compat.
private string EncryptPassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bRet = null;
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm hm = HashAlgorithm.Create("SHA1");
if (hm is KeyedHashAlgorithm)
{
KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm;
if (kha.Key.Length == bSalt.Length)
{
kha.Key = bSalt;
}
else if (kha.Key.Length < bSalt.Length)
{
byte[] bKey = new byte[kha.Key.Length];
Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
kha.Key = bKey;
}
else
{
byte[] bKey = new byte[kha.Key.Length];
for (int iter = 0; iter < bKey.Length;)
{
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
kha.Key = bKey;
}
bRet = kha.ComputeHash(bIn);
}
else
{
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = hm.ComputeHash(bAll);
}
}
else //MembershipPasswordFormat.Encrypted, aka 2
{
byte[] bEncrypt = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bEncrypt, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bEncrypt, bSalt.Length, bIn.Length);
// Distilled from MachineKeyConfigSection EncryptOrDecryptData function, assuming AES algo and paswordCompatMode=Framework20 (the default)
using (var stream = new MemoryStream())
{
var aes = new AesCryptoServiceProvider();
aes.Key = HexStringToByteArray(MachineKey.DecryptionKey);
aes.GenerateIV();
aes.IV = new byte[aes.IV.Length];
using (var transform = aes.CreateEncryptor())
{
using (var stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
stream2.Write(bEncrypt, 0, bEncrypt.Length);
stream2.FlushFinalBlock();
bRet = stream.ToArray();
}
}
}
}
return Convert.ToBase64String(bRet);
}
public static byte[] HexStringToByteArray(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;
}
private static MachineKeySection MachineKey
{
get
{
//Get encryption and decryption key information from the configuration.
System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
return cfg.GetSection("system.web/machineKey") as MachineKeySection;
}
}
}
If you have a different algorithm, then the steps will be very close to the same, but you may want to first dive into the source for MachineKeySection and carefully walkthrough how they're initializing things. Happy Coding!
Iam trying to send EmployeeId in another page using query string but I want to send it in encrypted format.
If anyone knows the answer, any help is a great help.
From http://www.infoexpediters.com/SecureQueryString.cs:
public string encrypt(string serializedQueryString)
{
byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
des.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(cryptoKey));
des.IV = IV;
return Convert.ToBase64String(
des.CreateEncryptor().TransformFinalBlock(
buffer,
0,
buffer.Length
)
);
}
public string decrypt(string encryptedQueryString)
{
try
{
byte[] buffer = Convert.FromBase64String(encryptedQueryString);
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
des.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(cryptoKey));
des.IV = IV;
return Encoding.ASCII.GetString(
des.CreateDecryptor().TransformFinalBlock(
buffer,
0,
buffer.Length
)
);
}
catch (CryptographicException)
{
throw new InvalidQueryStringException();
}
catch (FormatException)
{
throw new InvalidQueryStringException();
}
}
Use a POST not a GET, that way it is not visible in the url. Implement some small encryption done on the POST body before sending, and decrypt upon receiving.
I assume you are using javascript on the pages? Provide more info on what languages you are using (php/python etc?) for something more specific (and code)
You may or may not really need encryption, but assuming you do, you can do this in PHP using triple des (or whatever you want) like this:
// Init mcrypt stuff
$descriptor = mcrypt_module_open('tripledes', '', MCRYPT_MODE_ECB, '');
$key = substr(md5('put your secret here'), 0, mcrypt_enc_get_key_size($descriptor));
$vector = mcrypt_create_iv(mcrypt_enc_get_iv_size($descriptor), MCRYPT_RAND);
mcrypt_generic_init($descriptor, $key, $vector);
// Encrypt id
$encryptedEmployeeId = mcrypt_generic($descriptor, $_GET['EmployeeId']);
// Clean up mcrypt
mcrypt_generic_deinit($descriptor);
mcrypt_module_close($descriptor);
The reverse process is similar except using mdecrypt_generic(). Of course, I've made the assumption that you're using PHP :).
How does ASP.NET membership generate their salt key and then how do they encode it (that is, is it salt + password or password + salt)?
I am using SHA-1 with my membership, but I would like to recreate the same salts so the built-in membership stuff could hash the stuff the same way as my stuff can.
Edit 2: Never mind. I misread it and was thinking it said bytes, not bits. So I was passing in 128 bytes, not 128 bits.
Edit: I been trying to make it so. This is what I have,
public string EncodePassword(string password, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] src = Encoding.Unicode.GetBytes(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
private byte[] createSalt(byte[] saltSize)
{
byte[] saltBytes = saltSize;
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(saltBytes);
return saltBytes;
}
So I have not tried to see if the ASP.NET membership will recognize this yet the hashed password looks close. I just don't know how to convert it to base64 for the salt.
I did this
byte[] storeSalt = createSalt(new byte[128]);
string salt = Encoding.Unicode.GetString(storeSalt);
string base64Salt = Convert.ToBase64String(storeSalt);
int test = base64Salt.Length;
Test length is 172 which is well over the 128 bits so what am I doing wrong?
This is what their salt looks like
vkNj4EvbEPbk1HHW+K8y/A==
This is what my salt looks like
E9oEtqo0livLke9+csUkf2AOLzFsOvhkB/NocSQm33aySyNOphplx9yH2bgsHoEeR/aw/pMe4SkeDvNVfnemoB4PDNRUB9drFhzXOW5jypF9NQmBZaJDvJ+uK3mPXsWkEcxANn9mdRzYCEYCaVhgAZ5oQRnnT721mbFKpfc4kpI=
What is default hash algorithm that ASP.NET membership uses? has a good discussion of their default algorithm.
I hope that helps!
Edit-
The answer I was referring to is the code in the top post,
public string EncodePassword(string pass, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
//byte[] src = Encoding.Unicode.GetBytes(salt); Corrected 5/15/2013
byte[] src = Convert.FromBase64String(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
They are combining Unicode Salt + Pass using BlockCopy
-- In response to your question:
Both algorithms are necessary and fulfill different roles...
RNG Crypto is used to generate the salt. It is basically a long string of random data. This is generated and stored on a per user basis. Typically this is done when a user is created or a password is changed.
BlockCopy is just the method they use to combine the salt with the password. The above code essentially equates to salt + password.
You aren't going to be able to recreate a salt value as it is completely random. It is, however, stored for each user by the framework.
Combining the salt with the password and hashing it using the technique above will allow you to verify users passwords using the hashed value stored by the framework.
I think we both read your question differently. The code I posted won't generate your salt, but it will let you use it in a way that is compatible with ASP.NET membership.
Sorry my explanation isn't the best- does that answer your question?
Here is how the SQLMembershipProvider generates salt.
private string GenerateSalt() {
var buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
You can download the ASP.NET's SQL Provider code here.
The issue I was having was a development application running on IIS7. .NET 4.0 was using a different default hash algorithm than the default HashAlgorithmType for .NET 2.0.
In the "EncodePassword" sample code by Microsoft, they reference Membership.HashAlgorithmType which I believe returns the default for the framework, if it is not specified in the web.config.
I was able to get both this GenerateSalt and EncodePassword method to work for my application.
My combined code:
internal string GenerateSalt()
{
byte[] buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
internal string EncodePassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[] bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm s = HashAlgorithm.Create("SHA1");
// Hardcoded "SHA1" instead of Membership.HashAlgorithmType
bRet = s.ComputeHash(bAll);
}
else
{
bRet = EncryptPassword(bAll);
}
return Convert.ToBase64String(bRet);
}
Here is one way of doing it. A salt is just a random number, you can use RNGCryptoServiceProvider class in the framework library to produce good random number to use as salt
private const int ITERATIONS = 10000;
private const int SALT_SIZE = 32;
private const int HASH_SIZE = 32;
public void SaltAndHashPassword(string password, out byte[] salt,
out byte[] hash)
{
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
password,
SALT_SIZE,
ITERATIONS);
salt = rdb.Salt;
hash = rdb.GetBytes(HASH_SIZE);
}
I have given a task in which I need to encrypt an user's ID using AES encryption, what they want is I need to pass in a parameter in a website just like this.
URL : http://www.site.com/event/sample.jce
Parameter : ?param= encrypted text
aside from that there was an attched php sample that they want me to follow to encrypt but I don't have an idea on how to convert this one in .NET
function getEncrypt($sStr, $sKey, $sIV){
$sCipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $sKey, $sStr, MCRYPT_MODE_CFB, $sIV);
return bin2hex($sCipher);
}
$sStr = "13410##13";
$sKey = "mediaservice1234";
$sKey = "kjcemsdev3jangho"; // Do not change
$sIV = "fs0tjwkdgh0akstp"; // Do not change
$tmp= getEncrypt($sStr, $sKey, $sIV);
Could somebody help me to understand this codes? or better if they could help me to convert this one on .NEt code? Thanks. :)
Try this, you need to set the FeedbackSize and Padding:
public static string Encrypt(string plaintext)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
//RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.FeedbackSize = 8;
rijndaelCipher.Mode = CipherMode.CFB;
rijndaelCipher.KeySize = 128;
// rijndaelCipher.BlockSize = 128;
rijndaelCipher.BlockSize = 128;
rijndaelCipher.Padding = PaddingMode.Zeros;
byte[] plaintextByte = System.Text.Encoding.ASCII.GetBytes(plaintext);
//Rfc2898DeriveBytes
ASCIIEncoding textConverter = new ASCIIEncoding();
rijndaelCipher.Key = textConverter.GetBytes(PRIVATEKEY); ;
rijndaelCipher.IV = Convert.FromBase64String(PRIVATEIV);
ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor();
//http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(VS.80).aspx
//Encrypt the data.
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
//Convert the data to a byte array.
byte[] toEncrypt = textConverter.GetBytes(plaintext);
//Write all data to the crypto stream and flush it.
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
byte[] encrypted = new byte[16];
//Get encrypted array of bytes.
encrypted = msEncrypt.ToArray();
return Convert.ToBase64String(encrypted);
}
Here you can find some more information about using the AES encryption in .net:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged%28VS.80%29.aspx
The code is pretty straight forward.