I am trying to use AES encryption with encryption in one program and decryption in another. I have working code that encrypts the file but I need to extract the key to use in the other program to decrypt.
When I do this:
string key = String.Empty;
byte[] aesKey;
using (var aes = Aes.Create())
{
aesKey = aes.Key;
key = Convert.ToBase64String(aes.Key);
}
and use aesKey in my encrypt it works. When I try to convert from Base64 string to Byte[] it doesn't seem to work, It doesn't end up with the same bytes. How do you convert?
string sKey = "LvtZELDrB394hbSOi3SurLWAvC8adNpZiJmQDJHdfJU=";
aesKey = System.Text.Encoding.UTF8.GetBytes(sKey);
There is a corresponding From method that you should use.
byte[] aesKey = Convert.FromBase64String(sKey);
Related
I found an implementation for AES encryption/decryption that's supposed to work in PHP and C#:
https://odan.github.io/2017/08/10/aes-256-encryption-and-decryption-in-php-and-csharp.html
However, in this example, the IV is always 0, which is not good.
So, as the author suggests, I use the openssl_random_pseudo_bytes() function:
$ivlen = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($ivlen);
However, the problem now is, that I have to store the IV somewhere so that the C# app can use it for decryption. My idea was to base64_encode it and prepend it to the encrypted message with ":" separating both, so that I can simply split the string, then base64 decode it in C# and can use the IV. However, this does not work. This is the code:
public string DecryptString(string cipherText, byte[] key, byte[] iv)
{
// Instantiate a new Aes object to perform string symmetric encryption
Aes encryptor = Aes.Create();
encryptor.Mode = CipherMode.CBC;
// Set key and IV
byte[] aesKey = new byte[32];
Array.Copy(key, 0, aesKey, 0, 32);
encryptor.Key = aesKey;
encryptor.IV = iv;
// Instantiate a new MemoryStream object to contain the encrypted bytes
MemoryStream memoryStream = new MemoryStream();
// Instantiate a new encryptor from our Aes object
ICryptoTransform aesDecryptor = encryptor.CreateDecryptor();
// Instantiate a new CryptoStream object to process the data and write it to the
// memory stream
CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);
// Will contain decrypted plaintext
string plainText = String.Empty;
try {
// Convert the ciphertext string into a byte array
byte[] cipherBytes = Convert.FromBase64String(cipherText);
// Decrypt the input ciphertext string
cryptoStream.Write(cipherBytes, 0, cipherBytes . Length);
// Complete the decryption process
cryptoStream.FlushFinalBlock();
// Convert the decrypted data from a MemoryStream to a byte array
byte[] plainBytes = memoryStream.ToArray();
// Convert the decrypted byte array to string
plainText = Encoding.ASCII.GetString(plainBytes, 0, plainBytes.Length);
} finally {
// Close both the MemoryStream and the CryptoStream
memoryStream.Close();
cryptoStream.Close();
}
// Return the decrypted data as a string
return plainText;
}
And this is how I try to call the function with the IV prepended to the encrypted message:
private void btnDecrypt_Click(object sender, EventArgs e)
{
string encrypted = txtEncrypted.Text;
string password = txtPW.Text;
string[] temp = encrypted.Split(":".ToCharArray());
string iv_str = temp[0];
encrypted = temp[1];
SHA256 mySHA256 = SHA256Managed.Create();
byte[] key = mySHA256.ComputeHash(Encoding.ASCII.GetBytes(password));
iv_str = Encoding.Default.GetString(Convert.FromBase64String(iv_str));
byte[] iv = Encoding.ASCII.GetBytes(iv_str);
txtDecrypted.Text = this.DecryptString(encrypted, key, iv);
}
Doesn't work. It decrypts something, but that's just gibberish and not the message I encrypted in PHP.
I think it has to do with the IV somehow.
#Topaco:
Thank you very much... now I see what my mistake was. It works now with generated IV.
By the way, two more questions on the strength of the encryption:
Is it ok to use the following function to generate an IV (GenerateIV() for some reason won't work):
byte[] iv = new byte[16];
Random rnd = new Random();
rnd.NextBytes(iv);
I added a randomly generated salt to the password of the user, so that the key is a hash from the user password and a salt. I also prepend the salt, together with the now randomly generated IV, to the message. Then for the decryption process I use the prepended salt and the key the user enters. Works so far. But does it weaken the encryption? No, right?
Thank you very much.
// Edit: Code format doesn't work, don't know why.
Hi there i'm using this encryption method to encrypt my json value in .net side
public static string Encrypt256(string text)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.IV = Encoding.UTF8.GetBytes(AesIV256);
aes.Key = Encoding.UTF8.GetBytes(AesKey256);
aes.Mode = CipherMode.CBC;
byte[] src = Encoding.Unicode.GetBytes(text);
using (ICryptoTransform encrypt = aes.CreateEncryptor())
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
Debug.WriteLine(Convert.ToBase64String(dest));
return Convert.ToBase64String(dest);
}
}
And im trying to decrypt it in Node Js side
var crypto = require('crypto'),
algorithm = process.env.tombalaCryptoAlgorithm,
password = process.env.tombalaHmacPass,
iv = '!QAZ2WSX#EDC4RFV'
function encrypt(text) {
var cipher = crypto.createCipheriv(algorithm, password, iv)
var encrypted = cipher.update(text, 'utf8', 'base64')
encrypted += cipher.final('base64');
return encrypted;
You are converting your text to be encrypted to Unicode which means UTF-16.
In UTF-16 every character consists of two bytes. If the second byte is not used it is null as you have observed.
I assume you want UTF-8 encoding. Therefore replace the line
byte[] src = Encoding.Unicode.GetBytes(text);
with
byte[] src = Encoding.UTF8.GetBytes(text);
I've written a simple encryp/decrypt method in c# which uses the AES alg. When I try to encrypt and then decrypt a string with certain lengths like 4 or 7 characters, it works fine, with other lengths however It says that the padding is invalid and cannot be removed.
public static string Decrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateDecryptor();
byte[] encryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] decryptedBytes = dc.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.Unicode.GetString(decryptedBytes);
}
public static string Encrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateEncryptor();
byte[] decryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] encryptedBytes = dc.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length);
return Encoding.Unicode.GetString(encryptedBytes);
}
Ciphertexts are binary data which might contain bytes that are not printable. If try to encode the byte array as a Unicode string, you will lose some bytes. It will be impossible to recover them during decryption.
If you actually want to handle the ciphertext as a string, you need to convert it into a textual representation like Base 64 or Hex.
// encryption
return Convert.ToBase64String(decryptedBytes);
// decryption
byte[] decryptedBytes = Convert.FromBase64String(text);
I have the following code in C#:
Main Class
X509Certificate2 cert = new X509Certificate2("C:/test.pfx", "hello", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Encryption enc = new Encryption();
string encrypted = enc.Encrypt("hello there", cert);
string decrypted = enc.Decrypt(encrypted, cert);
Console.WriteLine("Encrypted Text: " + encrypted);
Console.WriteLine("Decrypted Text: " + decrypted);
Encryption Class
public string Encrypt(string plainText, X509Certificate2 cert)
{
RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] encryptedBytes = publicKey.Encrypt(plainBytes, false);
string encryptedText = encryptedBytes.ToString();
return encryptedText;
}
public string Decrypt(string encryptedText, X509Certificate2 cert)
{
RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
byte[] encryptedBytes = Encoding.UTF8.GetBytes(encryptedText);
byte[] decryptedBytes = privateKey.Decrypt(encryptedBytes, false);
string decryptedText = decryptedBytes.ToString();
return decryptedText;
}
As you can see, in the main class I am importing a certificate. Then I am creating an instance of the Encryption class. Then I pass plaintext to the Encrypt method along with the certificate in order to get the encrypted text. Afterwards, I pass the encrypted text to the Decrypt method to get the plaintext back.
My problem is that the result of printing the encrypted text is System.[]Byte (if I comment out the decryption call). If I do not comment out the decryption call, I get a Cryptographic Exception: Bad Data in the decryption method.
I guess that the encryptedBytes array is not being converted correctly to string. Furthermore, I am not sure if I am forming the RSAEncryptionProvider correctly. How can I solve this please?
Update
I solved one issue. When converting from byte array to string, I had to use Encoding.UTF8.GetString(EncryptedBytes). The problem now is that the decrypt method is giving me another cryptographic exception (he data to be decrypted exceeds the maximum for this modulus of 128 bytes).
Does anybody know why this is happening and how to solve it?
you can use base64 Format to convert type of variable (encryptedText) parameter by replace the functions
public string Encrypt(string plainText, X509Certificate2 cert)
{
RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] encryptedBytes = publicKey.Encrypt(plainBytes, false);
string encryptedText = Convert.ToBase64String(encryptedBytes);
return encryptedText;
}
public string Decrypt(string encryptedText, X509Certificate2 cert)
{
RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
byte[] decryptedBytes = privateKey.Decrypt(encryptedBytes, false);
string decryptedText = Encoding.UTF8.GetString(decryptedBytes);
return decryptedText;
}
Don't treat encrypted data as a string. Encryption algorithms work on binary data, and produce binary data, which cannot be interpreted as a string. It's naive to think that UTF-8 or any other encoding will be able to interpret any given chunk of binary data as a valid character string.
In your case, if you need to output encrypted data to the console for debugging purposes, go ahead with byte[] and dump it in hexadecimal, like this:
for (int i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString("X2"));
Console.Write(" ");
if ((i+1) % 16 == 0) Console.WriteLine();
}
I am trying to encrypt strings in .NET by using a RSA algorithm and decrypt the result in Java. At the moment, I have been able to do the opposite (Encrypt in Java, Decrypt in .NET).
Here I have my code that actually works (JAVA encryption):
byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String encryptedString = Base64.encode(cipherData);
return encryptedString;
And (.NET decryption)
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>");
string data2Decrypt = "BaB21vY+RD/jiY3AAsb269fIWTEH38s0xLUfJ7CoVUgaQ6vYzB0tiJ1Ag9HNEdCcuZdGchhqnms8jpsqsHC1iKrz6QCLsgUU7VNWDfQqZYR6Rl/GwR0biK2STnOL+g06f/JUdixHOHOgROify1m8qppYo5plpOVMqYFzEMREMkM=";
byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);
byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
string decryptedString = System.Text.Encoding.UTF8.GetString(plain);
Console.WriteLine("SALIDA: " + decryptedString);
Now I want to do the opposite... But I get some errors like (the size of the key should be 128 bytes... etc) How should I do it?
Here I add the current non working code:
.NET
public string Encrypt(string text)
{
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==</P><Q>4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==</Q><DP>5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==</DP><DQ>j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==</DQ><InverseQ>8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==</InverseQ><D>MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k=</D></RSAKeyValue>");
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] textBytes = encoding.GetBytes(text);
byte[] encryptedOutput = rsa1.Encrypt(textBytes, false);
string outputB64 = Convert.ToBase64String(encryptedOutput);
Console.WriteLine(outputB64);
return outputB64;
}
Java
public static String Decrypt(String encodedString) throws IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException
{
byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec rsaPrivKey = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(rsaPrivKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
}
The last few lines of your Java decrypt code do not make sense. These lines are:
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
You have to reverse the order of the steps you used to encrypt in .NET. First, you should Base64 decode the encoded string to get the cipher bytes. You did that, but you mislabeled the result as base64String. You probably should call this result cipherData. Second, you need to decrypt cipherData to get plain text. Third, you should create a string from plainbytes using the two-arg String constructor with the Charset for the second argument. Here is what the code should look like, or close to it.
byte[] cipherData = Base64.decode(encodedString);
byte[] plainBytes = cipher.doFinal(cipherData);
return new String(plainBytes, "UTF-8");
Finally, in Java every object has a toString() method but it doesn't always do what you want. For arrays the toString() method simply returns a representation of object id for that array, sort of the JVM equivalent of a memory address.
EDIT:
I missed that you are also using the wrong key in your decrypt code. Your are using the RSA public key, but you must instead use the RSA private key.
Here is the answer I couldn't post yesterday, related to the first answer to my post.
Well, I have tested the code and I have some problems. I have tried not to change anything unless it was completely necessary.
First I get an error here:
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
The "Entrust" crypto provider is not recognized... So I left just the first parameter. Then I get this error:
javax.crypto.BadPaddingException: Data must start with zero
I have tried through a WebService written in .NET which returns always byte arrays. Maybe there is some kind of problem in the translation. I know that I have to use Base64 numbers and (if I don't use AES) I have to break my Strings into pieces with the size of 128 bytes (limited by the RSA key).
I am still working on the problem to realize why I could encrypt in Java and decrypt in .NET but not the opposite.
Thanks again for your help!!
As you requested are hare some code snippets. RSA keys are from x509 certs.
Java RSA/AES:
// symmetric algorithm for data encryption
final String ALGORITHM = "AES";
// Padding for symmetric algorithm
final String PADDING_MODE = "/CBC/PKCS5Padding";
// character encoding
final String CHAR_ENCODING = "UTF-8";
// provider for the crypto
final String CRYPTO_PROVIDER = "Entrust";
// RSA algorithm used to encrypt symmetric key
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// symmetric key size (128, 192, 256) if using 192+ you must have the Java
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// installed
int AES_KEY_SIZE = 256;
private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// get the public key from the encryption certificate to encrypt with
PublicKey pubKey = cert.getPublicKey();
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
// set the cipher to use the public key
rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);
// encrypt the aesKey
return rsaCipher.doFinal(aesKey);
}
private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException {
// get the symmetric key generator
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(AES_KEY_SIZE); // set the key size
// generate the key
SecretKey skey = keyGen.generateKey();
// convert to binary
byte[] rawAesKey = skey.getEncoded();
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to encrypt mode, with the generated key
aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// get the initialization vector being used (to be returned)
byte[] aesIV = aesCipher.getIV();
// encrypt the data
byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);
// package the aes key, IV, and encrypted data and return them
return new AESEncryptedContents(rawAesKey, aesIV, encryptedData);
}
private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV,
byte[] encryptedData) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
NoSuchProviderException {
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to decrypt mode with the AES key, and IV
aesCipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(aesIV));
// decrypt and return the data
byte[] decryptedData = aesCipher.doFinal(encryptedData);
return decryptedData;
}
private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey)
throws IllegalBlockSizeException, BadPaddingException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, NoSuchProviderException {
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
// set the cipher to use the public key
rsaCipher.init(Cipher.DECRYPT_MODE, privKey);
// encrypt the aesKey
return rsaCipher.doFinal(encryptedAesKey);
}
C# .Net:
public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) {
if (data == null)
throw new ArgumentNullException("data");
byte[] encryptedData; // data to return
// begin AES key generation
RijndaelManaged aesAlg = new RijndaelManaged();
aesAlg.KeySize = AES_KEY_SIZE;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
// aes Key to be encrypted
byte[] aesKey = aesAlg.Key;
// aes IV that is passed back by reference
aesIV = aesAlg.IV;
//get a new RSA crypto service provider to encrypt the AES key with the certificates public key
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider())
{
//add the certificates public key to the RSA crypto provider
rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false));
//encrypt AES key with RSA Public key
//passed back by reference
encryptedAesKey = rsaCSP.Encrypt(aesKey, false);
//get an aes encryptor instance
ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor();
encryptedData = encryptWithAes(aesEncryptor, data);
}
if (encryptedData == null)
throw new CryptographicException(
"Fatal error while encrypting with AES");
return encryptedData;
}
private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) {
MemoryStream memStream = null; // stream to write encrypted data to
CryptoStream cryptoStream = null; // crypto stream to encrypted data
try {
memStream = new MemoryStream();
// initiate crypto stream telling it to write the encrypted data to
// the memory stream
cryptoStream = new CryptoStream(memStream, aesEncryptor,
CryptoStreamMode.Write);
// write the data to the memory stream
cryptoStream.Write(data, 0, data.Length);
} catch (Exception ee) {
// rethrow
throw new Exception("Error while encrypting with AES: ", ee);
} finally {
// close 'em
if (cryptoStream != null)
cryptoStream.Close();
if (memStream != null)
memStream.Close();
}
// return the encrypted data
return memStream.ToArray();
}