2

I was trying to test file encryption using the chilkat functionality. Based on code found on this example page, I replaced the last part with this:

#  Encrypt a string...
#  The input string is 44 ANSI characters (i.e. 44 bytes), so
#  the output should be 48 bytes (a multiple of 16).
#  Because the output is a hex string, it should
#  be 96 characters long (2 chars per byte).


my $input = "sample.pdf";
# create file handle for the pdf file
open my $fh, '<', $input or die $!;
binmode ($fh);

# the output should be sample.pdf.enc.dec
open my $ffh, '>', "$input.enc.dec" or die $!;
binmode $ffh;

my $encStr;
# read 16 bytes at a time
while (read($fh,my $block,16)) {
    # encrypt the 16 bytes block using encryptStringEnc sub provided by chilkat
    $encStr = $crypt->encryptStringENC($block);
    # Now decrypt:
    # decrypt the encrypted block
    my $decStr = $crypt->decryptStringENC($encStr);
    # print it in the sample.pdf.enc.dec file
    print $ffh $decStr;
}
close $fh;
close $ffh;

Disclaimer: I know the CBC mode is not recommended for file encryption because if one block is lost, the other blocks are lost too. The output file is corrupted and when I look with beyond compare at the two files, there are chunks of the file which match and there are chunks of file which doesn't. What am I doing wrong?

martin clayton
  • 76,436
  • 32
  • 213
  • 198
user30771
  • 109
  • 6
  • We can't be any help without knowing what kind of object `$crypt` is. How is it created? – Dave Cross May 27 '17 at 10:15
  • @DaveCross a quick search shows that it is the - *fck this, let's do it all in one class* - [CkCrypt2](https://www.chilkatsoft.com/refdoc/vcCkCrypt2Doc.html) component. – Maarten Bodewes May 27 '17 at 11:08
  • 2
    @MaartenBodewes: I think you mean to link to the [Perl module](https://www.chilkatsoft.com/refdoc/perlCkCrypt2Ref.html) not the C++ one. But my point was that we shouldn't need to do that search. – Dave Cross May 27 '17 at 14:14
  • @DaveCross The linked resource was not enough? I didn't want to make a too long post by copy pasting 100 lines of code. – user30771 May 27 '17 at 15:56
  • @user30771: Adding something like "`$crypt` is an instance of the chilkat::CkByteData class" along with a link to documenttation for the class, would have been really useful and wouldn't have made your post much longer. – Dave Cross May 27 '17 at 16:35

3 Answers3

3

You're trying to use character string encryption (encryptStringENC(), decryptStringENC()) for what is, at least partly, a binary file.

This worked for me:

my $input = "sample.pdf";
# create file handle for the pdf file
open my $fh, '<', $input or die $!;
binmode $fh;

# the output should be sample.pdf.enc.dec
open my $ffh, '>', "$input.enc.dec" or die $!;
binmode $ffh;

my $inData = chilkat::CkByteData->new;
my $encData = chilkat::CkByteData->new;
my $outData = chilkat::CkByteData->new;

# read 16 bytes at a time
while ( my $len = read( $fh, my $block, 16 ) ) {

    $inData->clear;
    $inData->append2( $block, $len );

    $crypt->EncryptBytes( $inData, $encData );
    $crypt->DecryptBytes( $encData, $outData );

    print $ffh $outData->getData;
}

close $fh;
close $ffh;

You likely better off perusing the Chilkat site further though, there are sample codes for binary data.

martin clayton
  • 76,436
  • 32
  • 213
  • 198
  • 2
    Please don't use indirect object notation (`new chilkat::CkByteData()`). I know it's in the documentation, but that's a sign that the author doesn't know much Perl. Indirect object notation is prone to being misparsed in certain circumstances and it will cause much frustration whilst tracking down the problem. Far better to use the alternative syntax - `chilkat::CkByteData->new()`. – Dave Cross May 27 '17 at 14:17
  • Thanks, the Chilkat Perl reference documentation and examples are in the process of being re-generated and uploaded to use "->new()" – Chilkat Software May 29 '17 at 13:44
0

I'm going to write and post a link to a sample that is much better than the examples posted here. The examples posted here are not quite correct. There are two important Chilkat Crypt2 properties that one needs to be aware of: FirstChunk and LastChunk. By default, both of these properties are true (or the value 1 in Perl). This means that for a given call to encrypt/decrypt, such as EncryptBytes, DecryptBytes, etc. it assumes the entire amount of data was passed. For CBC mode, this is important because the IV is used for the first chunk, and for the last chunk, the output is padded to the block size of the algorithm according to the value of the PaddingScheme property.

One can instead feed the input data to the encryptor chunk-by-chunk by doing the following:

  1. For the 1st chunk, set FirstChunk=1, LastChunk=0.
  2. For middle chunks, set FirstChunk=0, LastChunk=0.
  3. For the final chunk (even if a 0-byte final chunk), set FirstChunk=0, LastChunk=1. This causes a final padded output block to be emitted.

When passing chunks using FirstChunk/LastChunk, one doesn't need to worry about passing chunks matching the block size of the algorithm. If a partial block is passed in, or if the bytes are not an exact multiple of the block size (16 bytes for AES), then Chilkat will buffer the input and the partial block will be added to the data passed in the next chunk. For example:

  1. FirstChunk=1, LastChunk=0, pass in 23 bytes, output is 16 bytes, 7 bytes buffered.
  2. FirstChunk=0, LastChunk=0, pass in 23 bytes, output is 16 bytes, (46-32 bytes) 14 bytes buffered
  3. FirstChunk=0, LastChunk=1, pass in 5 bytes, output is 32 bytes, (14 buffered bytes + 5 more = 19 bytes. The 19 bytes is one full block (16 bytes) plus 3 bytes remainder, which is padded to 16, and thus the output is 32 bytes and the CBC stream is ended.
Chilkat Software
  • 1,405
  • 1
  • 9
  • 8
0

This example demonstrates using FirstChunk/LastChunk. Here's the example: https://www.example-code.com/perl/encrypt_file_chunks_cbc.asp

Chilkat Software
  • 1,405
  • 1
  • 9
  • 8