BouncyCastle create PKCS 7 Encrypted File? C# - c#

I am trying to use BouncyCastle to encrypt a file using the PKCS 7 file standard. Here is the code I have which outputs a p7m file. When I go to decrypt the file (using Entrust) I am prompted for my key store password, so it knows the file was encrypted for me using AES 128, but it cannot decrypt the body of the file. Something has to be going wrong on the encrypt.
byte[] fileContent = readFile(filename);
FileStream outStream = null;
Stream cryptoStream = null;
BinaryWriter binWriter = null;
try
{
CmsEnvelopedDataStreamGenerator dataGenerator = new CmsEnvelopedDataStreamGenerator();
dataGenerator.AddKeyTransRecipient(cert); //cert is the user's x509cert that i am encrypting for
outStream = new FileStream(filename + ".p7m", FileMode.Create);
cryptoStream = dataGenerator.Open(outStream, CmsEnvelopedGenerator.Aes128Cbc);
binWriter = new BinaryWriter(cryptoStream);
binWriter.Write(fileContent);
}
And when i try and decrypt the file using BouncyCastle I get this error when i pass the file contents to a CMSEnveloped Object:
IOException converting stream to byte array: Attempted to read past the end of the stream.
Any ideas whats going on here?

I used the EnvelopedCMS class to accomplish this.
http://msdn.microsoft.com/en-us/library/bb924575(VS.90).aspx

Related

C# Encrypting and Decrypting a text file

I'm trying to encrypt and then decrypt a file when needed, and read the file for use of the program. Still learning cryptography and I looked at several examples and tried this.
I have managed to en- and decrypt string but sadly that did not work in this case.
Cryptostream gives an IV does not match block size error on encrypt. Could not even have tested decrypting but that is most likely off too.
So question is: How can I encrypt, decrypt and read a .txt file?
private void EncryptFile(string resultFile)
{
string password = #"test";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsCrypt = File.Create(resultFile);
RijndaelManaged rmCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt, rmCrypto.CreateEncryptor(key, key),CryptoStreamMode.Write);
StreamWriter sWriter = new StreamWriter(cs);
sWriter.WriteLine(resultFile);
sWriter.Close();
cs.Close();
fsCrypt.Close();
}
private void DecryptFile(string resultFile)
{
string password = #"test";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsCrypt = new FileStream(resultFile, FileMode.Open);
RijndaelManaged rmCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt, rmCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read);
StreamWriter sWriter = new StreamWriter(cs);
sWriter.WriteLine(resultFile);
sWriter.Close();
cs.Close();
fsCrypt.Close();
}
I would recommend using AesManaged instead of RijndaelManaged, mostly because the former follows a defined standard.
Aes/rijndael have specified sizes for the key and initialization vector. You should not use bytes from a password directly. The correct way is to run the password thru a key derivation function see keyderivationalgorithmprovider, to ensure you have a key of the correct size and of good quality. Or use a randomly generated binary key of the correct size.
The second problem is the Initialization vector, this also need to be of a the correct size and should be random. But the IV is not secret and will usually be attached to the encrypted message, so using the key as the IV will not be secure.
The best option is probably to use the key and IV from the encryption class. See microsofts example for more details.

Rijndael encrypted text causes length of data to decrypt is invalid error - C#

