view release on metacpan or search on metacpan
Revision history for Perl extension Crypt::CBC.
3.07 -- Sun Jul 27 11:49:54 ADT 2025
[Changes Since 3.04]
- New maintainer
- Fix CVE-2025-2814 by using Crypt::URandom
- 3.05 Fixed bug involving manually-specified key not being used in some circumstances
- Fix decryption of ciphertext created with 'header' => 'randomiv'
- Fixed bug in which manually-specified key and -pkdf=>"none" was not having effect
- Converted build process to Dist::Zilla
2.26 Thu Mar 20 16:41:23 EDT 2008
- Fixed onezeropadding test, which was not reporting its test count
properly.
2.25 Fri Jan 11 15:26:27 EST 2008
- Fixed failure of oneandzeroes padding when plaintext size is
an even multiple of blocksize.
- Added new "rijndael_compat" padding method, which is compatible
with the oneandzeroes padding method used by Crypt::Rijndael in
CBC mode.
2.24 Fri Sep 28 11:21:07 EDT 2007
- Fixed failure to run under taint checks with Crypt::Rijndael
or Crypt::OpenSSL::AES (and maybe other Crypt modules). See
http://rt.cpan.org/Public/Bug/Display.html?id=29646.
2.23 Fri Apr 13 14:50:21 EDT 2007
- Added checks for other implementations of CBC which add no
standard padding at all when cipher text is an even multiple
of the block size.
2.22 Sun Oct 29 16:50:32 EST 2006
- Fixed bug in which plaintext encrypted with the -literal_key
option could not be decrypted using a new object created with
the same -literal_key.
- Added documentation confirming that -literal_key must be accompanied by a
-header of 'none' and a manually specificied IV.
2.21 Mon Oct 16 19:26:26 EDT 2006
- Fixed bug in which new() failed to work when first option is -literal_key.
2.20 Sat Aug 12 22:30:53 EDT 2006
- Added ability to pass a preinitialized Crypt::* block cipher object instead of
the class name.
- Fixed a bug when processing -literal_key.
2.19 Tue Jul 18 18:39:57 EDT 2006
- Renamed Crypt::CBC-2.16-vulnerability.txt so that package installs correctly under
Cygwin
2.18 2006/06/06 23:17:04
- added more documentation describing how to achieve compatibility with old encrypted messages
2.17 Mon Jan 9 18:22:51 EST 2006
-IMPORTANT NOTE: Versions of this module prior to 2.17 were incorrectly
using 8 byte IVs when generating the old-style RandomIV style header
(as opposed to the new-style random salt header). This affects data
encrypted using the Rijndael algorithm, which has a 16 byte blocksize,
and is a significant security issue.
The bug has been corrected in versions 2.17 and higher by making it
impossible to use 16-byte block ciphers with RandomIV headers. You may
still read legacy encrypted data by explicitly passing the
-insecure_legacy_decrypt option to Crypt::CBC->new().
-The salt, iv and key are now reset before each complete encryption
cycle. This avoids inadvertent reuse of the same salt.
-A new -header option has been added that allows you to select
among the various types of headers, and avoids the ambiguity
of having multiple interacting options.
-A new random_bytes() method provides access to /dev/urandom on
suitably-equipped hardware.
in decrypt routines.
2.14 Thu May 5 16:08:15 EDT 2005
- RandomIV in message header overrides manually-supplied -salt, as one
would expect it should.
2.13 Fri Apr 22 13:01:32 EDT 200
- Added OpenSSL compatibility
- Salt and IV generators take advantage of /dev/urandom device, if available
- Reorganized internal structure for coding clarity
- Added regression test for PCBC mode
2.12 Thu Jun 17 11:52:04 EDT 2004
- quenched (again) uninitialized variable warnings
2.11 Thu Jun 3 12:07:33 EDT 2004
-Fixed bug reported by Joshua Brown that caused certain length
strings to not encrypt properly if ending in a "0" character.
2.10 Sat May 29 13:10:05 EDT 2004
-Fixed Rijndael compat problems
-Quenched uninitialized variable warnings
2.08 Wed Sep 11 08:12:49 EDT 2002
-Bug fix from Chris Laas to fix custom padding
2.07 Thu Aug 8 14:44:52 EDT 2002
-Bug fixes from Stephen Waters to fix space padding
-Lots of regression tests from Stephen Waters
2.05 Tue Jun 11 22:18:04 EDT 2002
-Makes zero-and-one padding compatible with Crypt::Rijndael::MODE_CBC.
-Lots of improvements to padding mechanisms from Stephen Waters
2.04 Tue Jun 11 22:18:04 EDT 2002
WITHDRAWN VERSION DO NOT USE
2.03 Mon Feb 4 15:41:51 EST 2002
-Patch from Andy Turner <turner@mikomi.org> to allow backward
compatibility with old versions when key length exceeded max.
2.02 Thu Jan 24 00:15:52 EST 2002
1.21 Mon Nov 29 17:11:17 EST 1999
- Generate random initialization vector.
- Use same encryption format as Ben Laurie's patches to OpenSSL (versions >= 0.9.5)
1.20 Sun Dec 20 3:58:01 1998 MET
- Folded in bug fixes from Devin Carraway <aqua@sonic.net>
(chiefly having to do with finish() being called with a
zero-length buffer).
1.10 Thu Sep 11 09:15:01 1998
- Changed package name to Crypt::CBC
1.00 Tue Jun 16 07:37:35 1998
- original version; created by h2xs 1.18
META.yml
Makefile.PL
README
SECURITY.md
SIGNATURE
cpanfile
dist.ini
eg/aes.pl
eg/des.pl
eg/idea.pl
lib/Crypt/CBC.pm
lib/Crypt/CBC/PBKDF.pm
lib/Crypt/CBC/PBKDF/none.pm
lib/Crypt/CBC/PBKDF/opensslv1.pm
lib/Crypt/CBC/PBKDF/opensslv2.pm
lib/Crypt/CBC/PBKDF/pbkdf2.pm
lib/Crypt/CBC/PBKDF/randomiv.pm
t/AES.t
t/Blowfish.t
t/Blowfish_PP.t
t/CAST5.t
t/CTR.t
t/DES.t
t/IDEA.t
t/OFB.t
t/PCBC.t
t/Rijndael.t
t/Rijndael_compat.t
t/author-pod-spell.t
t/author-pod-syntax.t
t/func.t
t/github-issue7.t
t/nopadding.t
t/null_data.t
t/onezeropadding.t
t/parameters.t
],
"dynamic_config" : 0,
"generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
"license" : [
"artistic_2"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "Crypt-CBC",
"prereqs" : {
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"develop" : {
"requires" : {
"Software::Security::Policy::Individual" : "0",
"Test::CPAN::Meta::JSON" : "0.16",
},
"test" : {
"requires" : {
"Test" : "0",
"Test::More" : "0",
"lib" : "0"
}
}
},
"provides" : {
"Crypt::CBC" : {
"file" : "lib/Crypt/CBC.pm",
"version" : "3.07"
},
"Crypt::CBC::PBKDF" : {
"file" : "lib/Crypt/CBC/PBKDF.pm",
"version" : "3.07"
},
"Crypt::CBC::PBKDF::none" : {
"file" : "lib/Crypt/CBC/PBKDF/none.pm",
"version" : "3.07"
},
"Crypt::CBC::PBKDF::opensslv1" : {
"file" : "lib/Crypt/CBC/PBKDF/opensslv1.pm",
"version" : "3.07"
},
"Crypt::CBC::PBKDF::opensslv2" : {
"file" : "lib/Crypt/CBC/PBKDF/opensslv2.pm",
"version" : "3.07"
},
"Crypt::CBC::PBKDF::pbkdf2" : {
"file" : "lib/Crypt/CBC/PBKDF/pbkdf2.pm",
"version" : "3.07"
},
"Crypt::CBC::PBKDF::randomiv" : {
"file" : "lib/Crypt/CBC/PBKDF/randomiv.pm",
"version" : "3.07"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Crypt-CBC"
},
"homepage" : "http://search.cpan.org/dist/Crypt-CBC/",
"repository" : {
"type" : "git",
"url" : "git://github.com/lstein/Lib-Crypt-CBC.git",
"web" : "https://github.com/lstein/Lib-Crypt-CBC"
}
},
"version" : "3.07",
"x_generated_by_perl" : "v5.38.2",
"x_maintainers" : [
"Timothy Legge <timlegge@gmail.com>"
],
"x_serialization_backend" : "Cpanel::JSON::XS version 4.39",
"x_spdx_expression" : "Artistic-2.0"
}
Test::More: '0'
lib: '0'
configure_requires:
ExtUtils::MakeMaker: '0'
dynamic_config: 0
generated_by: 'Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010'
license: artistic_2
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: Crypt-CBC
provides:
Crypt::CBC:
file: lib/Crypt/CBC.pm
version: '3.07'
Crypt::CBC::PBKDF:
file: lib/Crypt/CBC/PBKDF.pm
version: '3.07'
Crypt::CBC::PBKDF::none:
file: lib/Crypt/CBC/PBKDF/none.pm
version: '3.07'
Crypt::CBC::PBKDF::opensslv1:
file: lib/Crypt/CBC/PBKDF/opensslv1.pm
version: '3.07'
Crypt::CBC::PBKDF::opensslv2:
file: lib/Crypt/CBC/PBKDF/opensslv2.pm
version: '3.07'
Crypt::CBC::PBKDF::pbkdf2:
file: lib/Crypt/CBC/PBKDF/pbkdf2.pm
version: '3.07'
Crypt::CBC::PBKDF::randomiv:
file: lib/Crypt/CBC/PBKDF/randomiv.pm
version: '3.07'
requires:
Crypt::Cipher::AES: '0'
Crypt::PBKDF2: '0'
Crypt::URandom: '0'
Digest::MD5: '0'
Digest::SHA: '0'
perl: '5.008'
resources:
bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Crypt-CBC
homepage: http://search.cpan.org/dist/Crypt-CBC/
repository: git://github.com/lstein/Lib-Crypt-CBC.git
version: '3.07'
x_generated_by_perl: v5.38.2
x_maintainers:
- 'Timothy Legge <timlegge@gmail.com>'
x_serialization_backend: 'YAML::Tiny version 1.76'
x_spdx_expression: Artistic-2.0
Makefile.PL view on Meta::CPAN
use 5.008;
use ExtUtils::MakeMaker;
my %WriteMakefileArgs = (
"ABSTRACT" => "Encrypt Data with Cipher Block Chaining Mode",
"AUTHOR" => "Lincoln Stein, lstein\@cshl.org",
"CONFIGURE_REQUIRES" => {
"ExtUtils::MakeMaker" => 0
},
"DISTNAME" => "Crypt-CBC",
"LICENSE" => "artistic_2",
"MIN_PERL_VERSION" => "5.008",
"NAME" => "Crypt::CBC",
"PREREQ_PM" => {
"Crypt::Cipher::AES" => 0,
"Crypt::PBKDF2" => 0,
"Crypt::URandom" => 0,
"Digest::MD5" => 0,
"Digest::SHA" => 0
},
"TEST_REQUIRES" => {
"Test" => 0,
"Test::More" => 0,
NAME
Crypt::CBC - Encrypt Data with Cipher Block Chaining Mode
SYNOPSIS
use Crypt::CBC;
$cipher = Crypt::CBC->new( -pass => 'my secret password',
-cipher => 'Cipher::AES'
);
# one shot mode
$ciphertext = $cipher->encrypt("This data is hush hush");
$plaintext = $cipher->decrypt($ciphertext);
# stream mode
$cipher->start('encrypting');
open(F,"./BIG_FILE");
while (read(F,$buffer,1024)) {
print $cipher->crypt($buffer);
}
print $cipher->finish;
# do-it-yourself mode -- specify key && initialization vector yourself
$key = Crypt::CBC->random_bytes(8); # assuming a 8-byte block cipher
$iv = Crypt::CBC->random_bytes(8);
$cipher = Crypt::CBC->new(-pbkdf => 'none',
-header => 'none',
-key => $key,
-iv => $iv);
$ciphertext = $cipher->encrypt("This data is hush hush");
$plaintext = $cipher->decrypt($ciphertext);
# encrypting via a filehandle (requires Crypt::FileHandle>
$fh = Crypt::CBC->filehandle(-pass => 'secret');
open $fh,'>','encrypted.txt" or die $!
print $fh "This will be encrypted\n";
close $fh;
DESCRIPTION
This module is a Perl-only implementation of the cryptographic cipher
block chaining mode (CBC). In combination with a block cipher such as
AES or Blowfish, you can encrypt and decrypt messages of arbitrarily
long length. The encrypted messages are compatible with the encryption
format used by the OpenSSL package.
To use this module, you will first create a Crypt::CBC cipher object
with new(). At the time of cipher creation, you specify an encryption
key to use and, optionally, a block encryption algorithm. You will then
call the start() method to initialize the encryption or decryption
process, crypt() to encrypt or decrypt one or more blocks of data, and
lastly finish(), to pad and encrypt the final block. For your
convenience, you can call the encrypt() and decrypt() methods to operate
on a whole data value at once.
new()
$cipher = Crypt::CBC->new( -pass => 'my secret key',
-cipher => 'Cipher::AES',
);
# or (for compatibility with versions prior to 2.0)
$cipher = new Crypt::CBC('my secret key' => 'Cipher::AES');
The new() method creates a new Crypt::CBC object. It accepts a list of
-argument => value pairs selected from the following list:
Argument Description
-------- -----------
-pass,-key The encryption/decryption passphrase. These arguments
are interchangeable, but -pass is preferred
("key" is a misnomer, as it is not the literal
encryption key).
-chain_mode The block chaining mode to use. Current options are:
'cbc' -- cipher-block chaining mode [default]
'pcbc' -- plaintext cipher-block chaining mode
'cfb' -- cipher feedback mode
'ofb' -- output feedback mode
'ctr' -- counter mode
-pbkdf The passphrase-based key derivation function used to derive
the encryption key and initialization vector from the
provided passphrase. For backward compatibility, Crypt::CBC
will default to "opensslv1", but it is recommended to use
the standard "pbkdf2"algorithm instead. If you wish to interoperate
with OpenSSL, be aware that different versions of the software
support a series of derivation functions.
'none' -- The value provided in -pass/-key is used directly.
This is the same as passing true to -literal_key.
You must also manually specify the IV with -iv.
The key and the IV must match the keylength
and blocklength of the chosen cipher.
in prehistoric versions of OpenSSL (dangerous)
'opensslv1' -- [default] Use the salted MD5 method that was default
in versions of OpenSSL through v1.0.2.
'opensslv2' -- [better] Use the salted SHA-256 method that was
the default in versions of OpenSSL through v1.1.0.
'pbkdf2' -- [best] Use the PBKDF2 method that was first
introduced in OpenSSL v1.1.1.
More derivation functions may be added in the future. To see the
supported list, use the command
perl -MCrypt::CBC::PBKDF -e 'print join "\n",Crypt::CBC::PBKDF->list'
-iter If the 'pbkdf2' key derivation algorithm is used, this specifies the number of
hashing cycles to be applied to the passphrase+salt (longer is more secure).
[default 10,000]
-hasher If the 'pbkdf2' key derivation algorithm is chosen, you can use this to provide
an initialized Crypt::PBKDF2::Hash object.
[default HMACSHA2 for OpenSSL compatability]
-header What type of header to prepend to the ciphertext. One of
"null", or "none" (default "standard").
-literal_key [deprected, use -pbkdf=>'none']
If true, the key provided by "-key" or "-pass" is used
directly for encryption/decryption without salting or
hashing. The key must be the right length for the chosen
cipher.
[default false)
-pcbc [deprecated, use -chaining_mode=>'pcbc']
Whether to use the PCBC chaining algorithm rather than
the standard CBC algorithm (default false).
-add_header [deprecated; use -header instead]
Whether to add the salt and IV to the header of the output
cipher text.
-regenerate_key [deprecated; use -literal_key instead]
Whether to use a hash of the provided key to generate
the actual encryption key (default true)
-prepend_iv [deprecated; use -header instead]
Whether to prepend the IV to the beginning of the
encrypted stream (default true)
Crypt::CBC requires three pieces of information to do its job. First it
needs the name of the block cipher algorithm that will encrypt or
decrypt the data in blocks of fixed length known as the cipher's
"blocksize." Second, it needs an encryption/decryption key to pass to
the block cipher. Third, it needs an initialization vector (IV) that
will be used to propagate information from one encrypted block to the
next. Both the key and the IV must be exactly the same length as the
chosen cipher's blocksize.
Crypt::CBC can derive the key and the IV from a passphrase that you
provide, or can let you specify the true key and IV manually. In
addition, you have the option of embedding enough information to
regenerate the IV in a short header that is emitted at the start of the
encrypted stream, or outputting a headerless encryption stream. In the
first case, Crypt::CBC will be able to decrypt the stream given just the
original key or passphrase. In the second case, you will have to provide
the original IV as well as the key/passphrase.
The -cipher option specifies which block cipher algorithm to use to
encode each section of the message. This argument is optional and will
default to the secure Crypt::Cipher::AES algorithm. You may use any
compatible block encryption algorithm that you have installed.
Currently, this includes Crypt::Cipher::AES, Crypt::DES,
Crypt::DES_EDE3, Crypt::IDEA, Crypt::Blowfish, Crypt::CAST5 and
Crypt::Rijndael. You may refer to them using their full names
("Crypt::IDEA") or in abbreviated form ("IDEA").
Instead of passing the name of a cipher class, you may pass an
already-created block cipher object. This allows you to take advantage
of cipher algorithms that have parameterized new() methods, such as
Crypt::Eksblowfish:
my $eksblowfish = Crypt::Eksblowfish->new(8,$salt,$key);
my $cbc = Crypt::CBC->new(-cipher=>$eksblowfish);
The -pass argument provides a passphrase to use to generate the
encryption key or the literal value of the block cipher key. If used in
passphrase mode (which is the default), -pass can be any number of
characters; the actual key will be derived by passing the passphrase
through a series of hashing operations. To take full advantage of a
given block cipher, the length of the passphrase should be at least
equal to the cipher's blocksize. For backward compatibility, you may
also refer to this argument using -key.
described in RFC 2898 L<https://tools.ietf.org/html/rfc2898>
"none" -- don't use a derivation function, but treat the passphrase
as the literal key. This is the same as B<-literal_key> true.
"nosalt" -- an insecure key derivation method used by prehistoric versions
of OpenSSL, provided for backward compatibility. Don't use.
"opensslv1" was OpenSSL's default key derivation algorithm through
version 1.0.2, but is susceptible to dictionary attacks and is no longer
supported. It remains the default for Crypt::CBC in order to avoid
breaking compatibility with previously-encrypted messages. Using this
option will issue a deprecation warning when initiating encryption. You
can suppress the warning by passing a true value to the -nodeprecate
option.
It is recommended to specify the "pbkdf2" key derivation algorithm when
compatibility with older versions of Crypt::CBC is not needed. This
algorithm is deliberately computationally expensive in order to make
dictionary-based attacks harder. As a result, it introduces a slight
delay before an encryption or decryption operation starts.
The -iter argument is used in conjunction with the "pbkdf2" key
derivation option. Its value indicates the number of hashing cycles used
to derive the key. Larger values are more secure, but impose a longer
delay before encryption/decryption starts. The default is 10,000 for
compatibility with OpenSSL's default.
The -hasher argument is used in conjunction with the "pbkdf2" key
derivation option to pass the reference to an initialized
Crypt::PBKDF2::Hash object. If not provided, it defaults to the
OpenSSL-compatible hash function HMACSHA2 initialized with its default
options (SHA-256 hash).
The -header argument specifies what type of header, if any, to prepend
to the beginning of the encrypted data stream. The header allows
Crypt::CBC to regenerate the original IV and correctly decrypt the data
without your having to provide the same IV used to encrypt the data.
Valid values for the -header are:
"salt" -- Combine the passphrase with an 8-byte random value to
generate both the block cipher key and the IV from the
provided passphrase. The salt will be appended to the
beginning of the data stream allowing decryption to
regenerate both the key and IV given the correct passphrase.
This method is compatible with current versions of OpenSSL.
"randomiv" -- Generate the block cipher key from the passphrase, and
choose a random 8-byte value to use as the IV. The IV will
be prepended to the data stream. This method is compatible
with ciphertext produced by versions of the library prior to
2.17, but is incompatible with block ciphers that have non
8-byte block sizes, such as Rijndael. Crypt::CBC will exit
with a fatal error if you try to use this header mode with a
non 8-byte cipher. This header type is NOT secure and NOT
recommended.
"none" -- Do not generate a header. To decrypt a stream encrypted
in this way, you will have to provide the true key and IV
manually.
The "salt" header is now the default as of Crypt::CBC version 2.17. In
all earlier versions "randomiv" was the default.
When using a "salt" header, you may specify your own value of the salt,
by passing the desired 8-byte character string to the -salt argument.
Otherwise, the module will generate a random salt for you. Crypt::CBC
will generate a fatal error if you specify a salt value that isn't
exactly 8 bytes long. For backward compatibility reasons, passing a
value of "1" will generate a random salt, the same as if no -salt
argument was provided.
The -padding argument controls how the last few bytes of the encrypted
stream are dealt with when they not an exact multiple of the cipher
block length. The default is "standard", the method specified in PKCS#5.
The -chaining_mode argument will select among several different block
the property that if one block in the ciphertext message
is damaged, only that block and the next one will be
rendered un-decryptable.
'pcbc' -- Plaintext Cipher-Block Chaining mode. This has the property
that one damaged ciphertext block will render the
remainder of the message unreadable
'cfb' -- Cipher Feedback Mode. In this mode, both encryption and decryption
are performed using the block cipher's "encrypt" algorithm.
The error propagation behaviour is similar to CBC's.
'ofb' -- Output Feedback Mode. Similar to CFB, the block cipher's encrypt
algorithm is used for both encryption and decryption. If one bit
of the plaintext or ciphertext message is damaged, the damage is
confined to a single block of the corresponding ciphertext or
plaintext, and error correction algorithms can be used to reconstruct
the damaged part.
'ctr' -- Counter Mode. This mode uses a one-time "nonce" instead of
an IV. The nonce is incremented by one for each block of
Passing a -pcbc argument of true will have the same effect as
-chaining_mode=>'pcbc', and is included for backward compatibility.
[deprecated].
For more information on chaining modes, see
<http://www.crypto-it.net/eng/theory/modes-of-block-ciphers.html>.
The -keysize argument can be used to force the cipher's keysize. This is
useful for several of the newer algorithms, including AES, ARIA,
Blowfish, and CAMELLIA. If -keysize is not specified, then Crypt::CBC
will use the value returned by the cipher's max_keylength() method. Note
that versions of CBC::Crypt prior to 2.36 could also allow you to set
the blocksize, but this was never supported by any ciphers and has been
removed.
For compatibility with earlier versions of this module, you can provide
new() with a hashref containing key/value pairs. The key names are the
same as the arguments described earlier, but without the initial hyphen.
You may also call new() with one or two positional arguments, in which
case the first argument is taken to be the key and the second to be the
optional block cipher algorithm.
crypt()
$ciphertext = $cipher->crypt($plaintext);
After calling start(), you should call crypt() as many times as
necessary to encrypt the desired data.
finish()
$ciphertext = $cipher->finish();
The CBC algorithm must buffer data blocks internally until they are even
multiples of the encryption algorithm's blocksize (typically 8 bytes).
After the last call to crypt() you should call finish(). This flushes
the internal buffer and returns any leftover ciphertext.
In a typical application you will read the plaintext from a file or
input stream and write the result to standard output in a loop that
might look like this:
$cipher = new Crypt::CBC('hey jude!');
$cipher->start('encrypting');
print $cipher->crypt($_) while <>;
print $cipher->finish();
encrypt()
$ciphertext = $cipher->encrypt($plaintext)
This convenience function runs the entire sequence of start(), crypt()
and finish() for you, processing the provided plaintext and returning
the corresponding ciphertext.
message.
filehandle()
This method returns a filehandle for transparent encryption or
decryption using Christopher Dunkle's excellent Crypt::FileHandle
module. This module must be installed in order to use this method.
filehandle() can be called as a class method using the same arguments as
new():
$fh = Crypt::CBC->filehandle(-cipher=> 'Blowfish',
-pass => "You'll never guess");
or on a previously-created Crypt::CBC object:
$cbc = Crypt::CBC->new(-cipher=> 'Blowfish',
-pass => "You'll never guess");
$fh = $cbc->filehandle;
The filehandle can then be opened using the familiar open() syntax.
Printing to a filehandle opened for writing will encrypt the data.
Filehandles opened for input will be decrypted.
Here is an example:
# transparent encryption
bytes, then a whole block of "0808080808080808" is appended.
oneandzeroes: Binary safe
pads with "80" followed by as many "00" necessary to fill the
block. If the last block is a full block and blocksize is 8, a
block of "8000000000000000" will be appended.
rijndael_compat: Binary safe, with caveats
similar to oneandzeroes, except that no padding is performed if
the last block is a full block. This is provided for
compatibility with Crypt::Rijndael's buit-in MODE_CBC.
Note that Crypt::Rijndael's implementation of CBC only
works with messages that are even multiples of 16 bytes.
null: text only
pads with as many "00" necessary to fill the block. If the last
block is a full block and blocksize is 8, a block of
"0000000000000000" will be appended.
space: text only
same as "null", but with "20".
none:
no padding added. Useful for special-purpose applications where
you wish to add custom padding to the message.
Both the standard and oneandzeroes paddings are binary safe. The space
and null paddings are recommended only for text data. Which type of
padding you use depends on whether you wish to communicate with an
external (non Crypt::CBC library). If this is the case, use whatever
padding method is compatible.
You can also pass in a custom padding function. To do this, create a
function that takes the arguments:
$padded_block = function($block,$blocksize,$direction);
where $block is the current block of data, $blocksize is the size to pad
it to, $direction is "e" for encrypting and "d" for decrypting, and
$padded_block is the result after padding or depadding.
When encrypting, the function should always return a string of
<blocksize> length, and when decrypting, can expect the string coming in
to always be that length. See _standard_padding(), _space_padding(),
_null_padding(), or _oneandzeroes_padding() in the source for examples.
Standard and oneandzeroes padding are recommended, as both space and
null padding can potentially truncate more characters than they should.
Comparison to Crypt::Mode::CBC
The CryptX modules Crypt::Mode::CBC, Crypt::Mode::OFB, Crypt::Mode::CFB,
and Crypt::Mode::CTR provide fast implementations of the respective
cipherblock chaining modes (roughly 5x the speed of Crypt::CBC).
Crypt::CBC was designed to encrypt and decrypt messages in a manner
compatible with OpenSSL's "enc" function. Hence it handles the
derivation of the key and IV from a passphrase using the same
conventions as OpenSSL, and it writes out an OpenSSL-compatible header
in the encrypted message in a manner that allows the key and IV to be
regenerated during decryption.
In contrast, the CryptX modules do not automatically derive the key and
IV from a passphrase or write out an encrypted header. You will need to
derive and store the key and IV by other means (e.g. with CryptX's
Crypt::KeyDerivation module, or with Crypt::PBKDF2).
EXAMPLES
Three examples, aes.pl, des.pl and idea.pl can be found in the eg/
subdirectory of the Crypt-CBC distribution. These implement command-line
DES and IDEA encryption algorithms using default parameters, and should
be compatible with recent versions of OpenSSL. Note that aes.pl uses the
"pbkdf2" key derivation function to generate its keys. The other two
were distributed with pre-PBKDF2 versions of Crypt::CBC, and use the
older "opensslv1" algorithm.
LIMITATIONS
The encryption and decryption process is about a tenth the speed of the
equivalent OpenSSL tool and about a fifth of the Crypt::Mode::CBC module
(both which use compiled C).
BUGS
Please report them.
AUTHOR
Lincoln Stein, lstein@cshl.org
LICENSE
This module is distributed under the ARTISTIC LICENSE v2 using the same
SECURITY.md view on Meta::CPAN
# Security Policy for the Crypt-CBC distribution.
Report security issues by email to Timothy Legge <timlegge@gmail.com>.
This is the Security Policy for Crypt-CBC.
This text is based on the CPAN Security Group's Guidelines for Adding
a Security Policy to Perl Distributions (version 1.3.0)
https://security.metacpan.org/docs/guides/security-policy-for-authors.html
# How to Report a Security Vulnerability
Security vulnerabilities can be reported to the current Crypt-CBC
maintainers by email to Timothy Legge <timlegge@gmail.com>.
Please include as many details as possible, including code samples
or test cases, so that we can reproduce the issue. Check that your
report does not expose any sensitive data, such as passwords,
tokens, or personal information.
If you would like any help with triaging the issue, or if the issue
is being actively exploited, please copy the report to the CPAN
Security Group (CPANSec) at <cpan-security@security.metacpan.org>.
SECURITY.md view on Meta::CPAN
The project maintainer(s) may forward this issue to the security
contacts for other projects where we believe it is relevant. This
may include embedded libraries, system libraries, prerequisite
modules or downstream software that uses this software.
They may also forward this issue to CPANSec.
# Which Software This Policy Applies To
Any security vulnerabilities in Crypt-CBC are covered by this policy.
Security vulnerabilities in versions of any libraries that are
included in Crypt-CBC are also covered by this policy.
Security vulnerabilities are considered anything that allows users
to execute unauthorised code, access unauthorised resources, or to
have an adverse impact on accessibility or performance of a system.
Security vulnerabilities in upstream software (prerequisite modules
or system libraries, or in Perl), are not covered by this policy
unless they affect Crypt-CBC, or Crypt-CBC can
be used to exploit vulnerabilities in them.
Security vulnerabilities in downstream software (any software that
uses Crypt-CBC, or plugins to it that are not included with the
Crypt-CBC distribution) are not covered by this policy.
## Supported Versions of Crypt-CBC
The maintainer(s) will only commit to releasing security fixes for
the latest version of Crypt-CBC.
# Installation and Usage Issues
The distribution metadata specifies minimum versions of
prerequisites that are required for Crypt-CBC to work. However, some
of these prerequisites may have security vulnerabilities, and you
should ensure that you are using up-to-date versions of these
prerequisites.
Where security vulnerabilities are known, the metadata may indicate
newer versions as recommended.
## Usage
Please see the software documentation for further information.
SHA256 79169792709633d57eab60e127427f43d0bcf76008e17332d9d48f7c59e7bd0b META.json
SHA256 194d13a2f79c2f6457826c7cfc5107b85ce77c5c592e62c01db0fef45ae61e0f META.yml
SHA256 aa6f29a4cb09dcca0025fec94be1a4570846b0f015d9810c31a4410f2f3ba5ad Makefile.PL
SHA256 ce507665c9a658dfb8acbbcad7be3672bc10bd2481cea71ee34f681b31e62504 README
SHA256 62356a1e52b943349e64219a2d51cb43943f6b81e1218ccb84f991ac285c936c SECURITY.md
SHA256 ebcb942a8f5dc6faa6c60d0b379d8f655ad53025c8ed08574af65cfec678539c cpanfile
SHA256 1f4349e2ce230fafba2243095dce6014367828847e5f531ab9e09f0394987acf dist.ini
SHA256 ff3527df59ea7328382fa1f65086e270809290dca89e34ec1929097b5dd4e0fd eg/aes.pl
SHA256 b5cb7faeaee8c09070429d1defaeb2903922eba246021e1c52e055fb25be8f32 eg/des.pl
SHA256 bbd874f2fe3658dba974a86de718bc39c9f75ec5d9ed749188f5521654c5ce1d eg/idea.pl
SHA256 98510e7b0d96543424373b824279f3a080ff0eb9d641f61b63ef66fa05470263 lib/Crypt/CBC.pm
SHA256 e46092064e718e5fb0ecd278544f91c184a72305182c084c1af9d0a9adb257ef lib/Crypt/CBC/PBKDF.pm
SHA256 df33ea417f6f014cba0757bb9a746f500b7fba05a397317dd713c325a712d29c lib/Crypt/CBC/PBKDF/none.pm
SHA256 497ea7a94c5862439fb3966bd74f1930b2511f5ae3b9a2f610338929bc0f231d lib/Crypt/CBC/PBKDF/opensslv1.pm
SHA256 8e2ce722eec9464a615f7e7a532f124e9dc82b6a79cecb2859e02f2daaa5a13a lib/Crypt/CBC/PBKDF/opensslv2.pm
SHA256 5339ad4f4a0a619546dda6fa5ccbfeb307dcd0810d4b96a5ac03a59ec12599fd lib/Crypt/CBC/PBKDF/pbkdf2.pm
SHA256 d261e9ab5a27787ddf171894370704fd2d7285e377c44af1901bf46ede2716e9 lib/Crypt/CBC/PBKDF/randomiv.pm
SHA256 f216d66ba1edb1691cb3acc16bd5c334d1d15dd31bcf3f327d610bc9ca492092 t/AES.t
SHA256 baf7adfcfd0448b0b7810a11e34f6c89bddf6289308b59205803cb0158938280 t/Blowfish.t
SHA256 8fd2cfb41a3848593dfb8a067eb714415626f97cdf4127610e382a12a926ca29 t/Blowfish_PP.t
SHA256 bd67ecd5679803b035e797edbb2bd3882324446df8cdf894bbd9d65fd6a986ca t/CAST5.t
SHA256 82801eaf629f85bb8112f8fecd023cc0e3b0a3acd9014610a427433ea9e1f0e1 t/CTR.t
SHA256 f41a40b0ea2001a2e2313c8a2cc19acecd96e87be474d0ddd8909802b63d1cc1 t/DES.t
SHA256 9f23f71abf2cc0b7320367a45006f8faa2eb265139047bd3d0c7656f5e6d6eb6 t/IDEA.t
SHA256 7f73640cd76f56dc1ee71f519fee80701509a9da8ef978ca7956fb7d9812c11e t/OFB.t
SHA256 761d2845c2b0589ac41389d7aeba32372e67ebdb66c5ceedab84a4e035cc93d5 t/PCBC.t
SHA256 a6d4a24a85fe6853a6d39eb390c9902d0bd884a7f520922ecbfc16e26ba36423 t/Rijndael.t
SHA256 0d34e793f3743f1d36471b9fd35afcd317ba6708f1426ff507acfd4b70d6de8e t/Rijndael_compat.t
SHA256 f91ae43560bb7f6d53aa449209e09b942e98460419b0db0c0b845dd77b93bb2f t/author-pod-spell.t
SHA256 305c657c6b73f10767a0ea286b8a73d693940f4cbb8b6a0a4d34e2b5a1c04635 t/author-pod-syntax.t
SHA256 38b453979b9a1f831352f9d03001518388b26194b248b777131abb91f3c452bc t/func.t
SHA256 fd68c96b0c4be704ddb7847d1776ba1fe6f8c62aea6f5e754eee59b631154dbc t/github-issue7.t
SHA256 2d3c167cccecb531128f48101c5bef259195ea54afb8f1777ac957e62e93bdf8 t/nopadding.t
SHA256 b981b47fe4fd89bef11745df99b5a3895530b0dcf29813d0586568cb082c125b t/null_data.t
SHA256 e47fdd241d16c5009e226ce2a4d9477703f576f1ce07af14e58a0f91f6f714b0 t/onezeropadding.t
SHA256 2ea648c93c413c69cda3791619c6896c13d2692813cab4667d4760889892bd70 t/parameters.t
name = Crypt-CBC
author = Lincoln Stein, lstein@cshl.org
main_module = lib/Crypt/CBC.pm
license = Artistic_2_0
copyright_holder = Lincoln Stein
copyright_year = 1998 - 2025
[Meta::Maintainers]
maintainer = Timothy Legge <timlegge@gmail.com>
[@Filter]
-bundle = @Basic
-remove = GatherDir
[CopyFilesFromBuild]
copy = Makefile.PL
copy = LICENSE
copy = cpanfile
copy = SECURITY.md
[Repository]
git_remote = upstream
[Bugtracker]
web = https://rt.cpan.org/Public/Dist/Display.html?Name=Crypt-CBC
[SecurityPolicy]
-policy = Individual
maintainer = Timothy Legge <timlegge@gmail.com>
[Homepage]
metadata = https://metacpan.org/pod/Crypt::CBC
[Git::NextVersion]
first_version = 3.06 ; this is the default
version_by_branch = 0 ; this is the default
version_regexp = ^(3.\d+)$ ; this is the default
[Git::GatherDir]
exclude_filename = cpanfile
exclude_filename = Makefile.PL
exclude_filename = README.md
#!/usr/bin/perl
use lib '../blib/lib';
use Getopt::Std;
use Crypt::CBC;
use strict vars;
my %options;
getopts('edk:p:i:o:',\%options) || die <<USAGE;
Usage: aes.pl [options] file1 file2 file3...
AES encrypt/decrypt files using Cipher Block Chaining mode, and
the PBKDF2 key derivation function.
It is compatible with files encrypted using
USAGE
;
@ARGV = $options{'i'} if $options{'i'};
push(@ARGV,'-') unless @ARGV;
open(STDOUT,">$options{'o'}") or die "$options{'o'}: $!"
if $options{'o'};
my $decrypt = $options{'d'} and !$options{'e'};
my $key = $options{'k'} || $options{'p'} || get_key(!$decrypt);
my $cipher = Crypt::CBC->new(-pass => $key,
-cipher => 'Crypt::Cipher::AES',
-pbkdf => 'pbkdf2',
-chain_mode => 'ctr',
) || die "Couldn't create CBC object";
$cipher->start($decrypt ? 'decrypt' : 'encrypt');
my $in;
while (@ARGV) {
my $file = shift @ARGV;
open(ARGV,$file) || die "$file: $!";
print $cipher->crypt($in) while read(ARGV,$in,1024);
close ARGV;
}
print $cipher->finish;
#!/usr/bin/perl
use lib '../blib/lib';
use Getopt::Std;
use Crypt::CBC;
use strict vars;
my %options;
getopts('edk:i:o:',\%options) || die <<USAGE;
Usage: des.pl [options] file1 file2 file3...
DES encrypt/decrypt files using Cipher Block Chaining mode.
It is compatible with files encrypted using
"openssl enc -des-cbc -md md5".
USAGE
;
@ARGV = $options{'i'} if $options{'i'};
push(@ARGV,'-') unless @ARGV;
open (STDOUT,">$options{'o'}") || die "$options{'o'}: $!"
if $options{'o'};
my $key = $options{'k'} || get_key();
# DES used by default
my $cipher = Crypt::CBC->new(-key => $key,
-cipher=> 'DES',
-salt => 1) || die "Couldn't create CBC object";
my $decrypt = $options{'d'} and !$options{'e'};
$cipher->start($decrypt ? 'decrypt' : 'encrypt');
my $in;
while (@ARGV) {
my $file = shift @ARGV;
open(ARGV,$file) || die "$file: $!";
print $cipher->crypt($in) while read(ARGV,$in,1024);
close ARGV;
}
#!/usr/bin/perl
use lib '../blib/lib';
use Getopt::Std;
use Crypt::IDEA;
use Crypt::CBC;
use strict vars;
my %options;
getopts('edk:i:o:',\%options) || die <<USAGE;
Usage: idea.pl [options] file1 file2 file3...
IDEA encrypt/decrypt files using Cipher Block Chaining mode.
Options:
-e encrypt (default)
-d decrypt
-o file output file
USAGE
;
@ARGV = $options{'i'} if $options{'i'};
push(@ARGV,'-') unless @ARGV;
open(STDOUT,">$options{'o'}") or die "$options{'o'}: $!"
if $options{'o'};
my $key = $options{'k'} || get_key();
my $cipher = Crypt::CBC->new(-key => $key,
-cipher => 'IDEA',
-salt => 1,
) || die "Couldn't create CBC object";
my $decrypt = $options{'d'} and !$options{'e'};
$cipher->start($decrypt ? 'decrypt' : 'encrypt');
my $in;
while (@ARGV) {
my $file = shift @ARGV;
open(ARGV,$file) || die "$file: $!";
print $cipher->crypt($in) while read(ARGV,$in,1024);
close ARGV;
}
lib/Crypt/CBC.pm view on Meta::CPAN
package Crypt::CBC;
use strict;
use Carp 'croak','carp';
use Crypt::CBC::PBKDF;
use Crypt::URandom ();
use bytes;
no warnings 'uninitialized';
our $VERSION = '3.07';
use constant DEFAULT_PBKDF => 'opensslv1';
use constant DEFAULT_ITER => 10_000; # same as OpenSSL default
my @valid_options = qw(
pass
lib/Crypt/CBC.pm view on Meta::CPAN
return $result;
}
# this is called at the end to flush whatever's left
sub finish (\$) {
my $self = shift;
my $bs = $self->{'blocksize'};
my $block = $self->{buffer}; # what's left
# Special case hack for backward compatibility with Crypt::Rijndael's CBC_MODE.
if (length $block == 0 && $self->{padding} eq \&_rijndael_compat) {
delete $self->{'civ'};
delete $self->{'buffer'};
return '';
}
$self->{civ} ||= '';
my $iv = $self->{civ};
my $code = $self->chaining_method($self->{decrypt});
lib/Crypt/CBC.pm view on Meta::CPAN
croak "padding method callback does not behave properly: expected $bs bytes back, got $rbs bytes back."
unless ($rbs == $bs);
}
} else {
$padding = $padding eq 'none' ? \&_no_padding
:$padding eq 'null' ? \&_null_padding
:$padding eq 'space' ? \&_space_padding
:$padding eq 'oneandzeroes' ? \&_oneandzeroes_padding
:$padding eq 'rijndael_compat'? \&_rijndael_compat
:$padding eq 'standard' ? \&_standard_padding
:croak "'$padding' padding not supported. See perldoc Crypt::CBC for instructions on creating your own.";
}
return $padding;
}
sub _get_key_and_block_sizes {
my $class = shift;
my $cipher = shift;
my $options = shift;
# allow user to override the keysize value
lib/Crypt/CBC.pm view on Meta::CPAN
sub pbkdf { shift->{pbkdf} }
# get the initialized PBKDF object
sub pbkdf_obj {
my $self = shift;
my $pbkdf = $self->pbkdf;
my $iter = $self->{iter};
my $hc = $self->{hasher};
my @hash_args = $hc ? ref ($hc) ? (hasher => $hc) : (hash_class => $hc)
: ();
return Crypt::CBC::PBKDF->new($pbkdf =>
{
key_len => $self->{keysize},
iv_len => $self->{blocksize},
iterations => $iter,
@hash_args,
}
);
}
############################# generating key, iv and salt ########################
lib/Crypt/CBC.pm view on Meta::CPAN
sub pcbc { shift->{pcbc} }
sub header_mode {shift->{header_mode} }
sub literal_key {shift->{literal_key}}
sub nodeprecate {shift->{nodeprecate}}
1;
__END__
=head1 NAME
Crypt::CBC - Encrypt Data with Cipher Block Chaining Mode
=head1 SYNOPSIS
use Crypt::CBC;
$cipher = Crypt::CBC->new( -pass => 'my secret password',
-cipher => 'Cipher::AES'
);
# one shot mode
$ciphertext = $cipher->encrypt("This data is hush hush");
$plaintext = $cipher->decrypt($ciphertext);
# stream mode
$cipher->start('encrypting');
open(F,"./BIG_FILE");
while (read(F,$buffer,1024)) {
print $cipher->crypt($buffer);
}
print $cipher->finish;
# do-it-yourself mode -- specify key && initialization vector yourself
$key = Crypt::CBC->random_bytes(8); # assuming a 8-byte block cipher
$iv = Crypt::CBC->random_bytes(8);
$cipher = Crypt::CBC->new(-pbkdf => 'none',
-header => 'none',
-key => $key,
-iv => $iv);
$ciphertext = $cipher->encrypt("This data is hush hush");
$plaintext = $cipher->decrypt($ciphertext);
# encrypting via a filehandle (requires Crypt::FileHandle>
$fh = Crypt::CBC->filehandle(-pass => 'secret');
open $fh,'>','encrypted.txt" or die $!
print $fh "This will be encrypted\n";
close $fh;
=head1 DESCRIPTION
This module is a Perl-only implementation of the cryptographic cipher
block chaining mode (CBC). In combination with a block cipher such as
AES or Blowfish, you can encrypt and decrypt messages of arbitrarily
long length. The encrypted messages are compatible with the
encryption format used by the B<OpenSSL> package.
To use this module, you will first create a Crypt::CBC cipher object
with new(). At the time of cipher creation, you specify an encryption
key to use and, optionally, a block encryption algorithm. You will
then call the start() method to initialize the encryption or
decryption process, crypt() to encrypt or decrypt one or more blocks
of data, and lastly finish(), to pad and encrypt the final block. For
your convenience, you can call the encrypt() and decrypt() methods to
operate on a whole data value at once.
=head2 new()
$cipher = Crypt::CBC->new( -pass => 'my secret key',
-cipher => 'Cipher::AES',
);
# or (for compatibility with versions prior to 2.0)
$cipher = new Crypt::CBC('my secret key' => 'Cipher::AES');
The new() method creates a new Crypt::CBC object. It accepts a list of
-argument => value pairs selected from the following list:
Argument Description
-------- -----------
-pass,-key The encryption/decryption passphrase. These arguments
are interchangeable, but -pass is preferred
("key" is a misnomer, as it is not the literal
encryption key).
lib/Crypt/CBC.pm view on Meta::CPAN
-chain_mode The block chaining mode to use. Current options are:
'cbc' -- cipher-block chaining mode [default]
'pcbc' -- plaintext cipher-block chaining mode
'cfb' -- cipher feedback mode
'ofb' -- output feedback mode
'ctr' -- counter mode
-pbkdf The passphrase-based key derivation function used to derive
the encryption key and initialization vector from the
provided passphrase. For backward compatibility, Crypt::CBC
will default to "opensslv1", but it is recommended to use
the standard "pbkdf2"algorithm instead. If you wish to interoperate
with OpenSSL, be aware that different versions of the software
support a series of derivation functions.
'none' -- The value provided in -pass/-key is used directly.
This is the same as passing true to -literal_key.
You must also manually specify the IV with -iv.
The key and the IV must match the keylength
and blocklength of the chosen cipher.
lib/Crypt/CBC.pm view on Meta::CPAN
in prehistoric versions of OpenSSL (dangerous)
'opensslv1' -- [default] Use the salted MD5 method that was default
in versions of OpenSSL through v1.0.2.
'opensslv2' -- [better] Use the salted SHA-256 method that was
the default in versions of OpenSSL through v1.1.0.
'pbkdf2' -- [best] Use the PBKDF2 method that was first
introduced in OpenSSL v1.1.1.
More derivation functions may be added in the future. To see the
supported list, use the command
perl -MCrypt::CBC::PBKDF -e 'print join "\n",Crypt::CBC::PBKDF->list'
-iter If the 'pbkdf2' key derivation algorithm is used, this specifies the number of
hashing cycles to be applied to the passphrase+salt (longer is more secure).
[default 10,000]
-hasher If the 'pbkdf2' key derivation algorithm is chosen, you can use this to provide
an initialized Crypt::PBKDF2::Hash object.
[default HMACSHA2 for OpenSSL compatability]
-header What type of header to prepend to the ciphertext. One of
lib/Crypt/CBC.pm view on Meta::CPAN
"null", or "none" (default "standard").
-literal_key [deprected, use -pbkdf=>'none']
If true, the key provided by "-key" or "-pass" is used
directly for encryption/decryption without salting or
hashing. The key must be the right length for the chosen
cipher.
[default false)
-pcbc [deprecated, use -chaining_mode=>'pcbc']
Whether to use the PCBC chaining algorithm rather than
the standard CBC algorithm (default false).
-add_header [deprecated; use -header instead]
Whether to add the salt and IV to the header of the output
cipher text.
-regenerate_key [deprecated; use -literal_key instead]
Whether to use a hash of the provided key to generate
the actual encryption key (default true)
-prepend_iv [deprecated; use -header instead]
Whether to prepend the IV to the beginning of the
encrypted stream (default true)
Crypt::CBC requires three pieces of information to do its job. First
it needs the name of the block cipher algorithm that will encrypt or
decrypt the data in blocks of fixed length known as the cipher's
"blocksize." Second, it needs an encryption/decryption key to pass to
the block cipher. Third, it needs an initialization vector (IV) that
will be used to propagate information from one encrypted block to the
next. Both the key and the IV must be exactly the same length as the
chosen cipher's blocksize.
Crypt::CBC can derive the key and the IV from a passphrase that you
provide, or can let you specify the true key and IV manually. In
addition, you have the option of embedding enough information to
regenerate the IV in a short header that is emitted at the start of
the encrypted stream, or outputting a headerless encryption stream. In
the first case, Crypt::CBC will be able to decrypt the stream given
just the original key or passphrase. In the second case, you will have
to provide the original IV as well as the key/passphrase.
The B<-cipher> option specifies which block cipher algorithm to use to
encode each section of the message. This argument is optional and
will default to the secure Crypt::Cipher::AES algorithm.
You may use any compatible block encryption
algorithm that you have installed. Currently, this includes
Crypt::Cipher::AES, Crypt::DES, Crypt::DES_EDE3, Crypt::IDEA, Crypt::Blowfish,
Crypt::CAST5 and Crypt::Rijndael. You may refer to them using their
full names ("Crypt::IDEA") or in abbreviated form ("IDEA").
Instead of passing the name of a cipher class, you may pass an
already-created block cipher object. This allows you to take advantage
of cipher algorithms that have parameterized new() methods, such as
Crypt::Eksblowfish:
my $eksblowfish = Crypt::Eksblowfish->new(8,$salt,$key);
my $cbc = Crypt::CBC->new(-cipher=>$eksblowfish);
The B<-pass> argument provides a passphrase to use to generate the
encryption key or the literal value of the block cipher key. If used
in passphrase mode (which is the default), B<-pass> can be any number
of characters; the actual key will be derived by passing the
passphrase through a series of hashing operations. To take full
advantage of a given block cipher, the length of the passphrase should
be at least equal to the cipher's blocksize. For backward
compatibility, you may also refer to this argument using B<-key>.
lib/Crypt/CBC.pm view on Meta::CPAN
described in RFC 2898 L<https://tools.ietf.org/html/rfc2898>
"none" -- don't use a derivation function, but treat the passphrase
as the literal key. This is the same as B<-literal_key> true.
"nosalt" -- an insecure key derivation method used by prehistoric versions
of OpenSSL, provided for backward compatibility. Don't use.
"opensslv1" was OpenSSL's default key derivation algorithm through
version 1.0.2, but is susceptible to dictionary attacks and is no
longer supported. It remains the default for Crypt::CBC in order to
avoid breaking compatibility with previously-encrypted messages. Using
this option will issue a deprecation warning when initiating
encryption. You can suppress the warning by passing a true value to
the B<-nodeprecate> option.
It is recommended to specify the "pbkdf2" key derivation algorithm
when compatibility with older versions of Crypt::CBC is not
needed. This algorithm is deliberately computationally expensive in
order to make dictionary-based attacks harder. As a result, it
introduces a slight delay before an encryption or decryption
operation starts.
The B<-iter> argument is used in conjunction with the "pbkdf2" key
derivation option. Its value indicates the number of hashing cycles
used to derive the key. Larger values are more secure, but impose a
longer delay before encryption/decryption starts. The default is
10,000 for compatibility with OpenSSL's default.
The B<-hasher> argument is used in conjunction with the "pbkdf2" key
derivation option to pass the reference to an initialized
Crypt::PBKDF2::Hash object. If not provided, it defaults to the
OpenSSL-compatible hash function HMACSHA2 initialized with its default
options (SHA-256 hash).
The B<-header> argument specifies what type of header, if any, to
prepend to the beginning of the encrypted data stream. The header
allows Crypt::CBC to regenerate the original IV and correctly decrypt
the data without your having to provide the same IV used to encrypt
the data. Valid values for the B<-header> are:
"salt" -- Combine the passphrase with an 8-byte random value to
generate both the block cipher key and the IV from the
provided passphrase. The salt will be appended to the
beginning of the data stream allowing decryption to
regenerate both the key and IV given the correct passphrase.
This method is compatible with current versions of OpenSSL.
"randomiv" -- Generate the block cipher key from the passphrase, and
choose a random 8-byte value to use as the IV. The IV will
be prepended to the data stream. This method is compatible
with ciphertext produced by versions of the library prior to
2.17, but is incompatible with block ciphers that have non
8-byte block sizes, such as Rijndael. Crypt::CBC will exit
with a fatal error if you try to use this header mode with a
non 8-byte cipher. This header type is NOT secure and NOT
recommended.
"none" -- Do not generate a header. To decrypt a stream encrypted
in this way, you will have to provide the true key and IV
manually.
B<The "salt" header is now the default as of Crypt::CBC version 2.17. In
all earlier versions "randomiv" was the default.>
When using a "salt" header, you may specify your own value of the
salt, by passing the desired 8-byte character string to the B<-salt>
argument. Otherwise, the module will generate a random salt for
you. Crypt::CBC will generate a fatal error if you specify a salt
value that isn't exactly 8 bytes long. For backward compatibility
reasons, passing a value of "1" will generate a random salt, the same
as if no B<-salt> argument was provided.
The B<-padding> argument controls how the last few bytes of the
encrypted stream are dealt with when they not an exact multiple of the
cipher block length. The default is "standard", the method specified
in PKCS#5.
The B<-chaining_mode> argument will select among several different
lib/Crypt/CBC.pm view on Meta::CPAN
the property that if one block in the ciphertext message
is damaged, only that block and the next one will be
rendered un-decryptable.
'pcbc' -- Plaintext Cipher-Block Chaining mode. This has the property
that one damaged ciphertext block will render the
remainder of the message unreadable
'cfb' -- Cipher Feedback Mode. In this mode, both encryption and decryption
are performed using the block cipher's "encrypt" algorithm.
The error propagation behaviour is similar to CBC's.
'ofb' -- Output Feedback Mode. Similar to CFB, the block cipher's encrypt
algorithm is used for both encryption and decryption. If one bit
of the plaintext or ciphertext message is damaged, the damage is
confined to a single block of the corresponding ciphertext or
plaintext, and error correction algorithms can be used to reconstruct
the damaged part.
'ctr' -- Counter Mode. This mode uses a one-time "nonce" instead of
an IV. The nonce is incremented by one for each block of
lib/Crypt/CBC.pm view on Meta::CPAN
Passing a B<-pcbc> argument of true will have the same effect as
-chaining_mode=>'pcbc', and is included for backward
compatibility. [deprecated].
For more information on chaining modes, see
L<http://www.crypto-it.net/eng/theory/modes-of-block-ciphers.html>.
The B<-keysize> argument can be used to force the cipher's
keysize. This is useful for several of the newer algorithms, including
AES, ARIA, Blowfish, and CAMELLIA. If -keysize is not specified, then
Crypt::CBC will use the value returned by the cipher's max_keylength()
method. Note that versions of CBC::Crypt prior to 2.36 could also
allow you to set the blocksize, but this was never supported by any
ciphers and has been removed.
For compatibility with earlier versions of this module, you can
provide new() with a hashref containing key/value pairs. The key names
are the same as the arguments described earlier, but without the
initial hyphen. You may also call new() with one or two positional
arguments, in which case the first argument is taken to be the key and
the second to be the optional block cipher algorithm.
lib/Crypt/CBC.pm view on Meta::CPAN
$ciphertext = $cipher->crypt($plaintext);
After calling start(), you should call crypt() as many times as
necessary to encrypt the desired data.
=head2 finish()
$ciphertext = $cipher->finish();
The CBC algorithm must buffer data blocks internally until they are
even multiples of the encryption algorithm's blocksize (typically 8
bytes). After the last call to crypt() you should call finish().
This flushes the internal buffer and returns any leftover ciphertext.
In a typical application you will read the plaintext from a file or
input stream and write the result to standard output in a loop that
might look like this:
$cipher = new Crypt::CBC('hey jude!');
$cipher->start('encrypting');
print $cipher->crypt($_) while <>;
print $cipher->finish();
=head2 encrypt()
$ciphertext = $cipher->encrypt($plaintext)
This convenience function runs the entire sequence of start(), crypt()
and finish() for you, processing the provided plaintext and returning
lib/Crypt/CBC.pm view on Meta::CPAN
=head2 filehandle()
This method returns a filehandle for transparent encryption or
decryption using Christopher Dunkle's excellent L<Crypt::FileHandle>
module. This module must be installed in order to use this method.
filehandle() can be called as a class method using the same arguments
as new():
$fh = Crypt::CBC->filehandle(-cipher=> 'Blowfish',
-pass => "You'll never guess");
or on a previously-created Crypt::CBC object:
$cbc = Crypt::CBC->new(-cipher=> 'Blowfish',
-pass => "You'll never guess");
$fh = $cbc->filehandle;
The filehandle can then be opened using the familiar open() syntax.
Printing to a filehandle opened for writing will encrypt the
data. Filehandles opened for input will be decrypted.
Here is an example:
# transparent encryption
lib/Crypt/CBC.pm view on Meta::CPAN
bytes, then a whole block of "0808080808080808" is appended.
oneandzeroes: Binary safe
pads with "80" followed by as many "00" necessary to fill the
block. If the last block is a full block and blocksize is 8, a
block of "8000000000000000" will be appended.
rijndael_compat: Binary safe, with caveats
similar to oneandzeroes, except that no padding is performed if
the last block is a full block. This is provided for
compatibility with Crypt::Rijndael's buit-in MODE_CBC.
Note that Crypt::Rijndael's implementation of CBC only
works with messages that are even multiples of 16 bytes.
null: text only
pads with as many "00" necessary to fill the block. If the last
block is a full block and blocksize is 8, a block of
"0000000000000000" will be appended.
space: text only
same as "null", but with "20".
none:
no padding added. Useful for special-purpose applications where
you wish to add custom padding to the message.
Both the standard and oneandzeroes paddings are binary safe. The
space and null paddings are recommended only for text data. Which
type of padding you use depends on whether you wish to communicate
with an external (non Crypt::CBC library). If this is the case, use
whatever padding method is compatible.
You can also pass in a custom padding function. To do this, create a
function that takes the arguments:
$padded_block = function($block,$blocksize,$direction);
where $block is the current block of data, $blocksize is the size to
pad it to, $direction is "e" for encrypting and "d" for decrypting,
and $padded_block is the result after padding or depadding.
When encrypting, the function should always return a string of
<blocksize> length, and when decrypting, can expect the string coming
in to always be that length. See _standard_padding(), _space_padding(),
_null_padding(), or _oneandzeroes_padding() in the source for examples.
Standard and oneandzeroes padding are recommended, as both space and
null padding can potentially truncate more characters than they should.
=head1 Comparison to Crypt::Mode::CBC
The L<CryptX> modules L<Crypt::Mode::CBC>, L<Crypt::Mode::OFB>,
L<Crypt::Mode::CFB>, and L<Crypt::Mode::CTR> provide fast
implementations of the respective cipherblock chaining modes (roughly
5x the speed of Crypt::CBC). Crypt::CBC was designed to encrypt and
decrypt messages in a manner compatible with OpenSSL's "enc"
function. Hence it handles the derivation of the key and IV from a
passphrase using the same conventions as OpenSSL, and it writes out an
OpenSSL-compatible header in the encrypted message in a manner that
allows the key and IV to be regenerated during decryption.
In contrast, the CryptX modules do not automatically derive the key
and IV from a passphrase or write out an encrypted header. You will
need to derive and store the key and IV by other means (e.g. with
CryptX's Crypt::KeyDerivation module, or with Crypt::PBKDF2).
=head1 EXAMPLES
Three examples, aes.pl, des.pl and idea.pl can be found in the eg/
subdirectory of the Crypt-CBC distribution. These implement
command-line DES and IDEA encryption algorithms using default
parameters, and should be compatible with recent versions of
OpenSSL. Note that aes.pl uses the "pbkdf2" key derivation function to
generate its keys. The other two were distributed with pre-PBKDF2
versions of Crypt::CBC, and use the older "opensslv1" algorithm.
=head1 LIMITATIONS
The encryption and decryption process is about a tenth the speed of
the equivalent OpenSSL tool and about a fifth of the Crypt::Mode::CBC
module (both which use compiled C).
=head1 BUGS
Please report them.
=head1 AUTHOR
Lincoln Stein, lstein@cshl.org
lib/Crypt/CBC/PBKDF.pm view on Meta::CPAN
package Crypt::CBC::PBKDF;
our $VERSION = '3.07';
# just a virtual base class for passphrase=>key derivation functions
use strict;
use File::Basename 'dirname','basename';
use Carp 'croak';
sub new {
my $class = shift;
my $subclass = shift;
lib/Crypt/CBC/PBKDF/none.pm view on Meta::CPAN
package Crypt::CBC::PBKDF::none;
use strict;
use Carp 'croak';
use base 'Crypt::CBC::PBKDF::opensslv1';
our $VERSION = '3.07';
# options:
# key_len => 32 default
# iv_len => 16 default
sub generate_hash {
my $self = shift;
my ($salt,$passphrase) = @_;
# ALERT: in this case passphrase IS the key and the salt is ignored
lib/Crypt/CBC/PBKDF/opensslv1.pm view on Meta::CPAN
package Crypt::CBC::PBKDF::opensslv1;
use strict;
use base 'Crypt::CBC::PBKDF';
use Digest::MD5 'md5';
our $VERSION = '3.07';
# options:
# salt_len => 8 default
# key_len => 32 default
# iv_len => 16 default
sub create {
my $class = shift;
lib/Crypt/CBC/PBKDF/opensslv2.pm view on Meta::CPAN
package Crypt::CBC::PBKDF::opensslv2;
use strict;
use base 'Crypt::CBC::PBKDF::opensslv1';
use Digest::SHA 'sha256';
our $VERSION = '3.07';
# options:
# key_len => 32 default
# iv_len => 16 default
sub generate_hash {
my $self = shift;
my ($salt,$passphrase) = @_;
lib/Crypt/CBC/PBKDF/pbkdf2.pm view on Meta::CPAN
package Crypt::CBC::PBKDF::pbkdf2;
use strict;
use base 'Crypt::CBC::PBKDF';
use Crypt::PBKDF2;
our $VERSION = '3.07';
# options:
# key_len => 32 default
# iv_len => 16 default
# iterations => 10000 default
# hash_class => 'HMACSHA2' default
sub create {
lib/Crypt/CBC/PBKDF/randomiv.pm view on Meta::CPAN
package Crypt::CBC::PBKDF::randomiv;
# This is for compatibility with early (pre v1.0) versions of OpenSSL
# THE KEYS GENERATED BY THIS ALGORITHM ARE INSECURE!!!
use strict;
use base 'Crypt::CBC::PBKDF';
use Digest::MD5 'md5';
our $VERSION = '3.07';
# options:
# salt_len => 8 default
# key_len => 32 default
# iv_len => 16 default
sub create {
my $class = shift;
lib/Crypt/CBC/PBKDF/randomiv.pm view on Meta::CPAN
sub generate_hash {
my $self = shift;
my ($salt,$passphrase) = @_;
my $desired_len = $self->{key_len};
my $material = md5($passphrase);
while (length($material) < $desired_len) {
$material .= md5($material);
}
substr($material,$desired_len) = '';
$material .= Crypt::CBC->_get_random_bytes($self->{iv_len});
return $material;
}
1;
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-pass=>'secret',
-cipher => 'Cipher::AES',
-pbkdf => 'pbkdf2'
),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
t/Blowfish.t view on Meta::CPAN
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-pass=>'secret',-cipher=>'Blowfish',-nodeprecate=>1),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
test(5+$c,$i->decrypt($i->encrypt($test_data)) eq $test_data);
}
t/Blowfish_PP.t view on Meta::CPAN
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-pass=>'secret',-cipher=>'Blowfish_PP',-nodeprecate=>1),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
test(5+$c,$i->decrypt($i->encrypt($test_data)) eq $test_data);
}
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new({key=>'secret',cipher=>'CAST5',nodeprecate=>1}),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
test(5+$c,$i->decrypt($i->encrypt($test_data)) eq $test_data);
}
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a big hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-key=>'secret',
-cipher => 'Cipher::AES',
-chain_mode => 'ctr',
-pbkdf => 'opensslv2'
),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-pass=>'secret',-cipher=>'DES',-pbkdf=>'pbkdf2'),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
test(5+$c,$i->decrypt($i->encrypt($test_data)) eq $test_data);
}
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-pass=>'secret',
-cipher=>'IDEA',
-nodeprecate=>1,
),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a big hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-key => 'secret',
-cipher => 'Cipher::AES',
-chain_mode => 'ofb',
-pbkdf => 'opensslv2',
),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-key=>'secret',
-cipher=>'Cipher::AES',
-chain_mode => 'pcbc',
-pbkdf => 'pbkdf2',
),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
t/Rijndael.t view on Meta::CPAN
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-pass=>'secret',-cipher=>'Rijndael',-pbkdf=>'opensslv2'),"Couldn't create new object");
test(3,$c = $i->encrypt($test_data),"Couldn't encrypt");
test(4,$p = $i->decrypt($c),"Couldn't decrypt");
test(5,$p eq $test_data,"Decrypted ciphertext doesn't match plaintext");
# now try various truncations of the whole
for (my $c=1;$c<=7;$c++) {
substr($test_data,-$c) = ''; # truncate
test(5+$c,$i->decrypt($i->encrypt($test_data)) eq $test_data);
}
t/Rijndael_compat.t view on Meta::CPAN
}
$test_data = <<END;
Mary had a little lamb,
Its fleece was black as coal,
And everywere that Mary went,
That lamb would dig a hole.
END
;
eval "use Crypt::CBC";
my $bs = Crypt::Rijndael->blocksize;
my $ks = Crypt::Rijndael->keysize;
test(1,!$@,"Couldn't load module");
test(2,$i = Crypt::CBC->new(-key => 'a' x $ks,
-cipher => 'Rijndael',
-iv => 'f' x $bs,
-pbkdf => 'none',
-header => 'none',
-padding => 'rijndael_compat',
),
"Couldn't create new object");
test(3,$j = Crypt::Rijndael->new('a' x $ks, Crypt::Rijndael->MODE_CBC),
"Couldn't create new object");
test(4,$j->set_iv('f' x $bs));
test(5,$i->decrypt($i->encrypt($test_data)) eq $j->decrypt($j->encrypt($test_data)),"Decrypt doesn't match");
test(6,$i->decrypt($j->encrypt($test_data)) eq $test_data,"Crypt::CBC can't decrypt Rijndael encryption");
test(7,$j->decrypt($i->encrypt($test_data)) eq $test_data,"Rijndael can't decrypt Crypt::CBC encryption");
# now try various truncations of the whole
my $t = $test_data;
for (my $c=1;$c<=7;$c++) {
substr($t,-$c) = ''; # truncate
test(7+$c,$t eq pad($i->decrypt($j->encrypt(pad($t,'e'))),'d'),"Crypt::CBC can't decrypt Rijndael encryption");
}
$t = $test_data;
for (my $c=1;$c<=7;$c++) {
substr($t,-$c) = ''; # truncate
test(14+$c,$t eq pad($j->decrypt($i->encrypt(pad($t,'e'))),'d'),"Rijndael can't decrypt Crypt::CBC encryption");
}
# now try various short strings
for (my $c=0;$c<=18;$c++) {
my $t = 'i' x $c;
test(22+$c,$t eq pad($j->decrypt($i->encrypt(pad($t,'e'))),'d'),"Rijndael can't decrypt Crypt::CBC encryption");
}
# now try various short strings
for (my $c=0;$c<=18;$c++) {
my $t = 'i' x $c;
test(41+$c,$t eq pad($j->decrypt($i->encrypt(pad($t,'e'))),'d'),"Rijndael can't decrypt Crypt::CBC encryption");
}