The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Crypt::FileHandle - encrypted FileHandle

SYNOPSIS

  use Crypt::CBC;
  use Crypt::FileHandle;

  # example cipher
  $cipher = Crypt::CBC->new(
        -cipher => 'Cipher::AES',
        -key    => $key,
        -header => 'salt'
  );

  # create tied FileHandle
  $fh = Crypt::FileHandle->new($cipher);

  ### treat $fh same as any FileHandle

  # write file
  open($fh, '>', $filename) || die $!;
  print $fh "This is a test string\n";
  close($fh);

  # read file
  open($fh, '<', $filename) || die $!;
  while(<$fh>) {
        print $_;
  }
  close($fh);

DESCRIPTION

This package creates a tied FileHandle that automatically encrypts or decrypts data using the provided cipher. The FileHandle returned from new() can be treated like a normal FileHandle. All encrypting, decrypting, and buffering is completely transparent to the caller.

CIPHER METHODS

This package generally supports ciphers compliant with Crypt::CBC, including CryptX ciphers. The cipher provided to new() must support at least the methods listed below, but no other methods are utilized by this package. Refer to Crypt::CBC for more information on these methods. Even though it is not recommended, a custom home-made cipher object can be used if it supports these methods.

start($string)

Initializes the encryption or decryption process according to the provided string, either 'encrypting' or 'decrypting'.

crypt($data)

Encrypts or decrypts the provided data and returns the resulting data.

finish()

Flushes the internal buffer and returns any remaining data.

GLOBAL METHODS

This package supports the following global methods. These methods cannot be called on the tied FileHandle returned from new() and should only be called via the package name.

new($cipher)

Returns a new FileHandle object that is "tied" with the provided cipher object. It utilizes TIEHANDLE to tie a FileHandle object with a real FileHandle object underneath. The returned FileHandle can be treated like a normal FileHandle, but all writes and reads will occur on the real FileHandle which will be encrypted or decrypted automatically using the methods of the cipher object.

The cipher object provided to new() should NOT be used in any other capacity, otherwise it may disrupt encryption and decryption operations.

verify_cipher($cipher)

Returns true or false if the provided cipher is supported by confirming that the necessary methods exist. This method is automatically called by new() to confirm the provided cipher is valid.

readsize()
readsize($readsize)

Returns the global READSIZE. When a file is open for reading, data is read from the real FileHandle in blocks of READSIZE bytes. Any decrypted data that is not returned by any of the read methods is automatically stored in an internal buffer to be utilized during future read calls.

The global READSIZE can be changed by providing an optional parameter. However, this is a global value and will affect all instances of Crypt::FileHandle. Beware of setting the READSIZE too small, which may prevent reading the entire encrypted file header during the first read call, causing the decryption to fail. The default READSIZE is 4096 bytes.

TIED METHODS

The following methods have been implemented for the tied FileHandle returned by new(). These methods are automatically called through the tied FileHandle and should not be called directly.

OPEN()

Called when open() is called on the tied FileHandle returned from new(). Opens the real FileHandle using the given parameters, and automatically calls start() on the provided cipher with 'encrypting' or 'decrypting' based on whether the real FileHandle was opened for writing or reading. If the mode is not explicitly provided, it assumes the file was open for reading. Note that sysopen() is not supported with a tied FileHandle.

BINMODE()

Called when binmode() is called on the tied FileHandle returned from new(). Calls binmode() with the provided parameters on the real FileHandle. Note that it should not be necessary to use this method because binmode() is automatically called on the real FileHandle when open() is called. This is to ensure portability on all systems since encrypted files will almost certainly contain binary data.

PRINT()
PRINTF()
WRITE()

Called when print(), printf(), or syswrite() is called on the tied FileHandle returned from new(). Each method will encrypt the data and write it to the real FileHandle based on the provided cipher. Note that syswrite() is always utilized to write to the real FileHandle regardless of the method called.

The number of encrypted bytes written to the real FileHandle may not be the same as the number of cleartext bytes processed, especially if a full block of data has not yet been provided. WRITE() will return the number of cleartext bytes processed, which keeps the encryption transparent to the caller.

READLINE()
READ()
GETC()

