Filter::Crypto::CryptFile - Encrypt (and decrypt) Perl files
use Filter::Crypto::CryptFile qw(:DEFAULT $ErrStr); # Encrypt one filehandle (or file name) to another. crypt_file($in_fh, $out_fh, $crypt_mode) or die "crypt_file() failed: $ErrStr\n"; crypt_file($in_file, $out_file, $crypt_mode) or die "crypt_file() failed: $ErrStr\n"; # The crypt mode can be determined automatically. crypt_file($in_fh, $out_fh) or die "crypt_file() failed: $ErrStr\n"; crypt_file($in_file, $out_file) or die "crypt_file() failed: $ErrStr\n"; # Encrypt one filehandle (or file name) in-place (in memory). crypt_file($in_out_fh, $crypt_mode) or die "crypt_file() failed: $ErrStr\n"; crypt_file($in_out_file, $crypt_mode) or die "crypt_file() failed: $ErrStr\n"; # The crypt mode can be determined automatically. crypt_file($in_out_fh) or die "crypt_file() failed: $ErrStr\n"; crypt_file($in_out_file) or die "crypt_file() failed: $ErrStr\n";
This module provides a single function called crypt_file() for converting files to/from an encrypted state in which they can be run via Filter::Crypto::Decrypt.
crypt_file()
The function takes either a pair of open filehandles (one to read from and one to write to) or else a single open filehandle (to process "in-place"). (File names can also be specified instead of open filehandles.) It reads data from the input source, either encrypts it or decrypts it according to the "crypt mode", and then writes the result to the output source.
In each case, the "crypt mode" may either be explicitly specified using the CRYPT_MODE_* flags, or else it can be omitted (or specified as undef or the null string) in order to be determined automatically by crypt_file().
CRYPT_MODE_*
undef
crypt_file($in_fh, $out_fh[, $crypt_mode])
crypt_file($in_out_fh[, $crypt_mode])
If two open filehandles, $in_fh and $out_fh, are supplied then input is read from $in_fh, encrypted or decrypted, and the output is written to $out_fh. Clearly $in_fh must have been opened for reading and $out_fh must have been opened for writing. Only a small amount of data is held in memory at any time, so this method is safe to use for "large" files without using unduly large amounts of memory.
If only one open filehandle, $in_out_fh, is supplied then input is read from it, encrypted or decrypted, and the output is written back to it after truncating the file to zero size. In this case, $in_out_fh must have been opened for "updating" (both reading and writing). Using this method the whole file is read into memory in one go, so it is not suitable for use on "large" files. This is unlikely to be a problem in practice, however, since Perl source code files are rarely, if ever, sufficiently large to cause any trouble in this regard.
Note that the filehandle being written to when encrypting and the filehandle being read from when decrypting must be opened in "binary" mode on those platforms where it makes a difference (notably Win32), otherwise the encrypted "binary" data being written or read may become corrupted by CR-LF translations. It will also be necessary to open the other filehandle (which the Perl source code itself is being read from or written to) in "binary" mode too if the Perl source code happens to contain any "binary" data, e.g. in a __DATA__ section.
__DATA__
File names may be supplied instead of open filehandles, in which case they will be opened appropriately by crypt_file() itself and closed again after use. (crypt_file() always opens the filehandles in "binary" mode so any "binary" data in the Perl source code will be correctly handled.)
The optional $crypt_mode argument specifies whether to perform encryption or decryption. If it is omitted or specified as undef or the null string then the crypt mode will be determined automatically by reading the beginning of the input data. If the beginning is
use Filter::Crypto::Decrypt;
then the data is presumed to be in an encrypted state already so the mode will be set to CRYPT_MODE_DECRYPT; otherwise the mode will be set to CRYPT_MODE_ENCRYPT.
CRYPT_MODE_DECRYPT
CRYPT_MODE_ENCRYPT
On success, returns the number of bytes written (which could be zero if the input was already in the requested state, in which case the special "zero but true" value will be returned); on failure returns the undefined value (in scalar context) or the empty list (in list context) and sets $ErrStr.
The $crypt_mode argument in crypt_file() specifies whether to encrypt or decrypt the input data, as follows:
CRYPT_MODE_AUTO
Have the crypt mode determined automatically by the same means as described under crypt_file() in the case where the $crypt_mode argument is omitted or specified as undef or the null string.
Encrypt the input data and prepend the statement
to the output data so that it can be run via Filter::Crypto::Decrypt. Produces a warning if the input data already has that statement at the beginning.
Decrypt the input data after first removing the statement
from the beginning. Produces a warning if the input data does not have that statement at the beginning.
CRYPT_MODE_ENCRYPTED
The same as CRYPT_MODE_ENCRYPT except that the encryption is not performed if the input data already begins with the statement
Thus, unencrypted data will be encrypted, while encrypted data will not be encrypted a second time.
CRYPT_MODE_DECRYPTED
The same as CRYPT_MODE_DECRYPT except that the decryption is not attempted if the input data does not begin with the statement
Thus, encrypted data will be decrypted, while unencrypted data will not be decrypted a second time.
Last error message.
If the crypt_file() function fails then a description of the last error will be set in this variable for use in reporting the cause of the failure, much like the use of the Perl Special Variables $! and $^E after failed system calls and OS API calls. See "Error Values" for a listing of the possible values of $ErrStr.
$!
$^E
If the function succeeds then this variable will generally be set to the null string. The only exceptions to this are when the crypt mode was specified as either CRYPT_MODE_ENCRYPTED or CRYPT_MODE_DECRYPTED and the input data was found to be already encrypted or decrypted respectively so that no action was required: in these cases a message to this effect will be set in $ErrStr.
This module may produce the following diagnostic messages. They are classified as follows (a la perldiag):
(W) A warning (optional). (F) A fatal error (trappable). (I) An internal error that you should never see (trappable).
(W) The specified file opened by crypt_file() for reading data from and writing data to when updating a file "in-place" could not be closed after use. The system error message corresponding to the standard C library errno variable is also given.
errno
(W) The specified input file opened by crypt_file() for reading data from could not be closed after use. The system error message corresponding to the standard C library errno variable is also given.
(W) The specified output file opened by crypt_file() for writing data to could not be closed after use. The system error message corresponding to the standard C library errno variable is also given.
(W) The exclusive lock acquired by crypt_file() on the filehandle used for reading data from and writing data to when updating a file "in-place" could not be released after use. The system error message corresponding to the standard library errno variable is also given.
(W) The shared lock acquired by crypt_file() on the input filehandle used for reading data from could not be released after use. The system error message corresponding to the standard C library errno variable is also given.
(W) The exclusive lock acquired by crypt_file() on the output filehandle used for writing data to could not be released after use. The system error message corresponding to the standard C library errno variable is also given.
(F) The attempt by crypt_file() to truncate the file to zero size before writing the data to it when updating a file "in-place" failed because the chsize() and ftruncate() functions are not implemented on this system.
chsize()
ftruncate()
(W) The crypt mode was specified as CRYPT_MODE_ENCRYPT but data read from the input filehandle already begins with the statement
Perhaps you are attempting to encrypt data when you meant to be decrypting it?
(W) The crypt mode was specified as CRYPT_MODE_DECRYPT but data read from the input filehandle did not begin with the statement
Perhaps you are attempting to decrypt data when you meant to be encrypting it?
(F) The first parameter for crypt_file() must be either a valid (open) filehandle or a file name, but the argument passed was neither of these things.
(F) The third parameter for crypt_file() must be either undef or the null string (meaning determine the crypt mode automatically), or a valid crypt mode (i.e. one of the CRYPT_MODE_* flags), but the argument passed was neither of these things.
(F) The second parameter for crypt_file() must be one of: undef or the null string (meaning determine the crypt mode automatically), a valid crypt mode (i.e. one of the CRYPT_MODE_* flags), or a valid (open) filehandle or a file name, but the argument passed was none of these things.
(F) You attempted to lookup the value of the specified constant in the Filter::Crypto::CryptFile module, but that constant is unknown to this module.
(F) This module's bootstrap function was called on the specified package, which does not exist.
(W) libcrypto's random number generator failed to generate cryptographically strong pseudo-random bytes for use as the initialization vector (IV) in the encryption. A weaker sequence of pseudo-random bytes was used instead, which is not necessarily unpredictable and may not be suitable for this purpose.
(W) libcrypto's random number generator failed to generate cryptographically strong pseudo-random bytes for use as the salt when performing the key derivation before encryption. A weaker sequence of pseudo-random bytes was used instead, which is not necessarily unpredictable and may not be suitable for this purpose.
(I) There was an unexpected error looking up the value of a constant: the constant-lookup function itself is apparently not defined.
(I) There was an unexpected error looking up the value of the specified constant: the C component of the constant-lookup function returned an unknown type.
(I) The XSUB called internally by crypt_file() was passed a crypt mode that it does not recognize or failed to derive correctly a crypt mode for setting in the crypto context structure to be used when performing the encryption or decryption.
(I) The crypto context structure used internally when performing encryption or decryption has been set-up with a crypt mode that it does not recognize.
(I) You attempted to lookup the value of the specified constant in the Filter::Crypto::CryptFile module, but that constant is apparently not defined.
The crypt_file() function sets $ErrStr to a value indicating the cause of the error when it fails. The possible values are as follows:
The filehandle used by crypt_file() for writing data to could not be locked for exclusive use. The system error message corresponding to the standard C library errno variable is also given.
The filehandle used by crypt_file() for reading data from and writing data to when updating a file "in-place" could not be locked for exclusive use. The system error message corresponding to the standard C library errno variable is also given.
The filehandle used by crypt_file() for reading data from could not be locked for shared use. The system error message corresponding to the standard C library errno variable is also given.
The cipher context structure used to perform the encryption or decryption could not be cleaned up after use. The last error message from libcrypto is also given.
The hexadecimal encoding of the encrypted source code, consisting of a pair of hexadecimal digits for each byte of data, could not be decoded because an odd number of hexadecimal digits were found.
The hexadecimal encoding of the encrypted source code, consisting of a pair of hexadecimal digits for each byte of data, could not be decoded because a byte other than a hexadecimal digit was found.
libcrypto's PKCS#5 v2.0 compatible key derivation algorithm failed to derive a key of the specified length from the supplied password for use in the encryption or decryption. The last error message from libcrypto is also given.
The cipher context structure used to perform the encryption or decryption could not be finalized. The last error message from libcrypto is also given.
libcrypto's random number generator failed to generate the specified number of pseudo-random bytes for use as the salt when performing the key derivation prior to encryption. The last error message from libcrypto is also given.
libcrypto's random number generator failed to generate the specified number of pseudo-random bytes for use as the initialization vector (IV) in the encryption. The last error message from libcrypto is also given.
The cipher context structure used to perform the encryption or decryption could not be initialized in the specified crypt mode. This is the first stage of the cipher context structure initialization, performed before setting the key length and modifying other cipher parameters. The last error message from libcrypto is also given.
The cipher context structure used to perform the encryption or decryption could not be initialized in the specified crypt mode with the specified key length. This is the final stage of the cipher context structure initialization, performed after setting the key length and modifying other cipher parameters. The last error message from libcrypto is also given.
libcrypto's random number generator could not be seeded with enough entropy.
The specified file could not be opened by crypt_file() for reading data from and writing data to when updating a file "in-place". The system error message corresponding to the standard C library errno variable is also given.
The specified file from which to read data could not be opened for reading by crypt_file(). The system error message corresponding to the standard C library errno variable is also given.
The specified file could not be opened by crypt_file() for writing data to. The system error message corresponding to the standard C library errno variable is also given.
There was an error reading data from the input filehandle. The system error message corresponding to the standard C library errno variable is also given.
The specified key length could not be set for the cipher context structure used to perform the encryption or decryption. The last error message from libcrypto is also given.
The specified effective key bits could not be set for the cipher context structure used to perform the encryption or decryption when using the RC2 cipher. The last error message from libcrypto is also given.
The specified number of rounds could not be set for the cipher context structure used to perform the encryption or decryption when using the RC5 cipher. The last error message from libcrypto is also given.
The filehandle used by crypt_file() for reading data from and writing data to when updating a file "in-place" could not be truncated to zero size before writing data to it. The system error message corresponding to the standard C library errno variable is also given.
The cipher context structure used to perform the encryption or decryption could not be updated with the specified number of bytes of input data. The last error message from libcrypto is also given.
There was an error writing the statement
to the output filehandle. The system error message corresponding to the standard C library errno variable is also given.
There was an error writing data to the filehandle when updating a file "in-place". The system error message corresponding to the standard C library errno variable is also given.
There was an error writing data to the output filehandle. The system error message corresponding to the standard C library errno variable is also given.
libcrypto's PKCS#5 v1.5 compatible key derivation algorithm failed to derive a key of the requested length from the supplied password for use in the encryption or decryption.
The crypt mode was specified as CRYPT_MODE_DECRYPTED and data read from the input filehandle does not begin with the statement
indicating that the data is probably already decrypted. No action was taken, and crypt_file() returned success. Use the crypt mode CRYPT_MODE_DECRYPT if you really want to force decryption in this case.
The crypt mode was specified as CRYPT_MODE_ENCRYPTED and data read from the input filehandle already begins with the statement
indicating that the data is probably already encrypted. No action was taken, and crypt_file() returned success. Use the crypt mode CRYPT_MODE_ENCRYPT if you really want to force encryption in this case.
See the crypt_file script for examples of the use of the crypt_file() function.
The following symbols are, or can be, exported by this module:
crypt_file;
crypt_file
CRYPT_MODE_AUTO, CRYPT_MODE_ENCRYPT, CRYPT_MODE_DECRYPT, CRYPT_MODE_ENCRYPTED, CRYPT_MODE_DECRYPTED.
$ErrStr.
$ErrStr
None.
Note that specifying the "crypt_mode" as CRYPT_MODE_AUTO, undef or the null string can be used to resolve any ambiguity in the case where crypt_file() is called with two arguments, namely, did the caller intend crypt_file($in_file, $out_file) or crypt_file($in_out_file, $crypt_mode)?
crypt_file($in_file, $out_file)
crypt_file($in_out_file, $crypt_mode)
In such cases, crypt_file() checks if the second argument is a valid "crypt mode" before considering if it is a file name, so it normally Does The Right Thing. However, if you wanted to write the output to a file called 1 (which happens to be the value of the CRYPT_MODE_ENCRYPT flag) then calling
crypt_file($in_file, '1');
will not do what you want. In this case, you can call
crypt_file($in_file, '1', CRYPT_MODE_AUTO);
instead to get the desired behaviour (without having to explicitly specify the crypt mode).
Filter::Crypto.
The FilterCrypto_PRNGInit() and FilterCrypto_GetRandNum() functions used by the XS code are based on code taken from the ssl_rand_seed() and ssl_rand_choosenum() functions in Apache httpd (version 2.4.9).
FilterCrypto_PRNGInit()
FilterCrypto_GetRandNum()
ssl_rand_seed()
ssl_rand_choosenum()
Thanks to Steve Henson for help with performing PBE and PKCS#5 v2.0 key derivation with arbitrary ciphers and non-default key lengths using the OpenSSL libcrypto library.
Steve Hay <shay@cpan.org>.
Copyright (C) 2004-2009, 2012-2014 Steve Hay. All rights reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself, i.e. under the terms of either the GNU General Public License or the Artistic License, as specified in the LICENCE file.
Version 2.10
02 Jul 2023
See the Changes file.
To install Filter::Crypto, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Filter::Crypto
CPAN shell
perl -MCPAN -e shell install Filter::Crypto
For more information on module installation, please visit the detailed CPAN module installation guide.