Crypt-FileHandle

 view release on metacpan or  search on metacpan

lib/Crypt/FileHandle.pm  view on Meta::CPAN


	# get parameters
	# acquire reference to provided scalar
	my $buf = \shift;
	my ($len, $off) = @_;

	# check parameters
	if (! defined $buf) {
		carp "Use of uninitialized value";
		return undef;
	}
	if (! defined $len) {
		# return entire buffer
		$len = length($self->{$V_READ_BUFFER});
	}
	if ($len < 0) {
		carp "Negative length";
		return undef;
	}
	if (! defined $off) {
		$off = 0;
	}

	# reference to buffer
	my $rbuf = \$self->{$V_READ_BUFFER};

	# extract requested bytes from buffer and replace with empty string
	# store extracted data in provided scalar at offset position
	# if offset is 0, same as writing over provided scalar
	# should be valid even for 0 byte requests
	# save length of extracted data for increment below
	my $xl;
	if (! defined $$buf) {
		# offset is ignored if provided scalar is not defined
		$$buf = substr($$rbuf, 0, $len, "");
		$xl = length($$buf);
	}
	else {
		$xl = length(substr($$buf, $off) = substr($$rbuf, 0, $len, ""));
	}

	# increment total number of bytes extracted
	# may differ from requested length if _decrypt_read() not called or EOF
	$self->{$V_TOTAL_BYTES} += $xl;

	return $xl;
}

############################################################

1;

__END__

=head1 NAME

Crypt::FileHandle - encrypted FileHandle

=head1 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);

=head1 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.

=head1 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.

=over 4

=item start($string)

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

=item crypt($data)

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

=item finish()

Flushes the internal buffer and returns any remaining data.

=back

=head1 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.

=over 4

=item F<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.

=item F<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.

=item F<readsize()>

=item F<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

lib/Crypt/FileHandle.pm  view on Meta::CPAN


=item F<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.

=item F<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.

=item F<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.

=item F<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.

=item F<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.

=back

=head1 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.

=over 4

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

=back

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.

=over 4

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.

=back

=head1 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.

=head1 SEE ALSO

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

=head1 AUTHOR

Christopher J. Dunkle

=head1 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.

=cut



( run in 0.861 second using v1.01-cache-2.11-cpan-e1769b4cff6 )