|
Wrap your code in a Try/Catch block:
try<br />
{<br />
}<br />
catch(CryptoHelpException che)<br />
{<br />
}
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Hi,
Please help me on this padding problem. I m facing problem while decrypt of the file after the closing the curly barces of
"using (CryptoStream cin = new CryptoStream(fin, sma.CreateDecryptor(), CryptoStreamMode.Read),
chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write))"
It works fine when we add something in the encrypted file, but problem arises if i delete something from the encrypted file & tried to decrypt the file again.
Regards
Pomey
public static void DecryptFileOnly(string filename, string filemask, string key, string fileExt)
{
try{
int index;
string outFile;
index = filename.LastIndexOf(fileExt);
outFile = filename.Substring(0, index);
//outFile = filename.Substring(0, filename.LastIndexOf(".")) + ".xml";
//*************************************************************
// create and open the file streams
using (FileStream fin = File.OpenRead(filename), fout = File.OpenWrite(outFile))
{
int size = (int)fin.Length; // the size of the file for progress notification
byte[] bytes = new byte[BUFFER_SIZE]; // byte buffer
int read = -1; // the amount of bytes read from the stream
// read off the IV and Salt
byte[] IV = new byte[16];
fin.Read(IV, 0, 16);
byte[] salt = new byte[16];
fin.Read(salt, 0, 16);
// create the crypting stream
SymmetricAlgorithm sma = CreateAlgo(key, salt);
sma.IV = IV;
long lSize = -1; // the size stored in the input stream
// create the hashing object, so that we can verify the file
HashAlgorithm hasher = SHA256.Create();
// create the cryptostreams that will process the file
using (CryptoStream cin = new CryptoStream(fin, sma.CreateDecryptor(), CryptoStreamMode.Read),
chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write))
{
// read size from file
BinaryReader br = new BinaryReader(cin);
lSize = br.ReadInt64();
ulong tag = br.ReadUInt64();
if (FC_TAG != tag)
throw new EncryptDecryptHelpException("File Corrupted!");
//determine number of reads to process on the file
long numReads = lSize / BUFFER_SIZE;
// determine what is left of the file, after numReads
long slack = (long)lSize % BUFFER_SIZE;
// read the buffer_sized chunks
for (int i = 0; i < numReads; ++i)
{
read = cin.Read(bytes, 0, bytes.Length);
fout.Write(bytes, 0, read);
chash.Write(bytes, 0, read);
}
// now read the slack
if (slack > 0)
{
read = cin.Read(bytes, 0, (int)slack);
fout.Write(bytes, 0, read);
chash.Write(bytes, 0, read);
}
// flush and close the hashing stream
chash.Flush();
chash.Close();
// flush and close the output file
fout.Flush();
fout.Close();
// read the current hash value
byte[] curHash = hasher.Hash;
// get and compare the current and old hash values
byte[] oldHash = new byte[hasher.HashSize / 8];
read = cin.Read(oldHash, 0, oldHash.Length);
}
}
//**************************************
//File.Delete(filename);
}
catch(Exception ex)
{
}
}
|
|
|
|
|
I get this error when i decrypt. I use this algorithm on xml files, this happens when i remove a node from the xml file. Any ideas?
|
|
|
|
|
I am trying to build a cryptography program using HMACSHA256 as the verification technique. I edited the code to use HMACSHA256 instead as well as C++. Upon decryption using the incorrect password, I will encounter this error.
An unhandled exception of type 'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll
Additional information: Padding is invalid and cannot be removed.
Below is my code and the error occurs at this line
while ( (bytesInCurrentBlock = cin->Read(buffer, 0, buffer->Length)) != 0 )
in the DecryptFile function. I would be grateful if someone could point out my mistake here.
PS: I am suppose to be expecting the hmacsha256 mismatch error to throw instead
void CryptoData::EncryptFile(String^ inFile, String^ outFile, String^ password, int keySize,
CryptoProgressCallBack^ callback)
{
FileStream^ fin = gcnew FileStream(inFile, FileMode::Open, FileAccess::Read);
FileStream^ fout = gcnew FileStream(outFile, FileMode::OpenOrCreate, FileAccess::Write);
fout->SetLength(0);
array<Byte>^ buffer = gcnew array<Byte>(BUFFER_SIZE);
int bytesInCurrentBlock;
long long bytesProcessed = 0;
long long fileLength = fin->Length;
long progress;
// generate IV and Salt
array<Byte>^ IV = GenerateRandomBytes(16);
array<Byte>^ salt = GenerateRandomBytes(16);
// create the crypting object
SymmetricAlgorithm^ sma = CreateRijndaelManaged(password, keySize, IV, salt);
// write the IV and salt to the beginning of the file
fout->Write(IV, 0, IV->Length);
fout->Write(salt, 0, salt->Length);
// Initialize the keyed hash object.
HashAlgorithm^ hmacsha256 = gcnew HMACSHA256(sma->Key);
// Compute the hash of the input file.
array<Byte>^ hashValue = hmacsha256->ComputeHash(fin);
// Reset fin to the beginning of the file.
fin->Position = 0;
// Write the computed hash value to the output file.
fout->Write(hashValue, 0, hashValue->Length);
// create the cryptostream
CryptoStream^ cout = gcnew CryptoStream(fout, sma->CreateEncryptor(), CryptoStreamMode::Write);
// read and write the bytes to the crypto stream in BUFFER_SIZE chunks
while ( (bytesInCurrentBlock = fin->Read(buffer, 0, buffer->Length)) != 0 )
{
cout->Write(buffer, 0, bytesInCurrentBlock);
bytesProcessed += bytesInCurrentBlock;
progress = (int)((bytesProcessed / fileLength) * 100);
callback(0, 100, progress);
}
// clear the hashing object
hmacsha256->Clear();
// flush and close the cryptostream
cout->Flush();
cout->Close();
// close the input file
fin->Close();
}
void CryptoData::DecryptFile(String^ inFile, String^ outFile, String^ password, int keySize,
CryptoProgressCallBack^ callback)
{
FileStream^ fin = gcnew FileStream(inFile, FileMode::Open, FileAccess::Read);
FileStream^ fout = gcnew FileStream(outFile, FileMode::OpenOrCreate, FileAccess::Write);
fout->SetLength(0);
array<Byte>^ buffer = gcnew array<Byte>(BUFFER_SIZE);
int bytesInCurrentBlock;
long long bytesProcessed = 0;
long long fileLength = fin->Length;
int progress;
// read the IV and Salt
array<Byte>^ IV = gcnew array<Byte>(16);
fin->Read(IV, 0, 16);
array<Byte>^ salt = gcnew array<Byte>(16);
fin->Read(salt, 0, 16);
// create the crypting object
SymmetricAlgorithm^ sma = CreateRijndaelManaged(password, keySize, IV, salt);
// Initialize the keyed hash object.
HashAlgorithm^ hmacsha256 = gcnew HMACSHA256(sma->Key);
// Create an array to hold the keyed hash value read from the file.
array<Byte>^ storedHash = gcnew array<Byte>(hmacsha256->HashSize / 8);
// Read in the storedHash.
fin->Read(storedHash, 0, storedHash->Length);
bytesProcessed = 64;
// create the cryptostream that will process the file
CryptoStream^ cin = gcnew CryptoStream(fin, sma->CreateDecryptor(), CryptoStreamMode::Read);
// read the BUFFER_SIZE chunks
while ( (bytesInCurrentBlock = cin->Read(buffer, 0, buffer->Length)) != 0 )
{
fout->Write(buffer, 0, bytesInCurrentBlock);
bytesProcessed += bytesInCurrentBlock;
progress = (int)((bytesProcessed / fileLength) * 100);
callback(0, 100, progress);
}
// Reposition the file to compute the hash of the output file.
fout->Position = 0;
array<Byte>^ computedHash = hmacsha256->ComputeHash(fout);
if (!ByteArrayEqual(computedHash, storedHash)) {
throw gcnew CryptoDataException("hmacsha256 mismatch");
}
// flush and close the cryptostream
cin->Flush();
cin->Close();
// close the output file
fout->Close();
}
|
|
|
|
|
Hi
I am getting error while calling the decrypting function in a loop.The error is "Padding is invalid and cannot be removed".
I am getting this exception at this line
if (FC_TAG != tag)
throw new CryptoHelpException("File Corrupted!");
Thanks in Advance
Regards
Chandu.Sanka
|
|
|
|
|
Hello,
I think I need more information on what you are trying to do. The methods that I created do input file to output file all in one step. This for both variants--encrypt and decrypt.
Are you encrypting more than one file in a loop? Are you then trying to decrypt those newly encrypted files?
Can you post a very simple example code that shows your problem?
Thank you,
Nathan
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Hi
Actually while I am using this code,in some cases only I am getting exception at the following code
if (FC_TAG != tag)
throw new CryptoHelpException("File Corrupted!");
I mean the values of FC_TAG and tag are generating different values and this is resulting in throwing an exception.
Almost in all the cases I am getting the value of FC_TAG is 18158797384510146255.
Can you please tell me what might be the problem and how to resolve it.
Thanks in Advance
Chandu.Sanka
|
|
|
|
|
chandu.sanka wrote: Almost in all the cases I am getting the value of FC_TAG is 18158797384510146255.
Actually, I hope the FC_TAG == 18158797384510146255 ALL the time. If not your computer has more problems (like memory corruption or something). FC_TAG is defined in hexadecimal--not decimal. The number you stated is in decimal.
FC_TAG is a constant defined at the top of CryptoHelp class. This constant is used just as a verification that the file is being decrypted right and that this file was encrypted by the EncryptFile method.
If tag is coming back not equal to FC_TAG , then the file that you encrypted has become corrupt. I guess I would need an example file that encrypts and then fails to decrypt so that I could check my code for errors.
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Hi, Nathan Blomquist
Nice Article...
Even I am getting the same error "Invalid Padding..."
When i try to process bunch of files in loop
i.e.
for each(string filename in filenamesStringArray){
EncryptorDecryptor.CryptoHelp.EncryptFile(filename,encryptedfilename , "password",cb);
EncryptorDecryptor.CryptoHelp.DecryptFile(encryptedfilename, decryptedFileName, "password",cb);
}
i face the exception just after 2 or 3 files !
EmersioN
|
|
|
|
|
First to Nathan, MANY thanks for contributing your code to the .Net developer community. You've saved me hours of work.
I am currently working on a project that needs to work with encrypted xml files. For security reasons, I didn't want to write out to a temporary decrypted file, therefore I modified Nathan's Decrypt method to return a string. Here is the result:
public static string DecryptFile(string inFile, string password)
{
StringBuilder sb = new StringBuilder();
// create and open the file streams
using(FileStream fin = File.OpenRead(inFile))
{
long lSize = -1;
int read = -1;
int value = 32;
int outValue = 0;
byte[] bytes = new byte[BUFFER_SIZE];
byte[] IV = new byte[16];
byte[] salt = new byte[16];
fin.Read(IV,0,16);
fin.Read(salt,0,16);
SymmetricAlgorithm sma;
HashAlgorithm hasher = SHA256.Create();
sma = CryptoHelp.CreateRijndael(password,salt);
sma.IV = IV;
using(CryptoStream cin = new CryptoStream(fin,sma.CreateDecryptor(),CryptoStreamMode.Read), chash = new CryptoStream(Stream.Null,hasher,CryptoStreamMode.Write))
{
BinaryReader br;
ulong tag;
br = new BinaryReader(cin);
lSize = br.ReadInt64();
if((tag = br.ReadUInt64()) != FC_TAG)
{
throw new CryptoHelpException("File Corrupted!");
}
ASCIIEncoding enc = new System.Text.ASCIIEncoding();
long numReads = lSize / BUFFER_SIZE;
long slack = (long)lSize % BUFFER_SIZE;
for( int i = 0; i < numReads; ++i )
{
string s;
read = cin.Read( bytes, 0, bytes.Length );
s = enc.GetString( bytes, 0, read );
sb.Append( s );
chash.Write( bytes, 0, read );
value += read;
outValue += read;
}
// now read the slack
if( slack > 0 )
{
string s;
read = cin.Read(bytes,0,(int)slack);
s = enc.GetString( bytes, 0, read );
sb.Append( s );
chash.Write(bytes,0,read);
value += read;
outValue += read;
}
// flush and close the hashing stream
chash.Flush();
chash.Close();
byte[] curHash = hasher.Hash;
byte[] oldHash = new byte[hasher.HashSize / 8];
read = cin.Read(oldHash,0,oldHash.Length);
if((oldHash.Length != read) || (CheckByteArrays(oldHash, curHash)) == false )
{
throw new CryptoHelpException("File Corrupted!");
}
}
// make sure the written and stored size are equal
if(outValue != lSize)
{
throw new CryptoHelpException("File Sizes don't match!");
}
return sb.ToString();
}
}
|
|
|
|
|
Hello!
I tried to path the encrypted file within Socket Connection. The Decryption proccess didn't show any problems, but after creating I couldn't open the decrypted file (that was originally in .jpg format).
What could be a reson?
Eli Kremer
|
|
|
|
|
Eli,
I am not sure I understand what you mean. Did you encrypt the file into another file and then try to send that file across a socket connection? If your socket connection is working for every other type of file you are sending that would be weird. I would need to see code to help.
Later,
Nathan
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Nathan,Thanks for your answer,
Yes, I encrypted file into another, and sent it across the socket connection:
Does the file corrupts when I open it for writing into networkstream on Server side and reading on client side? What is the simple way to avoid this ?
RECEIVING (Client Side):
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
private void GetFile(string FileName, Socket sock )
{
string FileEncryptedName;
NetworkStream nfs = null;
FileStream fout=null;
receiveDone.WaitOne(5000,false);
FileEncryptedName = FileName+".fcfe";
try
{
FileInfo fi = new FileInfo(PathToPlaceFiles+ "/" + FileEncryptedName);
fout = new FileStream(fi.FullName , FileMode.Create, FileAccess.Write) ;
nfs = new NetworkStream(sock) ;
}
catch (Exception ex)
{
this.clientLog.Text += " There may be problems with requested file" ;
}
int i=1; // Number of bytes to get from buffer in each cycle
double duration=0; // transfer speed
int rby=0 ; // Total number of bytes
byte[] buffer;
try
{
do
{
CurrentTime = DateTime.Now;
TimeSpan timeLeft = (CurrentTime-StartTime );
labelDurationDetails.Text = timeLeft.TotalSeconds.ToString("F3") ;
buffer = new byte[1024] ;
//Read from the Network Stream
if(nfs.CanRead)
i = nfs.Read(buffer,0,buffer.Length) ;
if(i>0)
{
fout.Write(buffer,0,i) ;
rby=rby+i ;
if(CurrentTime.Second > 0)
duration = rby/CurrentTime.Second;
duration/=1024;
pBar.PerformStep();
labelRateDetails.Text = duration.ToString("F3");
this.clientLog.Text += "";
}
}while( rby<this.pbar.maximum);
="" }catch(exception="" ed)
="" {
="" messagebox.show("problem="" in="" file="" accept"+ed.message);
="" }
="" try
="" filename+=".fcfd" ;
="" fileinfo="" finput="new" fileinfo(pathtoplacefiles+="" "="" +="" fileencryptedname);
fileinfo="" foutput="new" filename);
=""
cryptoprogresscallback="" cb="new" cryptoprogresscallback(this.progresscallbackdecrypt);
cryptoprogresscallback(this.progresscallbackdecrypt);
cryptohelp.decryptfile(finput.fullname,foutput.fullname,"1",cb);
="" }
catch="" (exception="" ed)
{
="" messagebox.show("error="" decryption"+ed.message);
}
="" sending="" (server="" side)
=""
public="" void="" readcallback(iasyncresult="" ar)=""
{="" i="" perform="" some="" validation="" –="" xml="" “dialog”="" between="" client="" and="" server="" by="" “3-="" way="" handshake”="" that="" the="" needed="" exists="" before="" file
="" stateobject="" state="(StateObject)" ar.asyncstate;
="" socket="" handler="state.workSocket;
" int="" bytesread="handler.EndReceive(ar);
" string="" content="Encoding.Unicode.GetString(state.buffer,0,bytesRead);
" getting="" name="" of="" requested="" if="" (content.indexof("<="">") > -1)
{
//Getting the source file
FileInfo file_info=LocateFile(content,1);
CryptoProgressCallBack cb = new
CryptoProgressCallBack(this.ProgressCallBackEncrypt);
CryptoHelp.EncryptFile(file_info.FullName,file_info.FullName+".fcfe","1",cb);
//Getting the encrypted file
file_info = LocateFile(content,2);
if( FileMessage(content) && file_info!=null )
{
SendFile(file_info,handler);
}
}
private FileInfo LocateFile(string content,int time)
{
//………………………
else if(time==2) {
if(file.Name.Equals(doc.SelectSingleNode("//FileName").InnerText+".fcfe" ))
return file;
}
//………………………….
}
private void SendFile(FileInfo file_info, Socket handler)
{
// Writes file_info into Network Stream
}
Eli
|
|
|
|
|
letoII wrote:
private void GetFile(string FileName, Socket sock )
The do while loop seems to be miss formatted at the bottom. All it says is:
letoII wrote:
}while( rby
It has no closing ')'. But from what I can determine, you don't know when to end the reading from the stream. Maybe if you send the number of bytes down the Socket in a long before actually sending the file, you could then read the long to tell you when you have read the required numbers of bytes.
-Nathan
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Thanks!! It was written:
}while(rby
|
|
|
|
|
letoII wrote:
The fact that I open the file to write in stream while sending and read from while getting, doesn't corrupts the file, isn't it?
If I am understanding correctly, yes, you should be able to read from the file and send the data into the socket with no problem. There should be no reason that you would have to read the entire file into memory first.
Something similiar to this (warning psuedo-code ahead):
FileStream fin = new FileStream("some file");
NetworkStream nout = new NetworkStream("some socket or other type of connection");
int read = -1;
byte[] buffer = new byte[1024];
while((read = fin.read(buffer,buffer.length)>0)
{
nout.write(buffer,read);
}
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Steven,
I want to thank you for your constructive criticisms. But I do have a couple comments/questions.
Steven Campbell wrote:
Do not save the IV together with the key. The IV is random, and it is not necessary to decrypt the data. Saving the IV weakens your encryption slightly.
I am not saving the IV with the key. I am saving the IV and salt. The salt is not the key. I use the salt inconjunction with the password to create the key. Look at the PasswordDeriveBytes class. My question I guess would be--How do you decrypt the data if you do not have the IV and the salt? I am randomly generating both (using the framework's RNGCryptoServiceProvider ) at the beginning of the encryption process. If I don't store them in the beginning of the encrypted file, I will never be able to get them back (never might be strong, but supposedly never). The IV is used as the first block in the chain of CBC mode. If the IV is just randomly generated during Decryption then the first block will be wrong and the decryption will fail.
Steven Campbell wrote:
I liked the use of a tag at the start...
I am now worried about the tag and the file size being imbedded in the file. It could possibly allow for a man in the middle attack. I will give more thought to it and maybe update the article if I figure anything out about it.
The reasoning behind my use of the for...loop was that I have embedded a hash of the file at the end of the Cryptostream . This was the easiest way to read of the file data while still allowing me easy access to the hash data. Maybe you could help with making this "better"?
Thanks again,
Nathan
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
The IV is not necessary to decrypt data, only to encrypt it. See this MSDN example.
I agree on the file size risk -- it would be best to just use the hash value as a check.
Insted of the for...loop I would just read all the data, then treat the last X bytes as the hash. If you do this, you will have to defer the calculation of the hash-check until you have separated the hash from the data.
my blog
|
|
|
|
|
I really must be missing something. This example does say that you need the same key and IV:
key = rc2CSP.Key;
IV = rc2CSP.IV;
ICryptoTransform encryptor =
rc2CSP.CreateEncryptor(key, IV);
ICryptoTransform decryptor =
rc2CSP.CreateDecryptor(key, IV);
I did two tests:
1.
a) Comment out the line sma.IV = IV; of the DecryptFile function.
b) Compile and Run the program
c) Encrypt a file
d) Attempt to decrypt the file.
Result: File Corrupted
2.
a) Uncomment out the line sma.IV = IV; of the DecryptFile function.
b) Compile and Run the program
c) Encrypt a file
d) Attempt to decrypt the file.
Result: Successful decryption
I guess I don't understand where/why you think the IV isn't needed... Are you using CipherMode.ECB ? If you are then, that is why the IV doesn't matter.
Thanks,
Nathan
---------------------------
Hmmm... what's a signature?
|
|
|
|
|
Nope, it's not you that is missing something, it is me! You are totally correct, you do need to keep the IV as well to be able to decrypt the data.
I don't know where I got the idea from, but I was 110% certain that you did not need to save it. Looking back at my own programs, and MSDN, it seems obvious that you need the original IV.
Sorry for misleading you!
my blog
|
|
|
|
|
First of all, great article! Second of all, Steven, you have proved you are a human being, and a man as well. It takes courage and an honest passion to learn to admit when you've made a mistake. I have (and probably will have again) been "110%" right about something, only to find out that I had it wrong. In those times if I would have stepped back and looked at the situation with open eyes, I would have much better off.
Thanks for reminding me the right way to be!
Sincerely,
Keith E. Cooper
kooth@coopermktg.com
|
|
|
|
|