I have searched online but have not been able to find any solutions to my problem.
I am using previously written methods to encrypt and ecrypt text using the Rijndael class.
I use these functions to encrypt and decrypt usernames and emails for a web application I have been working on.
The encryption/decryption works perfectly, but every once in a while I get this error:
System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid.
Currently, I am getting this error with a specific email address and I can't reproduce the error even if I replace some of the letters in the email.
Here are the encryption/decrytpion functions. The IV and Key are defined as read only strings.
static public string Encrypting(string Source)
{
byte[] bytIn = System.Text.ASCIIEncoding.ASCII.GetBytes(Source);
// create a MemoryStream so that the process can be done without I/O files
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
byte[] KEYBytes = Encoding.ASCII.GetBytes(KEY);
Rijndael rijndael = Rijndael.Create();
rijndael.IV = IVBytes;
rijndael.Key = KEYBytes;
// create Crypto Stream that transforms a stream using the encryption
CryptoStream cs = new CryptoStream(ms, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
// write out encrypted content into MemoryStream
cs.Write(bytIn, 0, bytIn.Length);
cs.FlushFinalBlock();
// get the output and trim the '\0' bytes
byte[] bytOut = ms.GetBuffer();
int i = 0;
for (i = 0; i < bytOut.Length; i++)
if (bytOut[i] == 0)
break;
// convert into Base64 so that the result can be used in xml
return System.Convert.ToBase64String(bytOut, 0, i);
}
static public string Decrypting(string Source)
{
// convert from Base64 to binary
byte[] bytIn = System.Convert.FromBase64String(Source);
// create a MemoryStream with the input
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytIn, 0, bytIn.Length);
byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
byte[] KEYBytes = Encoding.ASCII.GetBytes(KEY);
Rijndael rijndael = Rijndael.Create();
rijndael.IV = IVBytes;
rijndael.Key = KEYBytes;
// create Crypto Stream that transforms a stream using the decryption
CryptoStream cs = new CryptoStream(ms, rijndael.CreateDecryptor(), CryptoStreamMode.Read);
// read out the result from the Crypto Stream
System.IO.StreamReader sr = new System.IO.StreamReader(cs);
return sr.ReadToEnd();
}
FYI - I am very new to cryptography and security.
Can these functions be fixed to avoid special cases that cause the error, or should I scrap these and use the RijndaelManaged class?
Sites I found that use RijndaelManaged:
SeeSharp
TekEye
The issue is almost certainly nothing to do with Rijndael vs. RijndaelManaged (or any other such implementation), but instead because the encrypted data contains a 0x00, and you are incorrectly assuming that the the ciphertext ends at the first 0x00 byte. Since the ciphertext can legitimately contain any byte value you should instead use the stream's Length property to determine the length of the ciphertext.
Eliminate the section you've commented: "get the output and trim the '\0' bytes" and replace the return ... statement with:
return System.Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length);
It should be noted that there are many other issues with your use of cryptography here, e.g. the use of a key generated directly from the ASCII encoding of a string, and the fact you're using a fixed IV both negatively impact security.
The norm for the error is a padding issue. What version of .NET are you using? It is more common to use the AES classes (AES, or Advanced Encryption Standard, which is Rijndael). There are plenty of AES implementations you can find as samples.
If you need some proof AES is Rijndael: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard

XmlSerializer fails to deserialize XML containing encrypted string

I am serializing an object to an XML string using the .net XML serializer. That object contains a property of type string, whose content is an encrypyted string. The encryption is done using the Rijndael algorithm also provided by the .net, and the call looks like this:
var encryptedArr = EncryptStringToBytes(plainText, RijndaelKey, RijndaelIv);
return Encoding.Default.GetString(encryptedArr);
Although serialization goes fine, the problem is when trying to deserialize. the serializer throws an exception saying
"There is an error in XML document (1,1130). ' ', hexadecimal value
0x02, is an invalid character. Line..."
The thing is that these characters are to my understanding results of the encryption process so I guess messing with the encrypted string to make it XML-compatible is not an option. I also tried encoding the output string in the above piece of code differently:
UTF-8, Base64(which throws an exception saying the string is base64-incompatible) etc.
I've been looking into it for quite some time now. What do you recommend?
Have you taken a look at the example at the bottom of the RijndaelManaged class on MSDN?
Just wondering as they have a method, with the same name as the code you posted. If you are or arent encrypting via similar means, you could try returning a string instead of a byte array, from your method, by calling MemoryStream.GetString() and returning that value:
static string EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
//...
string cipherText = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
cipherText = msEncrypt.ToString();
}
}
}
// Return the encrypted bytes from the memory stream.
return cipherText;
}
What happens if your plainText goes though that? Maybe more information is needed about the plaintext. Might be the case of: Old Post

Encrypt data using c# and decrypt it using openssl api, why there are lots of trashy padding at the end of decrypted data?

