C# RSA Decrypt (The parameter is incorrect) - c#

Im using the following code to encrypt and decrypt a small file using RSA and safely transfer them using usb drive (I know, RSA is not the best for encrypting files...)
But for some reason it wont work anymore. Im trying to decrypt my file and it keeps throwing a "The parameter is incorrect" exception
The keys did not changed (both private and public)
The code did not changed (both encrypt and decrypt)
Anybody have an idea of what could be wrong?
static int SegmentLength = 213; //85; // keysize/8 -42 -1
public static byte[] EncryptRSA(string publicKey, byte[] data)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(2048, cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(publicKey));
//byte[] plainBytes = data;
//byte[] encryptedBytes = rsaProvider.Encrypt(plainBytes, false);
var length = data.Length / SegmentLength + 1;
MemoryStream stream = new MemoryStream();
for (var i = 0; i < length; i++)
{
int lengthToCopy;
if (i == length - 1 || data.Length < SegmentLength)
lengthToCopy = data.Length - (i * SegmentLength);
else
lengthToCopy = SegmentLength;
//var segment = decryptedData.Substring(i * SegmentLength, lengthToCopy);
byte[] segment = new byte[lengthToCopy];
Buffer.BlockCopy(data, i * SegmentLength, segment, 0, lengthToCopy);
byte[] encrypted = rsaProvider.Encrypt(segment,false);
stream.Write(encrypted,0,encrypted.Length);
}
return stream.ToArray();
}
private const int EncryptedLength = 256; //keylen * 8
public static byte[] DecryptRSA(string privateKey, byte[] data)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(2048, cspParams);
rsaProvider.ImportCspBlob(Convert.FromBase64String(privateKey));
var rsainfo = rsaProvider.ExportParameters(true);
var length = data.Length / EncryptedLength;
MemoryStream stream = new MemoryStream();
for (var i = 0; i < length; i++)
{
byte[] segment = new byte[EncryptedLength];
Buffer.BlockCopy(data, i * EncryptedLength, segment, 0, EncryptedLength);
byte[] decrypted = rsaProvider.Decrypt(segment, false);
stream.Write(decrypted, 0, decrypted.Length);
}
//string plainText = Encoding.UTF8.GetString(plainBytes, 0, plainBytes.Length);
return stream.ToArray();
}
System.Security.Cryptography.CryptographicException occurred
HResult=0x80070057 Message=Parâmetro incorreto.
Source=mscorlib StackTrace: at
System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32
hr) at
System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle
pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean
fOAEP, ObjectHandleOnStack ohRetDecryptedKey) at
System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[]
rgb, Boolean fOAEP) at Decriptor.Program.DecryptRSA(String
privateKey, Byte[] data) in
Program.cs:line 149
at Decriptor.Program.Main(String[] args) in
Program.cs:line 45
rsainfo {System.Security.Cryptography.RSAParameters} System.Security.Cryptography.RSAParameters
D {byte[256]} byte[]
DP {byte[128]} byte[]
DQ {byte[128]} byte[]
Exponent {byte[3]} byte[]
InverseQ {byte[128]} byte[]
Modulus {byte[256]} byte[]
P {byte[128]} byte[]
Q {byte[128]} byte[]

Related

How can i encrypt by postgres and decrypt by c#?

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

AES Encryption Windows Phone 8.1