Called when readline() (or <>), sysread(), or getc() is called on the tied FileHandle returned from new(). Each method will read data from the real FileHandle and decrypt it based on the provided cipher. Note that sysread() is always utilized to read from the real FileHandle regardless of the method called. Data is always read in blocks of READSIZE bytes. Any data that is read and decrypted but not returned is stored in an internal buffer to be utilized by future read calls.

READ() will return the number of cleartext bytes processed and not the actual number of bytes read from the real FileHandle, which keeps the decryption transparent to the caller.

TELL()

Called when tell() is called on the tied FileHandle returned from new(). Returns the number of cleartext bytes processed through the tied FileHandle. It does not return the position of the real FileHandle, which may differ because of the encryption. The logical position of the data is returned as if a normal FileHandle was used, which keeps the encryption and decryption transparent to the caller.

CLOSE()

Called when close() is called on the tied FileHandle returned from new(). It closes the real FileHandle. If the real FileHandle was opened for writing, it calls finish() on the cipher object to complete the encryption prior to closing the real FileHandle.

FILENO()

Called when fileno() is called on the tied FileHandle returned from new(). Returns the file number of the real FileHandle. Note that this method is also utilized when opened() is called on the tied FileHandle. The file number of the real FileHandle is returned to ensure a call to opened() accurately returns whether or not the file is actually open or not.

EOF()

Called when eof() is called on the tied FileHandle returned from new(). Returns true if the read calls have reached an end of file state or if the real FileHandle is closed. Note that the real FileHandle may have reached end of file when reading, but data may still exist in the internal buffer, and thus false is returned since the logical end of file has not yet been reached.

WARNINGS

The sysopen() method is not supported with a tied FileHandle.

The syswrite() and sysread() methods are always used to write to and read from real handles. This package cannot be used with handles that do not support these methods, such as opening directly to a Perl scalar.

If the salt or randomiv header options are not used in the Crypt::CBC cipher provided to new(), it is the caller's responsibility to initialize the decryption cipher appropriately to include any necessary salt or iv values. Otherwise using the same cipher to both encrypt and decrypt will be unsuccessful since the salt or iv values are not included in the encrypted file. When the salt header option is used, the necessary values are included in the resulting encrypted file, and can also be decrypted with OpenSSL as shown in the example below.

    openssl enc -d -aes-256-cbc -in <file> -k <key>

Due to cipher block chaining (CBC), random access is currently not permitted with this package. It would likely be necessary to read or write the entire contents of the file, or large portions of it, to enable random access. For this reason, the following restrictions exist.

    SEEK() is not implemented.

    Files must only be opened for read OR write access. Files cannot be open for both read AND write access.

    Files cannot be appended when writing.

UNTIE and DESTROY

When new() is called, a FileHandle object is created and tie() is automatically called on this object before it is returned. This is the tied FileHandle which is described above. All file reads and writes are performed on the real FileHandle object that is stored and referenced interally in the Crypt::FileHandle object that the FileHandle is tied to.

There is no automatic call to untie() because the tied FileHandle returned from new() is not accessible from within any of the other methods that are called. The tied FileHandle can only be accessed internally if a reference to itself is stored in the Crypt::FileHandle object created by TIEHANDLE(). Unfortunately, this would be a second hidden reference to the same object, preventing the tied object from being destroyed until the program exits. This behavior is avoided by not storing a second internal reference, excluding the ability to automatically call untie().

Since it is not automatically called anywhere, the caller can call untie() on the tied FileHandle if desired, but this will not destroy the underlying tied Crypt::FileHandle object. The tied FileHandle returned from new() can be reused like any other FileHandle after it has been closed, or properly destroyed by setting the reference to undef like any other reference. This will properly destroy the tied FileHandle and the Crypt::FileHandle object since there will no longer be any references to either.

SEE ALSO

FileHandle(3), Crypt::CBC(3), CryptX(3), OpenSSL(1)

AUTHOR

Christopher J. Dunkle

COPYRIGHT AND LICENSE

Copyright (C) 2004,2016,2018 by Christopher J. Dunkle

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.6.0 or, at your option, any later version of Perl 5 you may have available.