Encrypt process:
1) 8 bytes random IV ( Initialization Vector ).
Insert the 8 bytes random IV to the beginning of the data stream.
2) Key length with 16 bytes ( digest using MD5 ).
3) padding method compatible with RFC 2898.
4) Encrypt the file.
Decrypt process:
1) Read the first 8 bytes block and ignore it.
2) Digest the key using MD5.
3) Use the same padding method used when encrypting the file.
4) Decrypt the file.
To encrypt the file here is my code
void encryptFile(const char* password, const char* inputFileName,
const
char* outputFileName)
{
byte pass[ AES::BLOCKSIZE ]; // digest of password
byte iv[ 8 ]; // Initial Vector (IV)
AutoSeededRandomPool rng; // random number generator
try
{
// digest password
StringSource( password, true,new HashFilter(*(new MD5), new
ArraySink(pass, AES::BLOCKSIZE)) );
// random Initial Vector
rng.GenerateBlock(iv, 8);
// create object for encrypting
AES::Encryption aesEncryption(pass,
CryptoPP::AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption,
iv);
StreamTransformationFilter *encryptor;
encryptor = new StreamTransformationFilter(cbcEncryption, new
FileSink(outputFileName) );
encryptor->Put(iv, 8);
// "bind" a file and encrypt one
FileSource(inputFileName, true, encryptor);
}
catch(CryptoPP::Exception &e)
{
return;
}
}
void decryptFile(const char* password, const char*inputFileName,const
char*outputFileName)
{
//help me to write the decrypt functionality
}
How do I decrypt the file? I'm unable to read the first 8 bytes block
and ignore it.
Please help me to write the decrypt function satisfying the above
specifications.
Thanks in advance
memset(iv, 0, 8);
try
{
FileSource source(inputFileName, false);
StringSource( password, true,new HashFilter(*(new MD5), new
ArraySink(pass, AES::BLOCKSIZE)) );
CryptoPP::AES::Decryption aesDecryption(pass,
CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption
cbcDecryption( aesDecryption, iv );
// get and encrypt first block
source.Pump(8);
source.Get(head_file, 8);
// "bind" decryptor to output file
source.Attach( new StreamTransformationFilter(cbcDecryption,
new FileSink((outputFileName) ) ));
// push the rest data
source.PumpAll();
}
catch(CryptoPP::Exception &e)
{
return ;
Here is what I did. help me to fix this problem
void encryptFile(const char* password, const char* inputFileName,
const char* outputFileName)
{
byte pass[ AES::BLOCKSIZE ]; // digest of password
byte iv[ 8 ]; // Initial Vector (IV)
AutoSeededRandomPool rng;
// digest password
StringSource( password, true, new HashFilter(*(new SHA256), new
ArraySink(pass, AES::BLOCKSIZE)) );
// random Initial Vector
rng.GenerateBlock(iv, 8);
// create object for encrypting
AES::Encryption aesEncryption(pass,
CryptoPP::AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption,
iv);
StreamTransformationFilter *encryptor;
encryptor = new StreamTransformationFilter(cbcEncryption, new
FileSink(outputFileName) );
encryptor->Put(iv, 8);
// "bind" a file and encrypt one
FileSource(inputFileName, true, encryptor);
}
void decryptFile(const char* password, const char*inputFileName,const
char* outputFileName)
{
byte pass[ AES::BLOCKSIZE ];
byte iv[ 8 ];
byte head_file[ 8 ];
memset(iv, 0, 8 );
try
{
StringSource( password, true, new HashFilter(*(new SHA256), new
ArraySink(pass,AES::BLOCKSIZE)) );
CryptoPP::AES::Decryption aesDecryption(pass,
CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption
cbcDecryption( aesDecryption, iv );
StreamTransformationFilter *decryptor;
decryptor = new
StreamTransformationFilter(cbcDecryption, new
FileSink(outputFileName) );
decryptor->Get( head_file, 8 );
FileSource(inputFileName, true, decryptor);
}
catch(CryptoPP::Exception &e)
{
return;
Ok here is what I have been trying, Now the problem is I'm unable to
retrieve the first 5 bytes.
If the input is
"The library is an powerful and elegant tool for performing complex
cryptography"
I get the output as
"}ýŸ1/4 tÛ=rary is an powerful and elegant tool for performing complex
cryptography"
Here is what I did. help me to fix this problem
void encryptFile(const char* password, const char* inputFileName,
const char* outputFileName)
{
byte pass[ AES::BLOCKSIZE ]; // digest of password
byte iv[ 8 ]; // Initial Vector (IV)
AutoSeededRandomPool rng;
// digest password
StringSource( password, true, new HashFilter(*(new SHA256), new
ArraySink(pass, AES::BLOCKSIZE)) );
// random Initial Vector
rng.GenerateBlock(iv, 8);
// create object for encrypting
AES::Encryption aesEncryption(pass,
CryptoPP::AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption,
iv);
StreamTransformationFilter *encryptor;
encryptor = new StreamTransformationFilter(cbcEncryption, new
FileSink(outputFileName) );
encryptor->Put(iv, 8);
// "bind" a file and encrypt one
FileSource(inputFileName, true, encryptor);
}
void decryptFile(const char* password, const char*inputFileName,const
char* outputFileName)
{
byte pass[ AES::BLOCKSIZE ];
byte iv[ 8 ];
byte head_file[ 8 ];
memset(iv, 0, 8 );
try
{
StringSource( password, true, new HashFilter(*(new SHA256), new
ArraySink(pass,AES::BLOCKSIZE)) );
CryptoPP::AES::Decryption aesDecryption(pass,
CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption
cbcDecryption( aesDecryption, iv );
StreamTransformationFilter *decryptor;
decryptor = new
StreamTransformationFilter(cbcDecryption, new
FileSink(outputFileName) );
decryptor->Get( head_file, 8 );
FileSource(inputFileName, true, decryptor);
}
catch(CryptoPP::Exception &e)
{
return;
}
}
On Sep 2, 10:44 am, Rash <raj143p...@gmail.com> wrote:
If I recall correctly, the IV should be the same size as the block
size. This is because once a block is encrypted at stage i, it is fed
into stage i+1. For the first pass (stage 0), there is no stage -1. So
an IV is required.
Perhaps refreshing the topic with Schneier's Applied Cryptography or
Menenze (et al) Handbook of Applied Cryptography will be of assistance
to you.
As for stepping over your IV in the data stream, take a look at sample
4 in this example. It steps over salt housed in a std::string.
http://www.codeproject.com/cpp/AESProductKey.asp
Jeff
I am reading this to get some hints about how to use crypto++ to en/
decrypt files. I am a bit confused by Mouse's answer though. I have
two questions here:
+ Why did he choose 16-byte zeros as the initial vector for CBC mode?
Apparently my guess is wrong and it seems the first 16-byte random
prefix of the file is used as the real initial vector. If the file
prefix guess is true then how can the decryptFile function decrypt the
first 16-byte without knowning the IV.
+ how does the function call cbcDecryption.ProcessData((byte
*)garbage, (const byte *)iv_garbage, 16); make the decryptor state
adjust to IV, and file position pointer advance to the past-IV spot.
Thanks
Because for the sake of correctness, one should set IV to something. And
since you did not provide the means to transfer the "real" IV to the
decryptor - I chose to set it explicitly to something simple such as all
zeroes. It is cryptographically OK because the plaintext is prefixed with
random 16 bytes (that serve cryptographically as IV - though they are *not*
IV).
> Apparently my guess is wrong and it seems the first 16-byte
> random prefix of the file is used as the real initial vector.
No, don't mix IV (that is explicitly fed to the crypto engine) with prefix
(that is prepended to the data). End result is similar - but the processing
is very different.
> If the file prefix guess is true then how can the decryptFile
> function decrypt the first 16-byte without knowning the IV.
The first 16 bytes of the file decrypt into garbage because decryptor
doesn't have the correct IV - but since your random prefix carries no
information anyway, the only symptom of your error is that your decrypted
text is prepended with 16 garbage bytes.
> + how does the function call cbcDecryption.ProcessData((byte
> *)garbage, (const byte *)iv_garbage, 16); make the decryptor state
> adjust to IV, and file position pointer advance to the past-IV spot.
I leave this as a home exercise.
The process takes this way:
+ The IV(16-byte zeros) XOR the first 16-byte of plaintext (which is a
random number);
+ Use the key to encrypt the result then we get the first block of
ciphertext
+ Feed this block as an input (we can see this block as an IV to the
next round encryption) XOR the next block of plaintext
+ The real plain text encryption takes place from here...
+ Take the encryption code for example. You allocate memory for
'encryptor' but I never see you delete them in your code. I ran the
code in a debug mode and found out after the FileSource is called the
memory of 'encryptor' object is freed magically. Is this a smart
pointer design in CryptoPP?
+ Does CryptoPP AES implementation support 32-byte block size? Seems
not.
+ As you know, we need to consider the padding when using CBC mode so
that we can process data in multiple of block size. According to
CryptoPP's FAQ:
"Alternatively, you can wrap StreamTransformationFilter around the
mode object and use it as a Filter object. StreamTransformationFilter
will take care of buffering data into blocks for you when needed.
std::string ciphertext;
StreamTransformationFilter cfbEncryptor(cfbEncryption, new
StringSink(ciphertext));
cfbEncryptor.Put(plaintext, 100);
// input more plaintext here if needed
cfbEncryptor.MessageEnd(); "
Your decryption code throws an exception saying the data is not a
multiple of block size. Is this because padding should be added in the
encryption code and how?
I can't get help from the sample code because it uses MessageEnd() at
the end of the encryption. I can't use encryptor->MessageEnd() in your
code because the encryptor object is destroyed after the
FileSource(...).
Many thanks
+ why cfbEncryptor.MessageEnd(); is still called in the FAQ sample
code.
+ If StreamTransformationFilter takes care of the padding, why the
data is not a multiple of block size is thrown in the decryption code.
There is a slight change in my test. I use MAX_KEYLENGTH. So here's
the scenario:
Key size 256 Block size 128 IV size 128
Thanks
> + why cfbEncryptor.MessageEnd(); is still called in the
> FAQ sample code.
How is the filter suppose to know when the stream ends? The filter's
job is buffering - it accumulates and then pushes 'blocksize' chunks
to the encryption object.
Jeff
Sure.
> Take the encryption code for example. You allocate memory
> for 'encryptor' but I never see you delete them in your code.
In the example I gave I did not bother deleting the encryptor object,
letting the memory be reclaimed after the program completes.
> I ran the code in a debug mode and found out after the FileSource
> is called the memory of 'encryptor' object is freed magically.
That I cannot explain as I don't know.
> Is this a smart pointer design in CryptoPP?
Wei Dai would be the best one to answer this question. I don't know if
Crypto++ does or does not use Smart Pointers.
> Does CryptoPP AES implementation support 32-byte block size?
> Seems not.
Since 32-byte-block AES does not exist, the answer is obvious. Rijndael
design did support 32-byte blocks, but standardized AES does not.
> As you know, we need to consider the padding when using CBC
> mode so that we can process data in multiple of block size.
Which is why it usually makes sense to wrap the encryptor in the
StreamTransformationFilter().
std::string ciphertext;
StreamTransformationFilter cfbEncryptor(cfbEncryption, new
StringSink(ciphertext));
cfbEncryptor.Put(plaintext, 100);
// input more plaintext here if needed
cfbEncryptor.MessageEnd(); "
> Your decryption code throws an exception saying the data
> is not a multiple of block size. Is this because padding
> should be added in the encryption code and how?
Sorry, but *my* decryptor did not throw any exceptions - I've tested it
before posting. I don't know the code that *you* wrapped around the
decryptor, so cannot comment.
> I can't get help from the sample code because it uses MessageEnd()
> at the end of the encryption.
Oh so you removed the MessageEnd() at the end of the encryption, so there's
nothing to tell the encryptor "Now there's no more input - therefore pad
whatever data is sitting in the buffer, encrypt it and push it out". And now
you're surprised that your code does not work?
> I can't use encryptor->MessageEnd() in your code because the
> encryptor object is destroyed after the FileSource(...).
That object should NOT just get destroyed all by itself. Something in your
code must be doing something wrong with it. Again, take a look at the
example I posted earlier - it has been tested and works properly.
> Sorry, but *my* decryptor did not throw any exceptions - I've tested it
> before posting. I don't know the code that *you* wrapped around the
> decryptor, so cannot comment.
I thought that too. I then ran the test using your sample code, rash-
enc.cc without any changes. It works but after I added the more
characters in the plain text file (say up to 2KB). The test ended up
with the exception, the ciphertext is not a multiple of block size
again.
> Oh so you removed the MessageEnd() at the end of the encryption, so there's
> nothing to tell the encryptor "Now there's no more input - therefore pad
> whatever data is sitting in the buffer, encrypt it and push it out". And now
> you're surprised that your code does not work?
Not in the sample code from FAQ. I actually wondered why your code
didn't call MessageEnd() (after the FileSource(...)) until I read
about this in Crypto++ UserGuide:
"PumpAll(). Pumps all messages just like PumpMessages() would if
called with no argument, and then pumps the following uncomplete
message until there is no more data to extract. With FileSource and
StringSource, PumpAll() extracts data like Pump() and then calls
MessageEnd()."
> In the example I gave I did not bother deleting the encryptor object,
> letting the memory be reclaimed after the program completes.
Yeah. I just wondered without using the 'delete' operator how the
object is destroyed and memory is freed. And this seems to be the
answer
>From the readme file:
"1. If a constructor for A takes a pointer to an object B (except
primitive
types such as int and char), then A owns B and will delete B at A's
destruction. If a constructor for A takes a reference to an object B,
then the caller retains ownership of B and should not destroy it until
A no longer needs it."
Symptom: An exception, the cipher text is not a multiple of block size
is thrown when decrypting data.
Fix: Open the encrypted file in binary mode
...
ifstream inf;
inf.open(inputFileName, ifstream::binary); //open the encrypted
file in binary mode
inf.read(iv_garbage, 16); // absorb
random prefix
...
_PINUX_
Mouse-2 wrote:
>
>
>
>
> #include <iostream>
>
> #include <cryptopp/aes.h>
> #include <cryptopp/modes.h>
> #include <cryptopp/sha.h>
> #include <cryptopp/osrng.h>
> #include <cryptopp/files.h>
> #include <cryptopp/filters.h>
>
> USING_NAMESPACE(CryptoPP);
> USING_NAMESPACE(std);
>
> /**************************************************************/
> /* Code to illustrate usage of cryptographic primitives */
> /* provided by Crypto++ library v5.5.1 of Wei Dai. */
> /* */
> /* In particular, the program provides two functions: */
> /* */
> /* 1. Encrypt a file (key based on password) with random IV;*/
> /* */
> /* 2. Decrypt previously encrypted file. */
> /* */
> /* Issue with the original code: */
> /* - set IV in the encryptor but also used it as random */
> /* prefix, so garbage was the 1st encrypted block; */
> /* - did not "fast-forward" the encrypted file past the */
> /* first block (which was encrypted random garbage). */
> /* */
> /* Corrections performed: */
> /* - fixed encryptor by leaving random block prefixed, */
> /* but removing redundancy (having it in encryptor); */
> /* - fixed decryptor (see the source code). */
> /* */
> /*==========================================================*/
> /* Written by: */
> /* Rash <raj14...@gmail.com> */
> /* */
> /* Modified by: */
> /* Mouse <urim...@optonline.net> */
> /* Sun Sep 2, 12:25:00 2007 */
> /* */
> /************************************************************/
> /* */
> /* Copyright (C) 2007 Rash <raj14...@gmail.com> */
> /* Copyright (C) 2007 Mouse <urim...@optonline.net> */
> /* */
> /************************************************************/
>
> void encryptFile(const char* password, const char* inputFileName,
> const char* outputFileName)
> {
> byte pass[AES::BLOCKSIZE]; // digest of password
> byte iv[16]; // Initial Vector (IV), misused
> // by original author
> byte true_iv[16]; // real IV used - set to zero
>
> AutoSeededRandomPool rng;
>
> // digest password
> StringSource(password, true,
> new HashFilter(*(new SHA256),
> new ArraySink(pass, AES::BLOCKSIZE)));
>
> // random Initial Vector
> rng.GenerateBlock(iv, 16);
> memset(true_iv, 0, 16);
>
> // create object for encrypting
> AES::Encryption aesEncryption(pass,
> CryptoPP::AES::DEFAULT_KEYLENGTH);
> CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption,
> true_iv);
>
> StreamTransformationFilter *encryptor;
> encryptor = new StreamTransformationFilter(cbcEncryption,
> new FileSink(outputFileName) );
>
> encryptor->Put(iv, 16); // this prefixes the file with random block (not
> IV)
> // Cryptographically it is equivalent to IV, so just as
> good
>
> // "bind" a file and encrypt one
> FileSource(inputFileName, true, encryptor);
> }
>
>
> void decryptFile(const char* password, const char*inputFileName,
> const char* outputFileName)
> {
> byte pass[AES::BLOCKSIZE];
> byte iv[16]; // here's 1st problem: AES IV is 16 bytes
> byte head_file[16]; // so must skip 16 bytes, not 8.
>
> memset(iv, 0, 16); // very correct - in fact the encryptor prefixes file
> // with a random block, so no need to pass the IV explicitly.
>
> try {
> StringSource(password, true, new HashFilter(*(new SHA256), new
> ArraySink(pass,AES::BLOCKSIZE)));
>
> CryptoPP::AES::Decryption aesDecryption(pass,
> CryptoPP::AES::DEFAULT_KEYLENGTH);
> CryptoPP::CBC_Mode_ExternalCipher::Decryption
> cbcDecryption(aesDecryption, iv);
>
> StreamTransformationFilter *decryptor;
> decryptor = new
> StreamTransformationFilter(cbcDecryption, new
> FileSink(outputFileName));
>
>
> // decryptor->Get(head_file, 16); // does not do anything useful,
> wrong here
> // We must somehow decrypt 1st block of the input file, without
> sending the
> // result into the output file.
> char garbage[16], iv_garbage[16]; // place for IV stuff
> ifstream inf;
> inf.open(inputFileName); inf.read(iv_garbage, 16); // absorb random
> prefix
>
> // Decrypt random prefix (with zero IV) to some dummy buffer to get
> // (a) decryptor state adjusted to IV, and
> // (b) file position pointer advanced to the past-IV spot.
> cbcDecryption.ProcessData((byte *)garbage, (const byte *)iv_garbage,
> 16);
>
> // NOW can run the decryption engine in "automatic" mode
> FileSource(inf, true, decryptor);
>
> inf.close(); // to be nice
> }
> catch(CryptoPP::Exception &e)
> {
> cerr << "Caught exception during decryption!" << endl;
> return;
> }
> }
>
> int main(int argc, char *argv[])
> {
> const char *pwd = "not-so-complicated parole";
> const char *pfn = "plain.txt";
> const char *cfn = "cipher.dat";
> const char *ofn = "plain2.txt";
>
> // Create test plaintext file "plain.txt"
> ofstream plain;
> plain.open(pfn);
> plain << "An excellent test of file encryption techniques.\n";
> plain << "This test will not demonstrate many tricks though.\n";
> plain.close();
>
> // Invoke encryptor to encrypt into "cipher.dat"
> encryptFile(pwd, pfn, cfn);
>
> // Invoke decryptor to decrypt into "plain2.txt"
> decryptFile(pwd, cfn, ofn);
>
> exit(0);
> }
>
>
your code is working on text but when i used a binary file like an image it
failed
please help
what changes should i make
please reply
thanks in advance
--
View this message in context: http://old.nabble.com/Decrypt-file-using-AES%3A%3ACBC-tp12446523p29674413.html
Sent from the Crypto++ Users mailing list archive at Nabble.com.
We can probably help you on this list, but you'll need to provide more
information than this. The code that was provided ought to work equally
well for text and binary, so let's try to figure out what's wrong with
your example.
In what way does decryption fail?
Does it throw an exception? What exception?
Does it produce a corrupt file? In what way is the file corrupt? (That
is, in what way is it different from the original file?) Does it have
its CR's replaced with CRLF's? Does it have null bytes removed? Is it
the same size or a different size? Does it have random junk at the
beginning or end? Does it fail in the same way every time, or does it
depend on the random "IV" block? Does the output file just have the
wrong extension (.txt) for your OS to open it?
What OS are you running (Windows, right? What version?), and what
version of Crypto++?
Cheers,
Mike