I need to do 128 bit AES encryption on an application in Windows Phone 8.1. I used the following code for Encrypting and Decrypting the data respectively:
private string GetEncryptedContent(string content)
{
byte[] keyMaterial = Encoding.UTF8.GetBytes(EncryptionKey);
byte[] data = Encoding.UTF8.GetBytes(content);
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key, data, null);
return Encoding.UTF8.GetString(cipherText, 0, cipherText.Length);
}
private string GetDecryptedContent(string content)
{
byte[] keyMaterial = Encoding.UTF8.GetBytes(EncryptionKey);
byte[] data = Encoding.UTF8.GetBytes(content);
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Decrypt(key, data, null);
return Encoding.UTF8.GetString(cipherText, 0, cipherText.Length);
}
But the encryption and decryption doesn't seem to be working properly. It is getting encrypted to some unicode characters and throwing a crash on decrypting:
Length is not a multiple of block size and no padding is
selected.\r\nParameter name: ciphertext
What am I doing wrong here? Can someone please help?
EDIT
After a lot more time with Google, I found the following methods for encryption and decryption, but they doesn't seem to work either.
public string GetEncryptedContent(string input, string pass)
{
SymmetricKeyAlgorithmProvider SAP = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
CryptographicKey AES;
HashAlgorithmProvider HAP = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
CryptographicHash Hash_AES = HAP.CreateHash();
string encrypted = "";
try
{
byte[] hash = new byte[32];
Hash_AES.Append(CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(pass)));
byte[] temp;
CryptographicBuffer.CopyToByteArray(Hash_AES.GetValueAndReset(), out temp);
Array.Copy(temp, 0, hash, 0, 16);
Array.Copy(temp, 0, hash, 15, 16);
AES = SAP.CreateSymmetricKey(CryptographicBuffer.CreateFromByteArray(hash));
IBuffer Buffer = CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(input));
encrypted = CryptographicBuffer.EncodeToBase64String(CryptographicEngine.Encrypt(AES, Buffer, null));
return encrypted;
}
catch (Exception ex)
{
return null;
}
}
public string GetDecryptedContent(string input, string pass)
{
SymmetricKeyAlgorithmProvider SAP = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
CryptographicKey AES;
HashAlgorithmProvider HAP = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
CryptographicHash Hash_AES = HAP.CreateHash();
string decrypted = "";
try
{
byte[] hash = new byte[32];
Hash_AES.Append(CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(pass)));
byte[] temp;
CryptographicBuffer.CopyToByteArray(Hash_AES.GetValueAndReset(), out temp);
Array.Copy(temp, 0, hash, 0, 16);
Array.Copy(temp, 0, hash, 15, 16);
AES = SAP.CreateSymmetricKey(CryptographicBuffer.CreateFromByteArray(hash));
IBuffer Buffer = CryptographicBuffer.DecodeFromBase64String(input);
byte[] Decrypted;
CryptographicBuffer.CopyToByteArray(CryptographicEngine.Decrypt(AES, Buffer, null), out Decrypted);
decrypted = Encoding.UTF8.GetString(Decrypted, 0, Decrypted.Length);
return decrypted;
}
catch (Exception ex)
{
return null;
}
}
EDIT 2
Finally managed to get the encryption working properly, but the decryption is still not working presumably because the encoding I am passing is not the right one:
private string GetEncryptedContent(string content)
{
byte[] keyMaterial = Encoding.UTF8.GetBytes(EncryptionKey);
byte[] data = Encoding.UTF8.GetBytes(content);
byte[] iv = new byte[128 / 8]; // Adding this solved the encryption issue.
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key, data, iv);
return Convert.ToBase64String(cipherText);
}
private string GetDecryptedContent(string content)
{
byte[] keyMaterial = Encoding.UTF8.GetBytes(EncryptionKey);
byte[] data = Convert.FromBase64String(content); // Believe this is where the issue is, but not able to figure it out.
byte[] iv = new byte[128 / 8]; // Added this to make the decryption work the same way.
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Decrypt(key, data, iv);
return Convert.ToBase64String(cipherText);
}
I finally solved the problem. The problem was with the text encoding. Using the correct encoding solved the issue. The working code below:
public static string EncryptAES(string content, string password)
{
byte[] keyMaterial = Encoding.UTF8.GetBytes(password);
byte[] data = Encoding.UTF8.GetBytes(content);
byte[] iv = new byte[keyMaterial.Length];
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Encrypt(key, data, iv);
return Convert.ToBase64String(cipherText);
}
public static string DecryptAES(string content, string password)
{
byte[] keyMaterial = Encoding.UTF8.GetBytes(password);
byte[] data = Convert.FromBase64String(content);
byte[] iv = new byte[keyMaterial.Length];
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var key = provider.CreateSymmetricKey(keyMaterial);
byte[] cipherText = WinRTCrypto.CryptographicEngine.Decrypt(key, data, iv);
return Encoding.UTF8.GetString(cipherText, 0, cipherText.Length);
}
WinRTCrypto is available as part of PCLCrypto.

ArgumentOutOfRangeException when calling X509Certificate2