I using RSA(1024) to encrypt/decrypt strings. The encryption is implemented using public key and is written in C#, and the decryption is implementation by c. I encrypt the string:
86afaecb-c211-4d55-8e90-2b715d6d64b9
and write the encrypted data to a file. Then, I using openssl api to read the encrypted data from the file and decrypt it. However, I got the output as:
86afaecb-c211-4d55-8e90-2b715d6d64b9oeheBjQ8fo1AmDnor1D3BLuPyq9wJBAOV+M/WVNYzYr
PJBKoskOj+4LaNpT+SpkfK81nsnQEbHbjgao4eHNU+PmWl9
It seems that there are some trashy padding at the end of original string. Why It Occurs? And how to solve the problem?
Some code snippet is shown below:
// Encrypt
{
string plainData = “86afaecb-c211-4d55-8e90-2b715d6d64b9”;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(paraPub);
byte[] testData = Encoding.UTF8.GetBytes(plainData);
byte[] encryptedData = rsa.Encrypt(testData, true);
FileStream pFileStream = null;
string fileName = "encryptedData.dat";
pFileStream = new FileStream(fileName, FileMode.OpenOrCreate);
pFileStream.Write(encryptedData, 0, encryptedData.Length);
...
}
// Decrypt
{
char *encrypt = malloc(RSA_size(privateKey));
FILE *out = fopen("encryptedData.dat", "r");
int encrypt_len = fread(encrypt, sizeof(*encrypt), RSA_size(privateKey), out);
fclose(out);
decrypt = malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len,
(unsigned char*)encrypt,
(unsigned char*)decrypt,
privateKey, RSA_PKCS1_OAEP_PADDING) == -1) {
// error handle
}
printf("Decrypted message: %s\n", decrypt);
}
I solve the problem by initializing the decrypt using "memset(decrypt, 0, encrypt_len);" after "decrypt = malloc(encrypt_len);". Thx everyone.
The issue is that you should use the decrypted size instead of directly treating the output of the decryption as a null terminated string.
RSA_private_decrypt() returns the size of the recovered plaintext.

Encryption output always different even with same key

I'm trying to store a password in a file that I'd like to retrieve for later. Hashing is not an option as I need the password for connecting to a remote server for later.
The following code works well, but it creates a different output each time even though the key is the same. This is bad as when the application shuts down and restarts I won't be able to retrieve my password any more. How can I store passwords in a file and retrieve them later?
public class EncyptDecrypt {
static System.Security.Cryptography.TripleDESCryptoServiceProvider keyProv = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
public static System.Security.Cryptography.TripleDESCryptoServiceProvider KeyProvider {
get {
keyProv.Key = new byte[] { /* redacted with prejudice */ };
return keyProv;
}
}
public static string Encrypt(string text, SymmetricAlgorithm key) {
if (text.Equals(string.Empty)) return text;
// Create a memory stream.
MemoryStream ms = new MemoryStream();
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
// Create a StreamWriter to write a string
// to the stream.
StreamWriter sw = new StreamWriter(encStream);
// Write the plaintext to the stream.
sw.WriteLine(text);
// Close the StreamWriter and CryptoStream.
sw.Close();
encStream.Close();
// Get an array of bytes that represents
// the memory stream.
byte[] buffer = ms.ToArray();
// Close the memory stream.
ms.Close();
// Return the encrypted byte array.
return System.Convert.ToBase64String(buffer);
}
// Decrypt the byte array.
public static string Decrypt(string cypherText, SymmetricAlgorithm key) {
if (cypherText.Equals(string.Empty)) return cypherText;
string val;
try {
// Create a memory stream to the passed buffer.
MemoryStream ms = new MemoryStream(System.Convert.FromBase64String(cypherText));
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
// Create a StreamReader for reading the stream.
StreamReader sr = new StreamReader(encStream);
// Read the stream as a string.
val = sr.ReadLine();
// Close the streams.
sr.Close();
encStream.Close();
ms.Close();
}
catch (System.Exception) {
return string.Empty;
}
return val;
}
}
I believe that what's happening is that the crypto provider is randomly generating an IV. Specify this and it should no longer differ.
Edit: You can do this in your 'keyProvider' by setting the IV property.
According to the docs of CreateEncryptor:
If the current IV property is a null
reference (Nothing in Visual Basic),
the GenerateIV method is called to
create a new random IV.
This will make the ciphertext different every time.
Note: a way around this is discussed here where I suggest you can prepend the plaintext with a mac ... then the first block of ciphertext is effectively the IV, but it's all repeatable
You need to specify an IV (initialization vector), even if you generate a random one. If you use random IV then you must store it along with the ciphertext so you can use it later on decryption, or you can derive an IV from some other data (for example if you're encrypting a password, you can derive the IV from the username).

Categories