diff options
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Crypt/RSA.pm')
-rwxr-xr-x | Master/tlpkg/tlperl/lib/Crypt/RSA.pm | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/Crypt/RSA.pm b/Master/tlpkg/tlperl/lib/Crypt/RSA.pm new file mode 100755 index 00000000000..5a3d3bcfb9e --- /dev/null +++ b/Master/tlpkg/tlperl/lib/Crypt/RSA.pm @@ -0,0 +1,617 @@ +#!/usr/bin/perl -sw +## +## Crypt::RSA - Pure-perl implementation of RSA encryption/signing +## algorithms. +## +## Copyright (c) 2000-2001, Vipul Ved Prakash. All rights reserved. +## This code is free software; you can redistribute it and/or modify +## it under the same terms as Perl itself. +## +## $Id: RSA.pm,v 1.48 2001/09/25 12:44:55 vipul Exp $ + +package Crypt::RSA; +use FindBin qw($Bin); +use lib "$Bin/../../lib"; +use strict; +use base 'Class::Loader'; +use base 'Crypt::RSA::Errorhandler'; +use Crypt::RSA::Key; +use Crypt::RSA::DataFormat qw(steak octet_len); +use Convert::ASCII::Armour; +use Carp; + +$Crypt::RSA::VERSION = '1.99'; # change this elsewhere too! + +my %DEFAULTS = ( + 'ES' => { Name => 'OAEP_ES' }, + 'SS' => { Name => 'PSS_SS' }, + 'PP' => { Name => 'ASCII_PP' }, +); + + +my %KNOWNMAP = ( + + # ENCRYPTION SCHEMES + + OAEP_ES => { Module => "Crypt::RSA::ES::OAEP" }, + PKCS1v21_ES => { Module => "Crypt::RSA::ES::OAEP" }, + PKCS1v15_ES => { Module => "Crypt::RSA::ES::PKCS1v15" }, + + # SIGNATURE SCHEMES + + PSS_SS => { Module => "Crypt::RSA::SS::PSS" }, + PKCS1v21_SS => { Module => "Crypt::RSA::SS::PSS" }, + PKCS1v15_SS => { Module => "Crypt::RSA::SS::PKCS1v15" }, + + # POST PROCESSORS + + ASCII_PP => { Module => "Convert::ASCII::Armour" }, + +); + + +sub new { + + my ($class, %params) = @_; + my %self = (%DEFAULTS, %params); + my $self = bless \%self, $class; + + $self->_storemap (%KNOWNMAP); + + for (qw(ES SS PP)) { + $$self{$_} = { Name => $$self{$_} . "_$_" } unless ref $$self{$_}; + $$self{lc($_)} = $self->_load ( %{$$self{$_}} ); + } + + $$self{keychain} = new Crypt::RSA::Key; + + return bless \%self, $class; + +} + + +sub keygen { + + my ($self, %params) = @_; + $params{KF} = $$self{KF} if $$self{KF}; + + my @keys; + return (@keys = $self->{keychain}->generate (%params)) + ? @keys + : $self->error ($self->{keychain}->errstr); + +} + + +sub encrypt { + + my ($self, %params) = @_; + my $plaintext = $params{Message} || $params{Plaintext}; + my $key = $params{Key}; + + return $self->error ($key->errstr, \%params, $key, \$plaintext) + unless $key->check(); + + my $blocksize = blocksize ( $$self{es}->encryptblock (Key => $key), + length($plaintext) + ); + + return $self->error("Message too long.", \$key, \%params) if $blocksize <= 0; + + my $cyphertext; + my @segments = steak ($plaintext, $blocksize); + for (@segments) { + $cyphertext .= $self->{es}->encrypt (Message => $_, Key => $key) + || return $self->error ($self->{es}->errstr, \$key, \%params); + } + + if ($params{Armour} || $params{Armor}) { + $cyphertext = $self->{pp}->armour ( + Object => 'RSA ENCRYPTED MESSAGE', + Headers => { + Scheme => $$self{ES}{Module} || ${$KNOWNMAP{$$self{ES}{Name}}}{Module}, + Version => $self->{es}->version() + }, + Content => { Cyphertext => $cyphertext }, + Compress => 1, + ); + } + + return $cyphertext; + +} + + +sub decrypt { + + my ($self , %params) = @_; + my $cyphertext = $params{Cyphertext} || $params{Ciphertext}; + my $key = $params{Key}; + + return $self->error ($key->errstr, \%params, $key) unless $key->check(); + + if ($params{Armour} || $params{Armor}) { + my $decoded = $self->{pp}->unarmour ($cyphertext) || + return $self->error ($self->{pp}->errstr()); + $cyphertext = $$decoded{Content}{Cyphertext} + } + + my $plaintext; + my $blocksize = blocksize ( $$self{es}->decryptblock (Key => $key), + length($cyphertext) + ); + + return $self->error("Message too long.") if $blocksize <= 0; + + my @segments = steak ($cyphertext, $blocksize); + for (@segments) { + $plaintext .= $self->{es}->decrypt (Cyphertext=> $_, Key => $key) + || return $self->error ($self->{es}->errstr, \$key, \%params); + } + + return $plaintext; + +} + + +sub sign { + + my ($self, %params) = @_; + my $signature = $self->{ss}->sign (%params) + || return $self->error ($self->{ss}->errstr, + $params{Key}, \%params); + + if ($params{Armour} || $params{Armor}) { + $signature = $self->{pp}->armour ( + Object => "RSA SIGNATURE", + Headers => { + Scheme => $$self{SS}{Module} || ${$KNOWNMAP{$$self{SS}{Name}}}{Module}, + Version => $self->{ss}->version() }, + Content => { Signature => $signature }, + ); + } + + return $signature; + +} + + +sub verify { + + my ($self, %params) = @_; + + if ($params{Armour} || $params{Armor}) { + my $decoded = $self->{pp}->unarmour ($params{Signature}) || + return $self->error ($self->{pp}->errstr()); + $params{Signature} = $$decoded{Content}{Signature} + } + + my $verify = $self->{ss}->verify (%params) || + return $self->error ($self->{ss}->errstr, $params{Key}, \%params); + + return $verify; + +} + + +sub blocksize { + + my ($blocksize, $ptsize) = @_; + return $ptsize if $blocksize == -1; + return 0 if $blocksize < 1; + return $blocksize; + +} + +1; + + +=head1 NAME + +Crypt::RSA - RSA public-key cryptosystem. + +=head1 SYNOPSIS + + my $rsa = new Crypt::RSA; + + my ($public, $private) = + $rsa->keygen ( + Identity => 'Lord Macbeth <macbeth@glamis.com>', + Size => 1024, + Password => 'A day so foul & fair', + Verbosity => 1, + ) or die $rsa->errstr(); + + + my $cyphertext = + $rsa->encrypt ( + Message => $message, + Key => $public, + Armour => 1, + ) || die $rsa->errstr(); + + + my $plaintext = + $rsa->decrypt ( + Cyphertext => $cyphertext, + Key => $private, + Armour => 1, + ) || die $rsa->errstr(); + + + my $signature = + $rsa->sign ( + Message => $message, + Key => $private + ) || die $rsa->errstr(); + + + my $verify = + $rsa->verify ( + Message => $message, + Signature => $signature, + Key => $public + ) || die $rsa->errstr(); + +=head1 NOTE + +This manual assumes familiarity with public-key cryptography and the RSA +algorithm. If you don't know what these are or how they work, please refer +to the sci.crypt FAQ[15]. A formal treatment of RSA can be found in [1]. + +=head1 DESCRIPTION + +Crypt::RSA is a pure-perl, cleanroom implementation of the RSA public-key +cryptosystem. It uses Math::Pari(3), a perl interface to the blazingly +fast PARI library, for big integer arithmetic and number theoretic +computations. + +Crypt::RSA provides arbitrary size key-pair generation, plaintext-aware +encryption (OAEP) and digital signatures with appendix (PSS). For +compatibility with SSLv3, RSAREF2, PGP and other applications that follow +the PKCS #1 v1.5 standard, it also provides PKCS #1 v1.5 encryption and +signatures. + +Crypt::RSA is structured as bundle of modules that encapsulate different +parts of the RSA cryptosystem. The RSA algorithm is implemented in +Crypt::RSA::Primitives(3). Encryption schemes, located under +Crypt::RSA::ES, and signature schemes, located under Crypt::RSA::SS, use +the RSA algorithm to build encryption/signature schemes that employ secure +padding. (See the note on Security of Padding Schemes.) + +The key generation engine and other functions that work on both components +of the key-pair are encapsulated in Crypt::RSA::Key(3). +Crypt::RSA::Key::Public(3) & Crypt::RSA::Key::Private(3) provide +mechanisms for storage & retrival of keys from disk, decoding & encoding +of keys in certain formats, and secure representation of keys in memory. +Finally, the Crypt::RSA module provides a convenient, DWIM wrapper around +the rest of the modules in the bundle. + +=head1 SECURITY OF PADDING SCHEMES + +It has been conclusively shown that textbook RSA is insecure[3,7]. Secure +RSA requires that plaintext is padded in a specific manner before +encryption and signing. There are four main standards for padding: PKCS +#1 v1.5 encryption & signatures, and OAEP encryption & PSS signatures. +Crypt::RSA implements these as four modules that +provide overloaded encrypt(), decrypt(), sign() and verify() methods that +add padding functionality to the basic RSA operations. + +Crypt::RSA::ES::PKCS1v15(3) implements PKCS #1 v1.5 encryption, +Crypt::RSA::SS::PKCS1v15(3) implements PKCS #1 v1.5 signatures, +Crypt::RSA::ES::OAEP(3) implements Optimal Asymmetric Encryption and +Crypt::RSA::SS::PSS(3) Probabilistic Signatures. + +PKCS #1 v1.5 schemes are older and hence more widely deployed, but PKCS #1 +v1.5 encryption has certain flaws that make it vulnerable to +chosen-cyphertext attacks[9]. Even though Crypt::RSA works around these +vulnerabilities, it is recommended that new applications use OAEP and PSS, +both of which are provably secure[13]. In any event, +Crypt::RSA::Primitives (without padding) should never be used directly. + +That said, there exists a scheme called Simple RSA[16] that provides +security without padding. However, Crypt::RSA doesn't implement this +scheme yet. + +=head1 METHODS + +=over 4 + +=item B<new()> + +The constructor. When no arguments are provided, new() returns an object +loaded with default values. This object can be customized by specifying +encryption & signature schemes, key formats and post processors. For +details see the section on B<Customizing the Crypt::RSA +object> later in this manpage. + +=item B<keygen()> + +keygen() generates and returns an RSA key-pair of specified bitsize. +keygen() is a synonym for Crypt::RSA::Key::generate(). Parameters and +return values are described in the Crypt::RSA::Key(3) manpage. + +=item B<encrypt()> + +encrypt() performs RSA encryption on a string of arbitrary length with a +public key using the encryption scheme bound to the object. The default +scheme is OAEP. encrypt() returns cyphertext (a string) on success and +undef on failure. It takes a hash as argument with following keys: + +=over 4 + +=item B<Message> + +An arbitrary length string to be encrypted. + +=item B<Key> + +Public key of the recipient, a Crypt::RSA::Key::Public(3) or +compatible object. + +=item B<Armour> + +A boolean parameter that forces cyphertext through a post processor after +encrpytion. The default post processor is Convert::ASCII::Armour(3) that +encodes binary octets in 6-bit clean ASCII messages. The cyphertext is +returned as-is, when the Armour key is not present. + +=back + +=item B<decrypt()> + +decrypt() performs RSA decryption with a private key using the encryption +scheme bound to the object. The default scheme is OAEP. decrypt() returns +plaintext on success and undef on failure. It takes a hash as argument +with following keys: + +=over 4 + +=item B<Cyphertext> + +Cyphertext of arbitrary length. + +=item B<Key> + +Private key, a Crypt::RSA::Key::Private(3) or compatible object. + +=item B<Armour> + +Boolean parameter that specifies whether the Cyphertext is encoded with a +post processor. + +=back + +=item B<sign()> + +sign() creates an RSA signature on a string with a private key using the +signature scheme bound to the object. The default scheme is +PSS. sign() returns a signature on success and undef on failure. It takes +a hash as argument with following keys: + +=over 4 + +=item B<Message> + +A string of arbitrary length to be signed. + +=item B<Key> + +Private key of the sender, a Crypt::RSA::Key::Private(3) or +compatible object. + +=item B<Armour> + +A boolean parameter that forces the computed signature to be post +processed. + +=back + +=item B<verify()> + +verify() verifies an RSA signature with a public key using the signature +scheme bound to the object. The default scheme is PSS. verify() returns a +true value on success and undef on failure. It takes a hash as argument +with following keys: + +=over 4 + +=item B<Message> + +A signed message, a string of arbitrary length. + +=item B<Key> + +Public key of the signer, a Crypt::RSA::Key::Public(3) or +compatible object. + +=item B<Sign> + +A signature computed with sign(). + +=item B<Armour> + +Boolean parameter that specifies whether the Signature has been +post processed. + +=back + +=back + +=head1 MODULES + +Apart from Crypt::RSA, the following modules are intended for application +developer and end-user consumption: + +=over 4 + +=item B<Crypt::RSA::Key> + +RSA key pair generator. + +=item B<Crypt::RSA::Key::Public> + +RSA Public Key Management. + +=item B<Crypt::RSA::Key::Private> + +RSA Private Key Management. + +=item B<Crypt::RSA::ES::OAEP> + +Plaintext-aware encryption with RSA. + +=item B<Crypt::RSA::SS::PSS> + +Probabilistic Signature Scheme based on RSA. + +=item B<Crypt::RSA::ES::PKCS1v15> + +PKCS #1 v1.5 encryption scheme. + +=item B<Crypt::RSA::SS::PKCS1v15> + +PKCS #1 v1.5 signature scheme. + +=back + +=head1 CUSTOMISING A CRYPT::RSA OBJECT + +A Crypt::RSA object can be customized by passing any of the following keys +in a hash to new(): ES to specify the encryption scheme, SS to specify the +signature scheme, PP to specify the post processor, and KF to specify the +key format. The value associated with these keys can either be a name (a +string) or a hash reference that specifies a module name, its constructor, +and constructor arguments. For example: + + my $rsa = new Crypt::RSA ( ES => 'OAEP' ); + + or + + my $rsa = new Crypt::RSA ( ES => { Module => 'Crypt::RSA::ES::OAEP' } ); + +A module thus specified need not be included in the Crypt::RSA bundle, but +it must be interface compatible with the ones provided with Crypt::RSA. + +As of this writing, the following names are recognised: + +=over 4 + +=item B<ES> (Encryption Scheme) + + 'OAEP', 'PKCS1v15' + +=item B<SS> (Signature Scheme) + + 'PSS', 'PKCS1v15' + +=item B<KF> (Key Format) + + 'Native', 'SSH' + +=item B<PP> (Post Processor) + + 'ASCII' + +=back + +=head1 ERROR HANDLING + +All modules in the Crypt::RSA bundle use a common error handling method +(implemented in Crypt::RSA::Errorhandler(3)). When a method fails it +returns undef and calls $self->error() with the error message. This error +message is available to the caller through the errstr() method. For more +details see the Crypt::RSA::Errorhandler(3) manpage. + +=head1 AUTHOR + +Vipul Ved Prakash, E<lt>mail@vipul.netE<gt> + +=head1 ACKNOWLEDGEMENTS + +Thanks to Ilya Zakharevich for help with Math::Pari, Benjamin Trott for +several patches including SSH key support, Genèche Ramanoudjame for +extensive testing and numerous bug reports, Shizukesa on #perl for +suggesting the error handling method used in this module, and Dave Paris +for good advice. + +=head1 LICENSE + +Copyright (c) 2000-2008, Vipul Ved Prakash. This code is free software; +it is distributed under the same license as Perl itself. + +I have received requests for commercial licenses of +Crypt::RSA, from those who desire contractual support and +indemnification. I'd be happy to provide a commercial license +if you need one. Please send me mail at C<mail@vipul.net> with +the subject "Crypt::RSA license". Please don't send me mail +asking if you need a commercial license. You don't, if +Artistic of GPL suit you fine. + +=head1 SEE ALSO + +Crypt::RSA::Primitives(3), Crypt::RSA::DataFormat(3), +Crypt::RSA::Errorhandler(3), Crypt::RSA::Debug(3), Crypt::Primes(3), +Crypt::Random(3), Crypt::CBC(3), Crypt::Blowfish(3), +Tie::EncryptedHash(3), Convert::ASCII::Armour(3), Math::Pari(3), +Class::Loader(3), crypt-rsa-interoperability(3), +crypt-rsa-interoperability-table(3). + +=head1 REPORTING BUGS + +All bug reports related to Crypt::RSA should go to rt.cpan.org +at C<http://rt.cpan.org/Dist/Display.html?Queue=Crypt-RSA> + +Crypt::RSA is considered to be stable. If you are running into a +problem, it's likely of your own making. Please check your code +and consult the documentation before posting a bug report. A +google search with the error message might also shed light if it +is a common mistake that you've made. + +If the module installation fails with a "Segmentation Fault" or +"Bus Error", it is likely a Math::Pari issue. Please consult +Math::Pari bugs on rt.cpan.org or open a bug there. There have +been known issues on HP-UX and SunOS systems (with Math::Pari), +so if you are on those OSes, please consult Math::Pari +resources before opening a Crypt::RSA bug. + +=head1 BIBLIOGRAPHY + +Chronologically sorted (for the most part). + +=over 4 + +=item 1 B<R. Rivest, A. Shamir, L. Aldeman.> A Method for Obtaining Digital Signatures and Public-Key Cryptosystems (1978). + +=item 2 B<U. Maurer.> Fast Generation of Prime Numbers and Secure Public-Key Cryptographic Parameters (1994). + +=item 3 B<M. Bellare, P. Rogaway.> Optimal Asymmetric Encryption - How to Encrypt with RSA (1995). + +=item 4 B<M. Bellare, P. Rogaway.> The Exact Security of Digital Signatures - How to sign with RSA and Rabin (1996). + +=item 5 B<B. Schneier.> Applied Cryptography, Second Edition (1996). + +=item 6 B<A. Menezes, P. Oorschot, S. Vanstone.> Handbook of Applied Cryptography (1997). + +=item 7 B<D. Boneh.> Twenty Years of Attacks on the RSA Cryptosystem (1998). + +=item 8 B<D. Bleichenbacher, M. Joye, J. Quisquater.> A New and Optimal Chosen-message Attack on RSA-type Cryptosystems (1998). + +=item 9 B<B. Kaliski, J. Staddon.> Recent Results on PKCS #1: RSA Encryption Standard, RSA Labs Bulletin Number 7 (1998). + +=item 10 B<B. Kaliski, J. Staddon.> PKCS #1: RSA Cryptography Specifications v2.0, RFC 2437 (1998). + +=item 11 B<SSH Communications Security.> SSH 1.2.7 source code (1998). + +=item 12 B<S. Simpson.> PGP DH vs. RSA FAQ v1.5 (1999). + +=item 13 B<RSA Laboratories.> Draft I, PKCS #1 v2.1: RSA Cryptography Standard (1999). + +=item 14 B<E. Young, T. Hudson, OpenSSL Team.> OpenSSL 0.9.5a source code (2000). + +=item 15 B<Several Authors.> The sci.crypt FAQ at +http://www.faqs.org/faqs/cryptography-faq/part01/index.html + +=item 16 B<Victor Shoup.> A Proposal for an ISO Standard for Public Key Encryption (2001). + +=cut |