I tried create a X509Certificate2 object with a public rsa key for encryption in Unity with c#. I get the following exception:
> ArgumentOutOfRangeException: Cannot be negative.
> Parameter name: length
> System.String.Substring (Int32 startIndex, Int32 length) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/String.cs:348)
> Mono.Security.X509.X509Certificate.PEM (System.String type, System.Byte[] data) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/Mono.Security.X509/X509Certificate.cs:601)
.
static loadKey() {
//get rsa public key
byte[] data = GetBytes("MIIBIjANBgkqhk......EuH+zIXFzvirHQ2AxE/5wIDAQAB");
Debug.Log(data.Length);
X509Certificate2 x509certificate = new X509Certificate2(data);
//[...]
}
This is the GetBytes function
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;
}
For the record: data.Length is 784
Any ideas?
Thanks for your help. A certificate is defenately not a key so i finally managed to get a working function to encrypt a string with bouncycastle:
static string Encrypt2(string publicKeyFileName, string inputMessage)
{
try
{
// Converting the string message to byte array
System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
byte[] inputBytes = enc.GetBytes(inputMessage);
AsymmetricKeyParameter publicKey = ReadAsymmetricKeyParameter(publicKeyFileName);
// Creating the RSA algorithm object
IAsymmetricBlockCipher cipher = new Pkcs1Encoding(new RsaEngine());
// Initializing the RSA object for Encryption with RSA public key. Remember, for encryption, public key is needed
cipher.Init(true, publicKey);
//Encrypting the input bytes
byte[] cipheredBytes = cipher.ProcessBlock(inputBytes, 0, inputBytes.Length);
return Convert.ToBase64String(cipheredBytes);
}
catch (Exception ex)
{
// Any errors? Show them
Debug.Log("Exception encrypting file! More info:");
Debug.Log(ex.Message);
}
return "";
}
public static AsymmetricKeyParameter ReadAsymmetricKeyParameter(string pemFilename)
{
var fileStream = System.IO.File.OpenText(pemFilename);
var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(fileStream);
var KeyParameter = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)pemReader.ReadObject();
return KeyParameter;
}

SecretKey generation for DESede/CBC/PKCS5Padding

I'm having problems when encrypting data to be sent to a SOAP service.
I suppose the problem is in the SecretKey generation, because the response is still the same with an incorrect password.
The current code is:
WServiceSoap ws = new WService().getWServiceSoap();
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest("12345678".getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
SecretKey opKey = new SecretKeySpec(keyBytes, "DESede");
byte[] opIV = { 0, 0, 0, 1, 2, 3, 4, 5 };
Cipher c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, opKey, new IvParameterSpec(opIV));
byte[] encrypted = c.doFinal(
ClientDirectOperacionCTMS.DATOS_OPERACION.getBytes("UTF-8"));
String encryptedDatosOperacion= Base64.encodeBase64String(encrypted);
String result= ws.operacionCTMS(encryptedDatosOperacion);
System.out.println(result);
, and the exception is
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Server was unable to process request. ---> La operación de pago con tarjeta no ha sido satisfactoria. ---> Additional non-parsable characters are at the end of the string.
at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:111)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
I have also tried this code without success:
final byte[] keyBytes = Arrays.copyOf(Base64.decodeBase64("12345678"), 24);
SecretKey opKey = new SecretKeySpec(keyBytes, "DESede");
The decryption done by the server is
CheckKey(ref rgbKey);
cryptoProvider = new TripleDESCryptoServiceProvider();
cryptoTransform = cryptoProvider.CreateDecryptor(rgbKey, s_rgbIV);
memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(rgbEncryptedText, 0, rgbEncryptedText.Length);
}
originalText = Encoding.UTF8.GetString(memoryStream.ToArray());
, where CheckKey is
private static void CheckKey(ref Byte[] rgbKey)
{
if (rgbKey.Length > KEY_MAX_LENGTH)
{
Array.Resize(ref rgbKey, KEY_MAX_LENGTH);
}
else if (rgbKey.Length < KEY_MAX_LENGTH)
{
Byte fill = 0x41;
Int32 offset = rgbKey.Length;
Array.Resize(ref rgbKey, KEY_MAX_LENGTH);
for (Int32 index = offset; index < KEY_MAX_LENGTH; index++)
{
rgbKey[index] = fill++;
}
}
}

File Decryption Error: Bad Data

I am having some trouble getting a asp.net C# file encryption / decryption process to work. I can get the file uploaded and ecrypted, but cannot get the decryption to work.
I get the error: Exception Details: System.Security.Cryptography.CryptographicException: Bad Data. on the decryption line:
byte[] KeyDecrypted = rsa.Decrypt(KeyEncrypted, false);
Here is my encrypt function:
private void EncryptFile(string inFile)
{
RijndaelManaged rjndl = new RijndaelManaged();
rjndl.KeySize = 256;
rjndl.BlockSize = 256;
rjndl.Mode = CipherMode.CBC;
ICryptoTransform transform = rjndl.CreateEncryptor();
byte[] keyEncrypted = rsa.Encrypt(rjndl.Key, false);
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
int lKey = keyEncrypted.Length;
LenK = BitConverter.GetBytes(lKey);
int lIV = rjndl.IV.Length;
LenIV = BitConverter.GetBytes(lIV);
int startFileName = inFile.LastIndexOf("\\") + 1;
// Change the file's extension to ".enc"
string outFile = EncrFolder + inFile.Substring(startFileName, inFile.LastIndexOf(".") - startFileName) + ".enc";
lblDecryptFileName.Text = outFile;
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
outFs.Write(LenK, 0, 4);
outFs.Write(LenIV, 0, 4);
outFs.Write(keyEncrypted, 0, lKey);
outFs.Write(rjndl.IV, 0, lIV);
using (CryptoStream outStreamEncrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
int count = 0;
int offset = 0;
int blockSizeBytes = rjndl.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
int bytesRead = 0;
using (FileStream inFs = new FileStream(inFile, FileMode.Open))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamEncrypted.Write(data, 0, count);
bytesRead += blockSizeBytes;
}
while (count > 0);
inFs.Close();
}
outStreamEncrypted.FlushFinalBlock();
outStreamEncrypted.Close();
}
outFs.Close();
}
}
And here is the decrypt function where the error occurs.
private void DecryptFile(string inFile)
{
// Create instance of Rijndael for
// symetric decryption of the data.
RijndaelManaged rjndl = new RijndaelManaged();
rjndl.KeySize = 256;
rjndl.BlockSize = 256;
rjndl.Mode = CipherMode.CBC;
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
string outFile = DecrFolder + inFile.Substring(0, inFile.LastIndexOf(".")) + ".txt";
using (FileStream inFs = new FileStream(EncrFolder + inFile, FileMode.Open))
{
inFs.Seek(0, SeekOrigin.Begin);
inFs.Seek(0, SeekOrigin.Begin);
inFs.Read(LenK, 0, 3);
inFs.Seek(4, SeekOrigin.Begin);
inFs.Read(LenIV, 0, 3);
int lenK = BitConverter.ToInt32(LenK, 0);
int lenIV = BitConverter.ToInt32(LenIV, 0);
int startC = lenK + lenIV + 8;
int lenC = (int)inFs.Length - startC;
// Create the byte arrays for
// the encrypted Rijndael key,
// the IV, and the cipher text.
byte[] KeyEncrypted = new byte[lenK];
byte[] IV = new byte[lenIV];
// Extract the key and IV
// starting from index 8
// after the length values.
inFs.Seek(8, SeekOrigin.Begin);
inFs.Read(KeyEncrypted, 0, lenK);
inFs.Seek(8 + lenK, SeekOrigin.Begin);
inFs.Read(IV, 0, lenIV);
Directory.CreateDirectory(DecrFolder);
byte[] KeyDecrypted = rsa.Decrypt(KeyEncrypted, false);
ICryptoTransform transform = rjndl.CreateDecryptor(KeyDecrypted, IV);
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
int count = 0;
int offset = 0;
int blockSizeBytes = rjndl.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
inFs.Seek(startC, SeekOrigin.Begin);
using (CryptoStream outStreamDecrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamDecrypted.Write(data, 0, count);
}
while (count > 0);
outStreamDecrypted.FlushFinalBlock();
outStreamDecrypted.Close();
}
outFs.Close();
}
inFs.Close();
}
}
Any help on this would be great! I am not an RSA encryption expert and have been reading a lot of posts but still not able to come up with a solution.
I have finally figured this out. The code worked well in a desktop application when I tried it there. It just didn't work in the asp.net 4 web application I was trying to write. The issue was the RSA object wasn't persisted through the session. So, the RSA object was created okay. The file was encrypted okay. But when I went to decrypt the file the RSA object was not there. The error message of System.Security.Cryptography.CryptographicException: Bad Data is misleading as that wasn't really the issue, the data was fine.
So, when creating the key and the RSA object I used the following:
rsa = new RSACryptoServiceProvider(cspp);
Session["rsa"] = rsa;
Next, when the decryption function is called I added in:
if (rsa == null)
rsa = (RSACryptoServiceProvider)Session["rsa"];
Of course, there is a little more code around this also so catch if there is no key for the RSA session, but this is the high level solution for the issue I was having.
If anyone is looking for this let me know and I can share more of the code.

Categories

Resources