LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+
+
+Except below.
+
+- extlib/Crypt/Camellia_PP.pm
+ http://search.cpan.org/~oyama/Crypt-Camellia_PP-0.02/
+
+- mt-static/plugins/Lovers/js/CryptoCipherCamellia.js
+ http://alpha.mixi.co.jp/dist/CryptoCipherCamellia-js-1.0.2/
+
+- extlib/Crypt/CBC.pm
+ http://search.cpan.org/dist/Crypt-CBC/
+
+These files are licensed under the which own license.
#Localization
l10n_class: Lovers::L10N
+schema_version: 2
+object_types:
+ love_letter: Lovers::LoveLetter
+
#tag
tags:
help_url: http://mt-acme.sourceforge.jp/lovers/tags#%t
+ function:
+ LoveLetterResponse: Lovers::App::_hdlr_love_letter_response
+ LoveLetterOK: Lovers::App::_hdlr_love_letter_ok
+ LoveLetterCancel: Lovers::App::_hdlr_love_letter_cancel
+
block:
LoversPopularWith: Lovers::App::_hdlr_popular_with
Mote: Lovers::App::_hdlr_popular_with
-
-callbacks:
- MT::App::CMS::template_source.rebuilding: Lovers::App::source_rebuilding
- *::pre_build: Lovers::App::pre_build
- *::post_build: Lovers::App::post_build
+ LoveLetter: Lovers::App::_hdlr_love_letter
+ IfLoveLetterOK: Lovers::App::_hdlr_if_love_letter_ok
+ IfLoveLetterCancel: Lovers::App::_hdlr_if_love_letter_cancel
applications:
cms:
methods:
- lovers_icon: Lovers::App::icon
+ love_letter:
+ code: Lovers::App::app_love_letter
+ requires_login: 0
+
+callbacks:
+ MT::App::CMS::template_source.rebuilding: Lovers::App::source_rebuilding
+ *::post_build: Lovers::App::post_build
--- /dev/null
+package Crypt::CBC;
+
+use Digest::MD5 'md5';
+use Carp;
+use strict;
+use bytes;
+use vars qw($VERSION);
+$VERSION = '2.30';
+
+use constant RANDOM_DEVICE => '/dev/urandom';
+
+sub new {
+ my $class = shift;
+
+ my $options = {};
+
+ # hashref arguments
+ if (ref $_[0] eq 'HASH') {
+ $options = shift;
+ }
+
+ # CGI style arguments
+ elsif ($_[0] =~ /^-[a-zA-Z_]{1,20}$/) {
+ my %tmp = @_;
+ while ( my($key,$value) = each %tmp) {
+ $key =~ s/^-//;
+ $options->{lc $key} = $value;
+ }
+ }
+
+ else {
+ $options->{key} = shift;
+ $options->{cipher} = shift;
+ }
+
+ my $cipher_object_provided = $options->{cipher} && ref $options->{cipher};
+
+ # "key" is a misnomer here, because it is actually usually a passphrase that is used
+ # to derive the true key
+ my $pass = $options->{key};
+
+ if ($cipher_object_provided) {
+ carp "Both a key and a pre-initialized Crypt::* object were passed. The key will be ignored"
+ if defined $pass;
+ $pass ||= '';
+ }
+ elsif (!defined $pass) {
+ croak "Please provide an encryption/decryption passphrase or key using -key"
+ }
+
+ # header mode
+ my %valid_modes = map {$_=>1} qw(none salt randomiv);
+ my $header_mode = $options->{header};
+ $header_mode ||= 'none' if exists $options->{prepend_iv} && !$options->{prepend_iv};
+ $header_mode ||= 'none' if exists $options->{add_header} && !$options->{add_header};
+ $header_mode ||= 'salt'; # default
+ croak "Invalid -header mode '$header_mode'" unless $valid_modes{$header_mode};
+
+ croak "The -salt argument is incompatible with a -header mode of $header_mode"
+ if exists $options->{salt} && $header_mode ne 'salt';
+
+ my $cipher = $options->{cipher};
+ $cipher = 'Crypt::DES' unless $cipher;
+ my $cipherclass = ref $cipher || $cipher;
+
+ unless (ref $cipher) { # munge the class name if no object passed
+ $cipher = $cipher=~/^Crypt::/ ? $cipher : "Crypt::$cipher";
+ $cipher->can('encrypt') or eval "require $cipher; 1" or croak "Couldn't load $cipher: $@";
+ # some crypt modules use the class Crypt::, and others don't
+ $cipher =~ s/^Crypt::// unless $cipher->can('keysize');
+ }
+
+ # allow user to override these values
+ my $ks = $options->{keysize};
+ my $bs = $options->{blocksize};
+
+ # otherwise we get the values from the cipher
+ $ks ||= eval {$cipher->keysize};
+ $bs ||= eval {$cipher->blocksize};
+
+ # Some of the cipher modules are busted and don't report the
+ # keysize (well, Crypt::Blowfish in any case). If we detect
+ # this, and find the blowfish module in use, then assume 56.
+ # Otherwise assume the least common denominator of 8.
+ $ks ||= $cipherclass =~ /blowfish/i ? 56 : 8;
+ $bs ||= $ks;
+
+ my $pcbc = $options->{'pcbc'};
+
+ # Default behavior is to treat -key as a passphrase.
+ # But if the literal_key option is true, then use key as is
+ croak "The options -literal_key and -regenerate_key are incompatible with each other"
+ if exists $options->{literal_key} && exists $options->{regenerate_key};
+ my $key;
+ $key = $pass if $options->{literal_key};
+ $key = $pass if exists $options->{regenerate_key} && !$options->{regenerate_key};
+
+ # Get the salt.
+ my $salt = $options->{salt};
+ my $random_salt = 1 unless defined $salt && $salt ne '1';
+ croak "Argument to -salt must be exactly 8 bytes long" if defined $salt && length $salt != 8 && $salt ne '1';
+
+ # note: iv will be autogenerated by start() if not specified in options
+ my $iv = $options->{iv};
+ my $random_iv = 1 unless defined $iv;
+ croak "Initialization vector must be exactly $bs bytes long when using the $cipherclass cipher" if defined $iv and length($iv) != $bs;
+
+ my $literal_key = $options->{literal_key} || (exists $options->{regenerate_key} && !$options->{regenerate_key});
+ my $legacy_hack = $options->{insecure_legacy_decrypt};
+ my $padding = $options->{padding} || 'standard';
+
+ if ($padding && ref($padding) eq 'CODE') {
+ # check to see that this code does its padding correctly
+ for my $i (1..$bs-1) {
+ my $rbs = length($padding->(" "x$i,$bs,'e'));
+ croak "padding method callback does not behave properly: expected $bs bytes back, got $rbs bytes back."
+ unless ($rbs == $bs);
+ }
+ } else {
+ $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.";
+ }
+
+ # CONSISTENCY CHECKS
+ # HEADER consistency
+ if ($header_mode eq 'salt') {
+ croak "Cannot use salt-based key generation if literal key is specified"
+ if $options->{literal_key};
+ croak "Cannot use salt-based IV generation if literal IV is specified"
+ if exists $options->{iv};
+ }
+ elsif ($header_mode eq 'randomiv') {
+ croak "Cannot encrypt using a non-8 byte blocksize cipher when using randomiv header mode"
+ unless $bs == 8 || $legacy_hack;
+ }
+ elsif ($header_mode eq 'none') {
+ croak "You must provide an initialization vector using -iv when using -header=>'none'"
+ unless exists $options->{iv};
+ }
+
+ # KEYSIZE consistency
+ if (defined $key && length($key) != $ks) {
+ croak "If specified by -literal_key, then the key length must be equal to the chosen cipher's key length of $ks bytes";
+ }
+
+ # IV consistency
+ if (defined $iv && length($iv) != $bs) {
+ croak "If specified by -iv, then the initialization vector length must be equal to the chosen cipher's blocksize of $bs bytes";
+ }
+
+
+ return bless {'cipher' => $cipher,
+ 'passphrase' => $pass,
+ 'key' => $key,
+ 'iv' => $iv,
+ 'salt' => $salt,
+ 'padding' => $padding,
+ 'blocksize' => $bs,
+ 'keysize' => $ks,
+ 'header_mode' => $header_mode,
+ 'legacy_hack' => $legacy_hack,
+ 'literal_key' => $literal_key,
+ 'pcbc' => $pcbc,
+ 'make_random_salt' => $random_salt,
+ 'make_random_iv' => $random_iv,
+ },$class;
+}
+
+sub encrypt (\$$) {
+ my ($self,$data) = @_;
+ $self->start('encrypting');
+ my $result = $self->crypt($data);
+ $result .= $self->finish;
+ $result;
+}
+
+sub decrypt (\$$){
+ my ($self,$data) = @_;
+ $self->start('decrypting');
+ my $result = $self->crypt($data);
+ $result .= $self->finish;
+ $result;
+}
+
+sub encrypt_hex (\$$) {
+ my ($self,$data) = @_;
+ return join('',unpack 'H*',$self->encrypt($data));
+}
+
+sub decrypt_hex (\$$) {
+ my ($self,$data) = @_;
+ return $self->decrypt(pack'H*',$data);
+}
+
+# call to start a series of encryption/decryption operations
+sub start (\$$) {
+ my $self = shift;
+ my $operation = shift;
+ croak "Specify <e>ncryption or <d>ecryption" unless $operation=~/^[ed]/i;
+
+ $self->{'buffer'} = '';
+ $self->{'decrypt'} = $operation=~/^d/i;
+}
+
+# call to encrypt/decrypt a bit of data
+sub crypt (\$$){
+ my $self = shift;
+ my $data = shift;
+
+ my $result;
+
+ croak "crypt() called without a preceding start()"
+ unless exists $self->{'buffer'};
+
+ my $d = $self->{'decrypt'};
+
+ unless ($self->{civ}) { # block cipher has not yet been initialized
+ $result = $self->_generate_iv_and_cipher_from_datastream(\$data) if $d;
+ $result = $self->_generate_iv_and_cipher_from_options() unless $d;
+ }
+
+ my $iv = $self->{'civ'};
+ $self->{'buffer'} .= $data;
+
+ my $bs = $self->{'blocksize'};
+
+ croak "When using rijndael_compat padding, plaintext size must be a multiple of $bs"
+ if $self->{'padding'} eq \&_rijndael_compat
+ and length($data) % $bs;
+
+ return $result unless (length($self->{'buffer'}) >= $bs);
+
+ my @blocks = unpack("a$bs "x(int(length($self->{'buffer'})/$bs)) . "a*", $self->{'buffer'});
+ $self->{'buffer'} = '';
+
+ if ($d) { # when decrypting, always leave a free block at the end
+ $self->{'buffer'} = length($blocks[-1]) < $bs ? join '',splice(@blocks,-2) : pop(@blocks);
+ } else {
+ $self->{'buffer'} = pop @blocks if length($blocks[-1]) < $bs; # what's left over
+ }
+
+ foreach my $block (@blocks) {
+ if ($d) { # decrypting
+ $result .= $iv = $iv ^ $self->{'crypt'}->decrypt($block);
+ $iv = $block unless $self->{pcbc};
+ } else { # encrypting
+ $result .= $iv = $self->{'crypt'}->encrypt($iv ^ $block);
+ }
+ $iv = $iv ^ $block if $self->{pcbc};
+ }
+ $self->{'civ'} = $iv; # remember the iv
+ return $result;
+}
+
+# this is called at the end to flush whatever's left
+sub finish (\$) {
+ my $self = shift;
+ my $bs = $self->{'blocksize'};
+ my $block = defined $self->{'buffer'} ? $self->{'buffer'} : '';
+
+ $self->{civ} ||= '';
+
+ my $result;
+ if ($self->{'decrypt'}) { #decrypting
+ $block = length $block ? pack("a$bs",$block) : ''; # pad and truncate to block size
+
+ if (length($block)) {
+ $result = $self->{'civ'} ^ $self->{'crypt'}->decrypt($block);
+ $result = $self->{'padding'}->($result, $bs, 'd');
+ } else {
+ $result = '';
+ }
+
+ } else { # encrypting
+ $block = $self->{'padding'}->($block,$bs,'e') || '';
+ $result = length $block ? $self->{'crypt'}->encrypt($self->{'civ'} ^ $block) : '';
+ }
+ delete $self->{'civ'};
+ delete $self->{'buffer'};
+ return $result;
+}
+
+# this subroutine will generate the actual {en,de}cryption key, the iv
+# and the block cipher object. This is called when reading from a datastream
+# and so it uses previous values of salt or iv if they are encoded in datastream
+# header
+sub _generate_iv_and_cipher_from_datastream {
+ my $self = shift;
+ my $input_stream = shift;
+ my $bs = $self->blocksize;
+
+ # use our header mode to figure out what to do with the data stream
+ my $header_mode = $self->header_mode;
+
+ if ($header_mode eq 'none') {
+ croak "You must specify a $bs byte initialization vector by passing the -iv option to new() when using -header_mode=>'none'"
+ unless exists $self->{iv};
+ $self->{civ} = $self->{iv}; # current IV equals saved IV
+ $self->{key} ||= $self->_key_from_key($self->{passphrase});
+ }
+
+ elsif ($header_mode eq 'salt') {
+ my ($salt) = $$input_stream =~ /^Salted__(.{8})/s;
+ croak "Ciphertext does not begin with a valid header for 'salt' header mode" unless defined $salt;
+ $self->{salt} = $salt; # new salt
+ substr($$input_stream,0,16) = '';
+ my ($key,$iv) = $self->_salted_key_and_iv($self->{passphrase},$salt);
+ $self->{iv} = $self->{civ} = $iv;
+ $self->{key} = $key;
+ }
+
+ elsif ($header_mode eq 'randomiv') {
+ my ($iv) = $$input_stream =~ /^RandomIV(.{8})/s;
+ croak "Ciphertext does not begin with a valid header for 'randomiv' header mode" unless defined $iv;
+ croak "randomiv header mode cannot be used securely when decrypting with a >8 byte block cipher.\nUse the -insecure_legacy_decrypt flag if you are sure you want to do this" unless $self->blocksize == 8 || $self->legacy_hack;
+ $self->{iv} = $self->{civ} = $iv;
+ $self->{key} = $self->_key_from_key($self->{passphrase});
+ undef $self->{salt}; # paranoia
+ substr($$input_stream,0,16) = ''; # truncate
+ }
+
+ else {
+ croak "Invalid header mode '$header_mode'";
+ }
+
+ # we should have the key and iv now, or we are dead in the water
+ croak "Cipher stream did not contain IV or salt, and you did not specify these values in new()"
+ unless $self->{key} && $self->{civ};
+
+ # now we can generate the crypt object itself
+ $self->{crypt} = ref $self->{cipher} ? $self->{cipher}
+ : $self->{cipher}->new($self->{key})
+ or croak "Could not create $self->{cipher} object: $@";
+ return '';
+}
+
+sub _generate_iv_and_cipher_from_options {
+ my $self = shift;
+ my $blocksize = $self->blocksize;
+
+ my $result = '';
+
+ my $header_mode = $self->header_mode;
+ if ($header_mode eq 'none') {
+ croak "You must specify a $blocksize byte initialization vector by passing the -iv option to new() when using -header_mode=>'none'"
+ unless exists $self->{iv};
+ $self->{civ} = $self->{iv};
+ $self->{key} ||= $self->_key_from_key($self->{passphrase});
+ }
+
+ elsif ($header_mode eq 'salt') {
+ $self->{salt} = $self->_get_random_bytes(8) if $self->{make_random_salt};
+ defined (my $salt = $self->{salt}) or croak "No header_mode of 'salt' specified, but no salt value provided"; # shouldn't happen
+ length($salt) == 8 or croak "Salt must be exactly 8 bytes long";
+ my ($key,$iv) = $self->_salted_key_and_iv($self->{passphrase},$salt);
+ $self->{key} = $key;
+ $self->{civ} = $self->{iv} = $iv;
+ $result = "Salted__${salt}";
+ }
+
+ elsif ($header_mode eq 'randomiv') {
+ croak "randomiv header mode cannot be used when encrypting with a >8 byte block cipher. There is no option to allow this"
+ unless $blocksize == 8;
+ $self->{key} ||= $self->_key_from_key($self->{passphrase});
+ $self->{iv} = $self->_get_random_bytes(8) if $self->{make_random_iv};
+ length($self->{iv}) == 8 or croak "IV must be exactly 8 bytes long when used with header mode of 'randomiv'";
+ $self->{civ} = $self->{iv};
+ $result = "RandomIV$self->{iv}";
+ }
+
+ croak "key and/or iv are missing" unless defined $self->{key} && defined $self->{civ};
+
+ $self->_taintcheck($self->{key});
+ $self->{crypt} = ref $self->{cipher} ? $self->{cipher}
+ : $self->{cipher}->new($self->{key})
+ or croak "Could not create $self->{cipher} object: $@";
+ return $result;
+}
+
+sub _taintcheck {
+ my $self = shift;
+ my $key = shift;
+ return unless ${^TAINT};
+
+ my $has_scalar_util = eval "require Scalar::Util; 1";
+ my $tainted;
+
+ if ($has_scalar_util) {
+ $tainted = Scalar::Util::tainted($key);
+ } else {
+ local($@, $SIG{__DIE__}, $SIG{__WARN__});
+ local $^W = 0;
+ eval { kill 0 * $key };
+ $tainted = $@ =~ /^Insecure/;
+ }
+
+ croak "Taint checks are turned on and your key is tainted. Please untaint the key and try again"
+ if $tainted;
+}
+
+sub _key_from_key {
+ my $self = shift;
+ my $pass = shift;
+ my $ks = $self->{keysize};
+
+ return $pass if $self->{literal_key};
+
+ my $material = md5($pass);
+ while (length($material) < $ks) {
+ $material .= md5($material);
+ }
+ return substr($material,0,$ks);
+}
+
+sub _salted_key_and_iv {
+ my $self = shift;
+ my ($pass,$salt) = @_;
+
+ croak "Salt must be 8 bytes long" unless length $salt == 8;
+
+ my $key_len = $self->{keysize};
+ my $iv_len = $self->{blocksize};
+
+ my $desired_len = $key_len+$iv_len;
+
+ my $data = '';
+ my $d = '';
+
+ while (length $data < $desired_len) {
+ $d = md5($d . $pass . $salt);
+ $data .= $d;
+ }
+ return (substr($data,0,$key_len),substr($data,$key_len,$iv_len));
+}
+
+sub random_bytes {
+ my $self = shift;
+ my $bytes = shift or croak "usage: random_bytes(\$byte_length)";
+ $self->_get_random_bytes($bytes);
+}
+
+sub _get_random_bytes {
+ my $self = shift;
+ my $length = shift;
+ my $result;
+
+ if (-r RANDOM_DEVICE && open(F,RANDOM_DEVICE)) {
+ read(F,$result,$length);
+ close F;
+ } else {
+ $result = pack("C*",map {rand(256)} 1..$length);
+ }
+ # Clear taint and check length
+ $result =~ /^(.{$length})$/s or croak "Invalid length while gathering $length randim bytes";
+ return $1;
+}
+
+sub _standard_padding ($$$) {
+ my ($b,$bs,$decrypt) = @_;
+ $b = length $b ? $b : '';
+ if ($decrypt eq 'd') {
+ my $pad_length = unpack("C",substr($b,-1));
+
+ # sanity check for implementations that don't pad correctly
+ return $b unless $pad_length >= 0 && $pad_length <= $bs;
+ my @pad_chars = unpack("C*",substr($b,-$pad_length));
+ return $b if grep {$pad_length != $_} @pad_chars;
+
+ return substr($b,0,$bs-$pad_length);
+ }
+ my $pad = $bs - length($b) % $bs;
+ return $b . pack("C*",($pad)x$pad);
+}
+
+sub _space_padding ($$$) {
+ my ($b,$bs,$decrypt) = @_;
+ return unless length $b;
+ $b = length $b ? $b : '';
+ if ($decrypt eq 'd') {
+ $b=~ s/ *$//s;
+ return $b;
+ }
+ return $b . pack("C*", (32) x ($bs - length($b) % $bs));
+}
+
+sub _null_padding ($$$) {
+ my ($b,$bs,$decrypt) = @_;
+ return unless length $b;
+ $b = length $b ? $b : '';
+ if ($decrypt eq 'd') {
+ $b=~ s/\0*$//s;
+ return $b;
+ }
+ return $b . pack("C*", (0) x ($bs - length($b) % $bs));
+}
+
+sub _oneandzeroes_padding ($$$) {
+ my ($b,$bs,$decrypt) = @_;
+ $b = length $b ? $b : '';
+ if ($decrypt eq 'd') {
+ my $hex = unpack("H*", $b);
+ $hex =~ s/80*$//s;
+ return pack("H*", $hex);
+ }
+ return $b . pack("C*", 128, (0) x ($bs - length($b) % $bs - 1) );
+}
+
+sub _rijndael_compat ($$$) {
+ my ($b,$bs,$decrypt) = @_;
+ return unless length $b;
+ if ($decrypt eq 'd') {
+ my $hex = unpack("H*", $b);
+ $hex =~ s/80*$//s;
+ return pack("H*", $hex);
+ }
+ return $b . pack("C*", 128, (0) x ($bs - length($b) % $bs - 1) );
+}
+
+sub get_initialization_vector (\$) {
+ my $self = shift;
+ $self->iv();
+}
+
+sub set_initialization_vector (\$$) {
+ my $self = shift;
+ my $iv = shift;
+ my $bs = $self->blocksize;
+ croak "Initialization vector must be $bs bytes in length" unless length($iv) == $bs;
+ $self->iv($iv);
+}
+
+sub salt {
+ my $self = shift;
+ my $d = $self->{salt};
+ $self->{salt} = shift if @_;
+ $d;
+}
+
+sub iv {
+ my $self = shift;
+ my $d = $self->{iv};
+ $self->{iv} = shift if @_;
+ $d;
+}
+
+sub key {
+ my $self = shift;
+ my $d = $self->{key};
+ $self->{key} = shift if @_;
+ $d;
+}
+
+sub passphrase {
+ my $self = shift;
+ my $d = $self->{passphrase};
+ if (@_) {
+ undef $self->{key};
+ undef $self->{iv};
+ $self->{passphrase} = shift;
+ }
+ $d;
+}
+
+sub cipher { shift->{cipher} }
+sub padding { shift->{padding} }
+sub keysize { shift->{keysize} }
+sub blocksize { shift->{blocksize} }
+sub pcbc { shift->{pcbc} }
+sub header_mode {shift->{header_mode} }
+sub legacy_hack { shift->{legacy_hack} }
+
+1;
+__END__
+
+=head1 NAME
+
+Crypt::CBC - Encrypt Data with Cipher Block Chaining Mode
+
+=head1 SYNOPSIS
+
+ use Crypt::CBC;
+ $cipher = Crypt::CBC->new( -key => 'my secret key',
+ -cipher => 'Blowfish'
+ );
+
+ $ciphertext = $cipher->encrypt("This data is hush hush");
+ $plaintext = $cipher->decrypt($ciphertext);
+
+ $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(-literal_key => 1,
+ -key => $key,
+ -iv => $iv,
+ -header => 'none');
+
+ $ciphertext = $cipher->encrypt("This data is hush hush");
+ $plaintext = $cipher->decrypt($ciphertext);
+
+ # RANDOMIV-compatible mode
+ $cipher = Crypt::CBC->new(-key => 'Super Secret!'
+ -header => 'randomiv');
+
+
+=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
+DES or IDEA, 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( -key => 'my secret key',
+ -cipher => 'Blowfish',
+ );
+
+ # or (for compatibility with versions prior to 2.13)
+ $cipher = Crypt::CBC->new( {
+ key => 'my secret key',
+ cipher => 'Blowfish'
+ }
+ );
+
+
+ # or (for compatibility with versions prior to 2.0)
+ $cipher = new Crypt::CBC('my secret key' => 'Blowfish');
+
+The new() method creates a new Crypt::CBC object. It accepts a list of
+-argument => value pairs selected from the following list:
+
+ Argument Description
+ -------- -----------
+
+ -key The encryption/decryption key (required)
+
+ -cipher The cipher algorithm (defaults to Crypt::DES), or
+ a preexisting cipher object.
+
+ -salt Enables OpenSSL-compatibility. If equal to a value
+ of "1" then causes a random salt to be generated
+ and used to derive the encryption key and IV. Other
+ true values are taken to be the literal salt.
+
+ -iv The initialization vector (IV)
+
+ -header What type of header to prepend to ciphertext. One of
+ 'salt' -- use OpenSSL-compatible salted header
+ 'randomiv' -- Randomiv-compatible "RandomIV" header
+ 'none' -- prepend no header at all
+
+ -padding The padding method, one of "standard" (default),
+ "space", "oneandzeroes", "rijndael_compat",
+ or "null" (default "standard").
+
+ -literal_key If true, the key provided by "key" is used directly
+ for encryption/decryption. Otherwise the actual
+ key used will be a hash of the provided key.
+ (default false)
+
+ -pcbc Whether to use the PCBC chaining algorithm rather than
+ the standard CBC algorithm (default false).
+
+ -keysize Force the cipher keysize to the indicated number of bytes.
+
+ -blocksize Force the cipher blocksize to the indicated number of bytes.
+
+ -insecure_legacy_decrypt
+ Allow decryption of data encrypted using the "RandomIV" header
+ produced by pre-2.17 versions of Crypt::CBC.
+
+ -add_header [deprecated; use -header instread]
+ 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 add_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 quick-but-not-very-secure DES algorithm unless
+specified otherwise. You may use any compatible block encryption
+algorithm that you have installed. Currently, this includes
+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<-key> argument provides either 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<-key> can be any
+number of characters; the actual key will be derived by passing the
+passphrase through a series of MD5 hash 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. To skip this hashing
+operation and specify the key directly, pass a true value to the
+B<-literal_key> option. In this case, you should choose a key of
+length exactly equal to the cipher's key length. You should also
+specify the IV yourself and a -header mode of 'none'.
+
+If you pass an existing Crypt::* object to new(), then the -key
+argument is ignored and the module will generate a warning.
+
+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.
+
+ "none" -- Do not generate a header. To decrypt a stream encrypted
+ in this way, you will have to provide the original 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 salt 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<-pcbc> argument, if true, activates a modified chaining mode
+known as PCBC. It provides better error propagation characteristics
+than the default CBC encryption and is required for authenticating to
+Kerberos4 systems (see RFC 2222).
+
+The B<-keysize> and B<-blocksize> arguments can be used to force the
+cipher's keysize and/or blocksize. This is only currently useful for
+the Crypt::Blowfish module, which accepts a variable length
+keysize. If -keysize is not specified, then Crypt::CBC will use the
+maximum length Blowfish key size of 56 bytes (448 bits). The Openssl
+library defaults to 16 byte Blowfish key sizes, so for compatibility
+with Openssl you may wish to set -keysize=>16. There are currently no
+Crypt::* modules that have variable block sizes, but an option to
+change the block size is provided just in case.
+
+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.
+
+B<IMPORTANT NOTE:> Versions of this module prior to 2.17 were
+incorrectly using 8-byte IVs when generating the "randomiv" style of
+header, even when the chosen cipher's blocksize was greater than 8
+bytes. This primarily affects the Rijndael algorithm. Such encrypted
+data streams were B<not secure>. From versions 2.17 onward, Crypt::CBC
+will refuse to encrypt or decrypt using the "randomiv" header and non-8
+byte block ciphers. To decrypt legacy data encrypted with earlier
+versions of the module, you can override the check using the
+B<-insecure_legacy_decrypt> option. It is not possible to override
+encryption. Please use the default "salt" header style, or no headers
+at all.
+
+=head2 start()
+
+ $cipher->start('encrypting');
+ $cipher->start('decrypting');
+
+The start() method prepares the cipher for a series of encryption or
+decryption steps, resetting the internal state of the cipher if
+necessary. You must provide a string indicating whether you wish to
+encrypt or decrypt. "E" or any word that begins with an "e" indicates
+encryption. "D" or any word that begins with a "d" indicates
+decryption.
+
+=head2 crypt()
+
+ $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 inernally 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
+the corresponding ciphertext.
+
+=head2 decrypt()
+
+ $plaintext = $cipher->decrypt($ciphertext)
+
+This convenience function runs the entire sequence of start(), crypt()
+and finish() for you, processing the provided ciphertext and returning
+the corresponding plaintext.
+
+=head2 encrypt_hex(), decrypt_hex()
+
+ $ciphertext = $cipher->encrypt_hex($plaintext)
+ $plaintext = $cipher->decrypt_hex($ciphertext)
+
+These are convenience functions that operate on ciphertext in a
+hexadecimal representation. B<encrypt_hex($plaintext)> is exactly
+equivalent to B<unpack('H*',encrypt($plaintext))>. These functions
+can be useful if, for example, you wish to place the encrypted in an
+email message.
+
+=head2 get_initialization_vector()
+
+ $iv = $cipher->get_initialization_vector()
+
+This function will return the IV used in encryption and or decryption.
+The IV is not guaranteed to be set when encrypting until start() is
+called, and when decrypting until crypt() is called the first
+time. Unless the IV was manually specified in the new() call, the IV
+will change with every complete encryption operation.
+
+=head2 set_initialization_vector()
+
+ $cipher->set_initialization_vector('76543210')
+
+This function sets the IV used in encryption and/or decryption. This
+function may be useful if the IV is not contained within the
+ciphertext string being decrypted, or if a particular IV is desired
+for encryption. Note that the IV must match the chosen cipher's
+blocksize bytes in length.
+
+=head2 iv()
+
+ $iv = $cipher->iv();
+ $cipher->iv($new_iv);
+
+As above, but using a single method call.
+
+=head2 key()
+
+ $key = $cipher->key();
+ $cipher->key($new_key);
+
+Get or set the block cipher key used for encryption/decryption. When
+encrypting, the key is not guaranteed to exist until start() is
+called, and when decrypting, the key is not guaranteed to exist until
+after the first call to crypt(). The key must match the length
+required by the underlying block cipher.
+
+When salted headers are used, the block cipher key will change after
+each complete sequence of encryption operations.
+
+=head2 salt()
+
+ $salt = $cipher->salt();
+ $cipher->salt($new_salt);
+
+Get or set the salt used for deriving the encryption key and IV when
+in OpenSSL compatibility mode.
+
+=head2 passphrase()
+
+ $passphrase = $cipher->passphrase();
+ $cipher->passphrase($new_passphrase);
+
+This gets or sets the value of the B<key> passed to new() when
+B<literal_key> is false.
+
+=head2 $data = get_random_bytes($numbytes)
+
+Return $numbytes worth of random data. On systems that support the
+"/dev/urandom" device file, this data will be read from the
+device. Otherwise, it will be generated by repeated calls to the Perl
+rand() function.
+
+=head2 cipher(), padding(), keysize(), blocksize(), pcbc()
+
+These read-only methods return the identity of the chosen block cipher
+algorithm, padding method, key and block size of the chosen block
+cipher, and whether PCBC chaining is in effect.
+
+=head2 Padding methods
+
+Use the 'padding' option to change the padding method.
+
+When the last block of plaintext is shorter than the block size,
+it must be padded. Padding methods include: "standard" (i.e., PKCS#5),
+"oneandzeroes", "space", "rijndael_compat" and "null".
+
+ standard: (default) Binary safe
+ pads with the number of bytes that should be truncated. So, if
+ blocksize is 8, then "0A0B0C" will be padded with "05", resulting
+ in "0A0B0C0505050505". If the final block is a full block of 8
+ 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 only and can only be used
+ with messages that are a multiple of the Rijndael blocksize
+ 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".
+
+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 EXAMPLES
+
+Two examples, 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.
+
+=head1 LIMITATIONS
+
+The encryption and decryption process is about a tenth the speed of
+the equivalent SSLeay programs (compiled C). This could be improved
+by implementing this module in C. It may also be worthwhile to
+optimize the DES and IDEA block algorithms further.
+
+=head1 BUGS
+
+Please report them.
+
+=head1 AUTHOR
+
+Lincoln Stein, lstein@cshl.org
+
+This module is distributed under the ARTISTIC LICENSE using the same
+terms as Perl itself.
+
+=head1 SEE ALSO
+
+perl(1), Crypt::DES(3), Crypt::IDEA(3), rfc2898 (PKCS#5)
+
+=cut
--- /dev/null
+package Crypt::Camellia_PP;
+
+use strict;
+use warnings;
+use Carp;
+our $VERSION = '0.02';
+
+my $SIGMA1 = [ 0xA0, 0x9E, 0x66, 0x7F, 0x3B, 0xCC, 0x90, 0x8B ];
+my $SIGMA2 = [ 0xB6, 0x7A, 0xE8, 0x58, 0x4C, 0xAA, 0x73, 0xB2 ];
+my $SIGMA3 = [ 0xC6, 0xEF, 0x37, 0x2F, 0xE9, 0x4F, 0x82, 0xBE ];
+my $SIGMA4 = [ 0x54, 0xFF, 0x53, 0xA5, 0xF1, 0xD3, 0x6F, 0x1C ];
+my $SIGMA5 = [ 0x10, 0xE5, 0x27, 0xFA, 0xDE, 0x68, 0x2D, 0x1D ];
+my $SIGMA6 = [ 0xB0, 0x56, 0x88, 0xC2, 0xB3, 0xE6, 0xC1, 0xFD ];
+
+my @S1 = (
+ 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65,
+ 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189,
+ 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26,
+ 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77,
+ 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153,
+ 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215,
+ 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34,
+ 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80,
+ 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210,
+ 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148,
+ 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226,
+ 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46,
+ 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89,
+ 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250,
+ 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164,
+ 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158
+);
+my @S2 = (
+ 224,5,88,217,103,78,129,203,201,11,174,106,213,24,93,130,
+ 70,223,214,39,138,50,75,66,219,28,158,156,58,202,37,123,
+ 13,113,95,31,248,215,62,157,124,96,185,190,188,139,22,52,
+ 77,195,114,149,171,142,186,122,179,2,180,173,162,172,216,154,
+ 23,26,53,204,247,153,97,90,232,36,86,64,225,99,9,51,
+ 191,152,151,133,104,252,236,10,218,111,83,98,163,46,8,175,
+ 40,176,116,194,189,54,34,56,100,30,57,44,166,48,229,68,
+ 253,136,159,101,135,107,244,35,72,16,209,81,192,249,210,160,
+ 85,161,65,250,67,19,196,47,168,182,60,43,193,255,200,165,
+ 32,137,0,144,71,239,234,183,21,6,205,181,18,126,187,41,
+ 15,184,7,4,155,148,33,102,230,206,237,231,59,254,127,197,
+ 164,55,177,76,145,110,141,118,3,45,222,150,38,125,198,92,
+ 211,242,79,25,63,220,121,29,82,235,243,109,94,251,105,178,
+ 240,49,12,212,207,140,226,117,169,74,87,132,17,69,27,245,
+ 228,14,115,170,241,221,89,20,108,146,84,208,120,112,227,73,
+ 128,80,167,246,119,147,134,131,42,199,91,233,238,143,1,61
+);
+my @S3 = (
+ 56,65,22,118,217,147,96,242,114,194,171,154,117,6,87,160,
+ 145,247,181,201,162,140,210,144,246,7,167,39,142,178,73,222,
+ 67,92,215,199,62,245,143,103,31,24,110,175,47,226,133,13,
+ 83,240,156,101,234,163,174,158,236,128,45,107,168,43,54,166,
+ 197,134,77,51,253,102,88,150,58,9,149,16,120,216,66,204,
+ 239,38,229,97,26,63,59,130,182,219,212,152,232,139,2,235,
+ 10,44,29,176,111,141,136,14,25,135,78,11,169,12,121,17,
+ 127,34,231,89,225,218,61,200,18,4,116,84,48,126,180,40,
+ 85,104,80,190,208,196,49,203,42,173,15,202,112,255,50,105,
+ 8,98,0,36,209,251,186,237,69,129,115,109,132,159,238,74,
+ 195,46,193,1,230,37,72,153,185,179,123,249,206,191,223,113,
+ 41,205,108,19,100,155,99,157,192,75,183,165,137,95,177,23,
+ 244,188,211,70,207,55,94,71,148,250,252,91,151,254,90,172,
+ 60,76,3,53,243,35,184,93,106,146,213,33,68,81,198,125,
+ 57,131,220,170,124,119,86,5,27,164,21,52,30,28,248,82,
+ 32,20,233,189,221,228,161,224,138,241,214,122,187,227,64,79
+);
+my @S4 = (
+ 112,44,179,192,228,87,234,174,35,107,69,165,237,79,29,146,
+ 134,175,124,31,62,220,94,11,166,57,213,93,217,90,81,108,
+ 139,154,251,176,116,43,240,132,223,203,52,118,109,169,209,4,
+ 20,58,222,17,50,156,83,242,254,207,195,122,36,232,96,105,
+ 170,160,161,98,84,30,224,100,16,0,163,117,138,230,9,221,
+ 135,131,205,144,115,246,157,191,82,216,200,198,129,111,19,99,
+ 233,167,159,188,41,249,47,180,120,6,231,113,212,171,136,141,
+ 114,185,248,172,54,42,60,241,64,211,187,67,21,173,119,128,
+ 130,236,39,229,133,53,12,65,239,147,25,33,14,78,101,189,
+ 184,143,235,206,48,95,197,26,225,202,71,61,1,214,86,77,
+ 13,102,204,45,18,32,177,153,76,194,126,5,183,49,23,215,
+ 88,97,27,28,15,22,24,34,68,178,181,145,8,168,252,80,
+ 208,125,137,151,91,149,255,210,196,72,247,219,3,218,63,148,
+ 92,2,74,51,103,243,127,226,155,38,55,59,150,75,190,46,
+ 121,140,110,142,245,182,253,89,152,106,70,186,37,66,162,250,
+ 7,85,238,10,73,104,56,164,40,123,201,193,227,244,199,158
+);
+
+
+sub blocksize { 16 }
+sub keysize { 32 }
+
+
+
+sub new {
+ my $class = shift;
+ my $key = shift;
+ if (!defined $key) {
+ croak q{Usage: Crypt::Camellia_PP->new($key);};
+ }
+ my $keysize = length $key;
+ if ($keysize != 16 && $keysize != 24 && $keysize != 32) {
+ croak q{wrong key length: key must be 128, 192 or 256 bit.};
+ }
+
+ my @key = unpack 'C*', $key;
+ my $self = bless {
+ keysize => $keysize,
+ kw => [
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0]
+ ],
+ k => [
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0]
+ ],
+ kl => [
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0]
+ ]
+ }, $class;
+ $self->_prepare_sub_key(\@key);
+ return $self;
+}
+
+
+sub encrypt {
+ my $self = shift;
+ my $in = shift;
+ my $l = [ unpack 'C8', $in ];
+ my $r = [ unpack 'C8', substr $in, 8, 8];
+ _xor_block($l, $l, $self->{kw}->[0], 8);
+ _xor_block($r, $r, $self->{kw}->[1], 8);
+ if ($self->{keysize} == 16) {
+ for (my $i = 0; $i < 18; $i += 2) {
+ _feistel($r, 0, $l, $self->{k}->[$i]);
+ _feistel($l, 0, $r, $self->{k}->[$i+1]);
+ if ($i == 4) { # round 6
+ _flayer($l, $l, $self->{kl}->[0], 0);
+ _flayer_1($r, $r, $self->{kl}->[1], 0);
+ }
+ elsif ($i == 10) { # round 12
+ _flayer($l, $l, $self->{kl}->[2], 0);
+ _flayer_1($r, $r, $self->{kl}->[3], 0);
+ }
+ }
+ }
+ else {
+ for (my $i = 0; $i < 24; $i += 2) {
+ _feistel($r, 0, $l, $self->{k}->[$i]);
+ _feistel($l, 0, $r, $self->{k}->[$i+1]);
+ if ($i == 4) { # round 6
+ _flayer($l, $l, $self->{kl}->[0], 0);
+ _flayer_1($r, $r, $self->{kl}->[1], 0);
+ }
+ elsif ($i == 10) { # round 12
+ _flayer($l, $l, $self->{kl}->[2], 0);
+ _flayer_1($r, $r, $self->{kl}->[3], 0);
+ }
+ elsif ($i == 16) { # round 18
+ _flayer($l, $l, $self->{kl}->[4], 0);
+ _flayer_1($r, $r, $self->{kl}->[5], 0);
+ }
+ }
+ }
+ _xor_block($r, $r, $self->{kw}->[2], 8);
+ _xor_block($l, $l, $self->{kw}->[3], 8);
+
+ return pack 'C16', @$r, @$l;
+}
+
+
+sub decrypt {
+ my $self = shift;
+ my $in = shift;
+
+ my $r = [ unpack 'C8', $in ];
+ my $l = [ unpack 'C8', substr $in, 8, 8];
+ _xor_block($r, $r, $self->{kw}->[2], 8);
+ _xor_block($l, $l, $self->{kw}->[3], 8);
+ if ($self->{keysize} == 16) {
+ for (my $i = 16; $i >= 0; $i -= 2) {
+ _feistel($l, 0, $r, $self->{k}->[$i+1]);
+ _feistel($r, 0, $l, $self->{k}->[$i]);
+ if ($i == 12) {
+ _flayer($r, $r, $self->{kl}->[3]);
+ _flayer_1($l, $l, $self->{kl}->[2]);
+ }
+ elsif ($i == 6) {
+ _flayer($r, $r, $self->{kl}->[1]);
+ _flayer_1($l, $l, $self->{kl}->[0]);
+ }
+ }
+ }
+ else {
+ for (my $i = 22; $i >= 0; $i -= 2) {
+ _feistel($l, 0, $r, $self->{k}->[$i+1]);
+ _feistel($r, 0, $l, $self->{k}->[$i]);
+ if ($i == 18) {
+ _flayer($r, $r, $self->{kl}->[5]);
+ _flayer_1($l, $l, $self->{kl}->[4]);
+ }
+ elsif ($i == 12) {
+ _flayer($r, $r, $self->{kl}->[3]);
+ _flayer_1($l, $l, $self->{kl}->[2]);
+ }
+ elsif ($i == 6) {
+ _flayer($r, $r, $self->{kl}->[1]);
+ _flayer_1($l, $l, $self->{kl}->[0]);
+ }
+ }
+
+ }
+ _xor_block($l, $l, $self->{kw}->[0], 8);
+ _xor_block($r, $r, $self->{kw}->[1], 8);
+
+ return pack 'C16', @$l, @$r;
+}
+
+
+
+sub _prepare_sub_key {
+ my $self = shift;
+ my $key = shift;
+ my $kl = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
+ my $kr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
+ my $ka = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
+
+ if ($self->{keysize} == 16) {
+ _move($kl, 0, $key, 0, 16);
+ }
+ elsif ($self->{keysize} == 24) {
+ _move($kl, 0, $key, 0, 16);
+ _move($kr, 0, $key, 16, 8);
+ for (my $i = 0; $i < 8; $i++) {
+ $kr->[$i+8] = $key->[$i+16] ^ 0xff;
+ }
+ }
+ elsif ($self->{keysize} == 32) {
+ _move($kl, 0, $key, 0, 16);
+ _move($kr, 0, $key, 16,16);
+ }
+
+ _xor_block($ka, $kl, $kr, 16);
+ _feistel($ka, 8, $ka, $SIGMA1);
+ _feistel($ka, 0, [@$ka[8..15]], $SIGMA2);
+ _xor_block($ka, $kl, $ka, 16);
+
+ _feistel($ka, 8, $ka, $SIGMA3);
+ _feistel($ka, 0, [@$ka[8..15]], $SIGMA4);
+
+ if ($self->{keysize} == 16) {
+ _rot_shift($self->{kw}->[0], $self->{kw}->[1], $kl, 0);
+
+ _rot_shift($self->{k}->[0], $self->{k}->[1], $ka, 0);
+ _rot_shift($self->{k}->[2], $self->{k}->[3], $kl, 15);
+ _rot_shift($self->{k}->[4], $self->{k}->[5], $ka, 15);
+
+ _rot_shift($self->{kl}->[0], $self->{kl}->[1], $ka, 30);
+
+ _rot_shift($self->{k}->[6], $self->{k}->[7], $kl, 45);
+ _rot_shift($self->{k}->[8], [0,0,0,0,0,0,0,0], $ka, 45);
+ _rot_shift([0,0,0,0,0,0,0,0], $self->{k}->[9], $kl, 60);
+ _rot_shift($self->{k}->[10], $self->{k}->[11], $ka, 60);
+
+ _rot_shift($self->{kl}->[2], $self->{kl}->[3], $kl, 77);
+
+ _rot_shift($self->{k}->[12], $self->{k}->[13], $kl, 94);
+ _rot_shift($self->{k}->[14], $self->{k}->[15], $ka, 94);
+ _rot_shift($self->{k}->[16], $self->{k}->[17], $kl, 111);
+
+ _rot_shift($self->{kw}->[2], $self->{kw}->[3], $ka, 111);
+ }
+ else {
+ my $kb = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
+ _xor_block($kb, $kr, $ka, 16);
+ _feistel($kb, 8, $kb, $SIGMA5);
+ _feistel($kb, 0, [@$kb[8..15]], $SIGMA6);
+
+ _rot_shift($self->{kw}->[0], $self->{kw}->[1], $kl, 0);
+
+ _rot_shift($self->{k}->[0], $self->{k}->[1], $kb, 0);
+ _rot_shift($self->{k}->[2], $self->{k}->[3], $kr, 15);
+ _rot_shift($self->{k}->[4], $self->{k}->[5], $ka, 15);
+
+ _rot_shift($self->{kl}->[0], $self->{kl}->[1], $kr, 30);
+
+ _rot_shift($self->{k}->[6], $self->{k}->[7], $kb, 30);
+ _rot_shift($self->{k}->[8], $self->{k}->[9], $kl, 45);
+ _rot_shift($self->{k}->[10], $self->{k}->[11], $ka, 45);
+
+ _rot_shift($self->{kl}->[2], $self->{kl}->[3], $kl, 60);
+
+ _rot_shift($self->{k}->[12], $self->{k}->[13], $kr, 60);
+ _rot_shift($self->{k}->[14], $self->{k}->[15], $kb, 60);
+ _rot_shift($self->{k}->[16], $self->{k}->[17], $kl, 77);
+
+ _rot_shift($self->{kl}->[4], $self->{kl}->[5], $ka, 77);
+
+ _rot_shift($self->{k}->[18], $self->{k}->[19], $kr, 94);
+ _rot_shift($self->{k}->[20], $self->{k}->[21], $ka, 94);
+ _rot_shift($self->{k}->[22], $self->{k}->[23], $kl, 111);
+
+ _rot_shift($self->{kw}->[2], $self->{kw}->[3], $kb, 111);
+ }
+
+ return $self;
+}
+
+
+
+sub _move {
+ for (my $i = 0; $i < $_[4]; $i++) {
+ $_[0]->[$i+$_[1]] = $_[2]->[$i+$_[3]];
+ }
+}
+
+
+sub _xor_block {
+ for (my $i = 0; $i < $_[3]; $i++) {
+ $_[0]->[$i] = $_[1]->[$i] ^ $_[2]->[$i];
+ }
+}
+
+
+sub _feistel {
+ my $dist = shift;
+ my $o = shift;
+ my $x = shift;
+ my $k = shift;
+ my $w = [0,0,0,0,0,0,0,0];
+ _xor_block($w, $x, $k, 8);
+ # S funcs
+ my @ws = ($S1[$w->[0]], $S2[$w->[1]], $S3[$w->[2]], $S4[$w->[3]],
+ $S2[$w->[4]], $S3[$w->[5]], $S4[$w->[6]], $S1[$w->[7]]);
+ # P func
+ $dist->[0+$o] ^= $ws[0] ^ $ws[2] ^ $ws[3] ^ $ws[5] ^ $ws[6] ^ $ws[7];
+ $dist->[1+$o] ^= $ws[0] ^ $ws[1] ^ $ws[3] ^ $ws[4] ^ $ws[6] ^ $ws[7];
+ $dist->[2+$o] ^= $ws[0] ^ $ws[1] ^ $ws[2] ^ $ws[4] ^ $ws[5] ^ $ws[7];
+ $dist->[3+$o] ^= $ws[1] ^ $ws[2] ^ $ws[3] ^ $ws[4] ^ $ws[5] ^ $ws[6];
+ $dist->[4+$o] ^= $ws[0] ^ $ws[1] ^ $ws[5] ^ $ws[6] ^ $ws[7];
+ $dist->[5+$o] ^= $ws[1] ^ $ws[2] ^ $ws[4] ^ $ws[6] ^ $ws[7];
+ $dist->[6+$o] ^= $ws[2] ^ $ws[3] ^ $ws[4] ^ $ws[5] ^ $ws[7];
+ $dist->[7+$o] ^= $ws[0] ^ $ws[3] ^ $ws[4] ^ $ws[5] ^ $ws[6];
+}
+
+
+sub _flayer {
+ my ($dist, $x, $k) = @_;
+ _move($dist, 0, $x, 0, 8);
+ $dist->[4+0] ^= ((($x->[0] & $k->[0]) << 1) & 0xff) ^ ($x->[1] & $k->[1]) >> 7;
+ $dist->[4+1] ^= ((($x->[1] & $k->[1]) << 1) & 0xff) ^ ($x->[2] & $k->[2]) >> 7;
+ $dist->[4+2] ^= ((($x->[2] & $k->[2]) << 1) & 0xff) ^ ($x->[3] & $k->[3]) >> 7;
+ $dist->[4+3] ^= ((($x->[3] & $k->[3]) << 1) & 0xff) ^ ($x->[0] & $k->[0]) >> 7;
+ $dist->[0] ^= $dist->[4+0] | $k->[4+0];
+ $dist->[1] ^= $dist->[4+1] | $k->[4+1];
+ $dist->[2] ^= $dist->[4+2] | $k->[4+2];
+ $dist->[3] ^= $dist->[4+3] | $k->[4+3];
+}
+
+
+sub _flayer_1 {
+ my ($dist, $x, $k) = @_;
+ _move($dist, 0, $x, 0, 8);
+ $dist->[0] ^= $x->[4+0] | $k->[4+0];
+ $dist->[1] ^= $x->[4+1] | $k->[4+1];
+ $dist->[2] ^= $x->[4+2] | $k->[4+2];
+ $dist->[3] ^= $x->[4+3] | $k->[4+3];
+ $dist->[4+0] ^= ((($dist->[0] & $k->[0]) << 1) & 0xff) ^ ($dist->[1] & $k->[1]) >> 7;
+ $dist->[4+1] ^= ((($dist->[1] & $k->[1]) << 1) & 0xff) ^ ($dist->[2] & $k->[2]) >> 7;
+ $dist->[4+2] ^= ((($dist->[2] & $k->[2]) << 1) & 0xff) ^ ($dist->[3] & $k->[3]) >> 7;
+ $dist->[4+3] ^= ((($dist->[3] & $k->[3]) << 1) & 0xff) ^ ($dist->[0] & $k->[0]) >> 7;
+}
+
+
+sub _rot_shift {
+ my ($dist_l, $dist_r, $src, $bit) = @_;
+ if ($bit == 0) {
+ for (my $i = 0; $i < 8; $i++) {
+ $dist_l->[$i] = $src->[$i];
+ }
+ for (my $i = 0; $i < 8; $i++) {
+ $dist_r->[$i] = $src->[$i+8];
+ }
+ return;
+ }
+ my $o = int($bit / 8) + 1;
+ my $so = $o * 8 - $bit;
+ $o = $o % 16;
+ for (my $i = 0; $i < 8; $i++) {
+ $dist_l->[$i] = (($src->[($i+$o) % 16] >> $so) & 0xff)
+ | (($src->[($i+$o-1) % 16] << (8 - $so)) & 0xff);
+ $dist_r->[$i] = (($src->[($i+8+$o) % 16] >> $so) & 0xff)
+ | (($src->[($i+8+$o-1) % 16] << (8 - $so)) & 0xff);
+ }
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Crypt::Camellia_PP - Pure Perl Camellia 128-bit block cipher module.
+
+=head1 SYNOPSIS
+
+ use Crypt::Camellia_PP;
+
+ my $key = pack 'H*', '00000000000000000000000000000000';
+ my $plain_text = pack 'H*', '00000000000000000000000000000000';
+ my $c = Crypt::Camellia->new($key);
+ my $cipher_text = $c->encrypt($plain_text);
+
+
+=head1 DESCRIPTION
+
+this module implements the Camellia cipher by Pure Perl.
+
+=head2 Methods
+
+=over 4
+
+=item new($key)
+
+Create a new "Crypt::Camellia_PP" cipher object with the given key (which must be 128 or 192 or 256 bit long).
+
+=item encrypt($data)
+
+Encrypt data. The size of $data must be a 16 bytes.
+
+=item decrypt($data)
+
+Decrypts $data.
+
+=back
+
+=head1 EXAMPLE
+
+=head2 Encrypt and Decrypt
+
+ use Crypt::Camellia_PP;
+
+ my $key = pack 'H*', '00112233445566778899AABBCCDDEEFF';
+ my $src = pack 'H*', 'FFEEDDCCBBAA99887766554433221100';
+ my $camellia = Crypt::Camellia_PP->new($key);
+ my $cipher_string = $camellia->encrypt($src);
+
+ my $plain_string = $camellia->decrypt($cipher_string);
+ $plain_string eq $src;
+
+=head2 With Crypt::CBC module
+
+ use Crypt::CBC;
+
+ my $cbc = Crypt::CBC->new({
+ cipher => 'Crypt::Camellia_PP',
+ key => pack('H*', '00112233445566778899aabbccddeeff'),
+ iv => pack('H*', '00000000000000000000000000000000'),
+ literal_key => 1,
+ header => 'none',
+ padding => 'standard',
+ });
+ my $cipher_text = $cbc->encrypt('Hello World!');
+ my $plain_text = $cbc->decrypt($cipher_text);
+ $plain_text eq 'Hello World!';
+
+=head1 SEE ALSO
+
+L<Crypt::Camellia>,
+http://search.cpan.org/dist/Crypt-Camellia/,
+http://info.isl.ntt.co.jp/crypt/camellia/
+
+=head1 AUTHOR
+
+Hiroyuki OYAMA E<lt>oyama@module.jpE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2006 by Hiroyuki OYAMA. Japan.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.6 or,
+at your option, any later version of Perl 5 you may have available.
+
+=cut
$$tmpl =~ s/($old)/$new/g;
}
-sub pre_build {
- my ($cb) = @_;
+sub _hdlr_love_letter_response {
+ my($ctx, $args, $cond) = @_;
+ my $width = $args->{'width'} ? ' width: ' . $args->{'width'} : '';
+ my $height = $args->{'height'} ? ' height: ' . $args->{'height'} : '';
+ my $style = $args->{'style'} || '';
+
+ <<__EOF__;
+<textarea name="response" style="$width $height $style; display: none;">
+</textarea>
+__EOF__
+}
+
+sub _hdlr_love_letter_ok {
+ my($ctx, $args, $cond) = @_;
+
+ <<__EOF__;
+<input type="submit" name="ok" value="@{[ $args->{'value'} || 'OK' ]}" style="display: none;"/>
+__EOF__
+}
+
+sub _hdlr_love_letter_cancel {
+ my($ctx, $args, $cond) = @_;
+
+ <<__EOF__;
+<input type="submit" name="cancel" value="@{[ $args->{'value'} || 'Cancel' ]}" style="display: none;" />
+__EOF__
+}
+
+sub _hdlr_love_letter {
+ my($ctx, $args, $cond) = @_;
+ my $tmpl = $ctx->stash('template');
+ my $app = MT->instance;
+ my $plugin = MT->component('Lovers');
+ my $password = $args->{'password'} || '';
+
+ my $res = '';
+ my $builder = $ctx->stash('builder');
+ my $tokens = $ctx->stash('tokens');
+
+ defined($res = $builder->build($ctx, $tokens, $cond))
+ or return $ctx->error( $builder->errstr );
+
+ my $entry = $ctx->stash('entry');
+ my $entry_id = $entry ? $entry->id : 0;
+ my $love_letter_id = $args->{'id'} || 0;
+ my $template_id = $tmpl ? $tmpl->id : 0;
+ my $ll_class = $app->model('love_letter');
+ my $obj = $ll_class->load({
+ entry_id => $entry_id,
+ template_id => $template_id,
+ love_letter_id => $love_letter_id,
+ });
+ if (! $obj) {
+ $obj = $ll_class->new;
+ }
+
+ $obj->set_values({
+ entry_id => $entry_id,
+ template_id => $template_id,
+ love_letter_id => $love_letter_id,
+ author_id => $entry ? $entry->author_id : $tmpl->modified_by,
+ from => $args->{'from'} || '',
+ to => $args->{'to'} || '',
+ });
+
+ if ((! $obj->sent_on || $obj->sent_on =~ m/^0/) && $obj->to) {
+ my $param = $obj->mail_param;
+ $param->{'permalink'} =
+ $entry ? $entry->permalink : $tmpl->published_url;
+ if ($password) {
+ $param->{'permalink'} =~ s/#.*//;
+ $param->{'permalink'} .= '#password'
+ }
+ my $tmpl = $plugin->load_tmpl('mail_love_letter.tmpl');
+ my $body = MT->translate_templatized(
+ $tmpl->output($param)
+ );
+ my $cfg = $app->config;
+
+ my %head = (
+ id => 'love_letter',
+ To => $param->{'to'},
+ From => $param->{'from'},
+ Subject => $plugin->translate('You got love letter.'),
+ );
+ my $charset = $cfg->MailEncoding || $cfg->PublishCharset;
+ $head{'Content-Type'} = qq(text/plain; charset="$charset");
+
+ require MT::Mail;
+ MT::Mail->send( \%head, $body )
+ or return $app->error( MT::Mail->errstr() );
+
+ my @lt = reverse((localtime)[0 .. 5]);
+ $lt[0] += 1900;
+ $lt[1] += 1;
+ $obj->sent_on(sprintf('%04d%02d%02d%02d%02d%02d', @lt));
+ }
+
+ $obj->save;
+
+ if ($password) {
+ require Crypt::CBC;
+ require MIME::Base64;
+ require Encode;
+
+ my $content_header = 'love_letter:';
+
+ eval{
+ my $dec = Encode::decode('utf-8', $password);
+ $password = $dec;
+ };
+ $password = join('', map(ord($_), split(//, $password)));
+ $password .= '0' x 32;
+ $password = substr($password, 0, 32);
+
+ my $cbc = Crypt::CBC->new({
+ cipher => 'Crypt::Camellia_PP',
+ key => pack('H*', $password),
+ iv => pack('H*', '00000000000000000000000000000000'),
+ literal_key => 1,
+ header => 'none',
+ padding => 'standard',
+
+ keysize => 16,
+ });
+
+ $res = MIME::Base64::encode_base64($cbc->encrypt(
+ $content_header . $res
+ ));
+
+ $res = <<__EOF__;
+<script type="text/javascript" src="@{[ $app->static_path ]}plugins/Lovers/js/CryptoCipherCamellia.js"></script>
+<script type="text/javascript">
+function love_letter_decrypt_$love_letter_id(k) {
+ var j = jQuery;
+
+ if (! k) {
+ k = '';
+ }
+
+ k = j.map(k.split(''), function(v, k) {
+ return v.charCodeAt(0);
+ }).join('');
+ k += '00000000000000000000000000000000';
+ k = k.substr(0, 32);
+
+ var iv = '00000000000000000000000000000000';
+ var cipher = new CryptoCipherCamellia();
+ try {
+ var cbc = new CryptoModeCBC(cipher,
+ CryptoUtil.arrayFromHex(k),
+ CryptoUtil.arrayFromHex(iv));
+ var res = cbc.decrypt(CryptoUtil.arrayFromBase64(
+ j.trim(j('#love_letter_encrypted_$love_letter_id').text())
+ ));
+ var contents = CryptoUtil.stringFromArray(res);
+ var match = contents.match(/^$content_header/);
+ if (match) {
+ j('#love_letter_encrypted_$love_letter_id').html(
+ contents.replace(/^$content_header/, '')
+ ).show();
+ setTimeout(love_letter_init_form_$love_letter_id, 0);
+ return true;
+ }
+ else {
+ alert('@{[ $plugin->translate('wrong password') ]}');
+ }
+ }
+ catch (e) {
+ alert(e);
+ }
+
+ return false;
+}
+
+jQuery(function() {
+ var j = jQuery;
+ var k = '';
+
+ if (document.location.hash.match(/password/i)) {
+ /*
+ k = window.prompt('password');
+ love_letter_decrypt_$love_letter_id(k);
+ */
+ var prompt = j('#love_letter_prompt_$love_letter_id');
+ var pass = prompt.find('input[name="password"]');
+ prompt.show();
+ prompt.find('input[name="password_input"]').focus(function() {
+ j(this).hide();
+ pass.show().get(0).focus();
+ });
+ prompt.find('input[type="submit"]').click(function() {
+ if (love_letter_decrypt_$love_letter_id(pass.val())) {
+ prompt.hide();
+ }
+ return false;
+ });
+ }
+});
+</script>
+<div id="love_letter_prompt_$love_letter_id" style="display:none">
+<input name="password_input" value="@{[ $plugin->translate('Please input password.') ]}" style="color: #999"/>
+<input type="password" name="password" value="" style="display: none;"/>
+<br />
+<input type="submit" value="@{[ $plugin->translate('show love letter') ]}" />
+</div>
+<div id="love_letter_encrypted_$love_letter_id" style="display:none">$res</div>
+__EOF__
+ ;
+ }
+
+ $res = <<__EOF__;
+<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
+<script type="text/javascript">
+jQuery.noConflict();
+function love_letter_init_form_$love_letter_id() {
+ var j = jQuery;
+ var speed = 'normal';
+
+ var container = j('#love_letter_container_$love_letter_id');
+ var loading = j('#love_letter_loading_$love_letter_id');
+ if (loading.length == 0) {
+ container.append(
+ '<div id="love_letter_loading_$love_letter_id" style="background: white url(\\'@{[ $app->static_path ]}plugins/Lovers/img/loading.gif\\') center center no-repeat; display: none; height: ' + container.height() + 'px; width: ' + container.width() + 'px;"></div>'
+ );
+ loading = j('#love_letter_loading_$love_letter_id');
+ }
+ function show_loading() {
+ loading.width(container.width());
+ loading.height(container.height());
+ loading.fadeIn();
+ }
+
+ var form = j('#love_letter_form_$love_letter_id');
+
+ function send(type, callback) {
+ var param = form.serializeArray();
+ param.push({
+ 'name': type,
+ 'value': 1
+ });
+ j.post(form.attr('action'), param, function() {
+ var args = arguments;
+ setTimeout(function() {
+ callback.apply(null, args);
+ }, 2000);
+ });
+ }
+
+ form.find('textarea[name="response"]').show();
+
+ form.find('input[name="ok"]').show().click(function() {
+ send('ok', function(data) {
+ var message = data.match(/<message>(.*?)<\\/message/i);
+ if (! message) {
+ alert('@{[ $plugin->translate('unknown error') ]}');
+ }
+ else if (message[1].match(/^\\s+ok\\s+\$/i)) {
+ alert(message[1]);
+ }
+ else {
+ loading.fadeOut(
+ speed,
+ function() {
+ form.find('[name="if_love_letter_ok"]').show();
+ }
+ );
+ }
+ });
+
+ form.find(
+ 'textarea[name="response"], input[name="ok"], input[name="cancel"]'
+ ).fadeOut(speed, show_loading);
+
+ return false;
+ });
+
+ form.find('input[name="cancel"]').show().click(function() {
+ send('cancel', function(data) {
+ var message = data.match(/<message>(.*?)<\\/message/i);
+ if (! message) {
+ alert('@{[ $plugin->translate('Unknown error.') ]}');
+ }
+ else if (message[1].match(/^\\s+ok\\s+\$/i)) {
+ alert(message[1]);
+ }
+ else {
+ loading.fadeOut(
+ speed,
+ function() {
+ form.find('[name="if_love_letter_cancel"]').show();
+ }
+ );
+ }
+ });
+
+ form.find(
+ 'textarea[name="response"], input[name="ok"], input[name="cancel"]'
+ ).fadeOut(speed, show_loading);
+
+ return false;
+ });
+}
+
+jQuery(function() {
+ love_letter_init_form_$love_letter_id();
+});
+</script>
+<form
+ class="@{[ $args->{'class'} || 'love_letter' ]}"
+ action="@{[ $app->base . $app->mt_uri ]}"
+ method="post"
+ id="love_letter_form_$love_letter_id"
+>
+<input type="hidden" name="__mode" value="love_letter" />
+<input type="hidden" name="entry_id" value="$entry_id" /> <input type="hidden" name="template_id" value="$template_id" />
+<input type="hidden" name="love_letter_id" value="$love_letter_id" />
+<div id="love_letter_container_$love_letter_id">
+$res
+</form>
+__EOF__
+
+ $res;
+}
+
+sub _hdlr_if_love_letter_ok {
+ my($ctx, $args, $cond) = @_;
+ my $tmpl = $ctx->stash('template');
+ my $app = MT->instance;
+
+ my $res = '';
+ my $builder = $ctx->stash('builder');
+ my $tokens = $ctx->stash('tokens');
+
+ defined($res = $builder->build($ctx, $tokens, $cond))
+ or return $ctx->error( $builder->errstr );
+
+ $res = <<__EOF__;
+<div name="if_love_letter_ok" style="display: none">
+$res
+</div>
+__EOF__
+
+ $res;
+}
+
+sub _hdlr_if_love_letter_cancel {
+ my($ctx, $args, $cond) = @_;
+ my $tmpl = $ctx->stash('template');
+ my $app = MT->instance;
+
+ my $res = '';
+ my $builder = $ctx->stash('builder');
+ my $tokens = $ctx->stash('tokens');
+
+ defined($res = $builder->build($ctx, $tokens, $cond))
+ or return $ctx->error( $builder->errstr );
+
+ $res = <<__EOF__;
+<div name="if_love_letter_cancel" style="display: none">
+$res
+</div>
+__EOF__
+
+ $res;
+}
+
+sub app_love_letter {
+ my ($app) = @_;
+
+ my $plugin = MT->component('Lovers');
+
+ my $ll_class = $app->model('love_letter');
+ my $ll = $ll_class->load({
+ entry_id => $app->param('entry_id') || 0,
+ template_id => $app->param('template_id') || 0,
+ love_letter_id => $app->param('love_letter_id') || 0,
+ });
+
+ if (! $ll) {
+ return <<__MSG__;
+<message>@{[
+ $plugin->translate('unknown love letter')
+]}</message>
+__MSG__
+ }
+
+ if (! $app->param('ok') && ! $app->param('cancel')) {
+ return <<__MSG__;
+<message>@{[
+ $plugin->translate('vague response')
+]}</message>
+__MSG__
+ }
+
+ my $param = $ll->mail_param;
+ $param->{'message'} = $app->param('response') || '';
+ $param->{'ok'} = $app->param('ok') ? 1 : 0;
+
+ my $tmpl = $plugin->load_tmpl('mail_response.tmpl');
+ my $body = MT->translate_templatized(
+ $tmpl->output($param)
+ );
+ my $cfg = $app->config;
+
+ my %head = (
+ id => 'love_letter',
+ To => $param->{'from'},
+ From => $param->{'to'} || $param->{'from'},
+ Subject => $plugin->translate('You got response of love letter.'),
+ );
+ my $charset = $cfg->MailEncoding || $cfg->PublishCharset;
+ $head{'Content-Type'} = qq(text/plain; charset="$charset");
+
+ require MT::Mail;
+ MT::Mail->send( \%head, $body )
+ or return $app->error( MT::Mail->errstr() );
+
+ return <<__MSG__;
+<message>ok</message>
+__MSG__
+
}
sub post_build {
%Lexicon = (
'Provide Movable Type functions for lovers.' => '心と心の交流を促進します',
'My heart begins to throb...' => 'ドキドキしています',
+
+ 'You got love letter.' => 'ラブレターが届きました',
+ 'You got response of love letter.' => 'ラブレターの返事が届きました',
+
+ 'unknown error' => '原因不明のエラーです',
+ 'unknown love letter' => '不明なラブレターです',
+ 'vague response' => '曖昧な回答です',
+
+ 'It is a love letter from [_1]' => '[_1]さんからのラブレターです',
+ 'Detail of message is here: [_1]' => '詳細はこちら: [_1]',
+
+ 'It is a response from [_1]' => '[_1]さんからの返事です',
+
+ 'OK button was pressed.' => 'OKされました',
+ 'Cancel button was pressed.' => 'キャンセルされました',
+
+ 'wrong password' => 'パスワードが間違っています',
+ 'Please input password.' => 'パスワードを入力してください',
+ 'show love letter' => 'ラブレターを読む',
);
1;
--- /dev/null
+# Copyright (c) 2008 Movable Type ACME Plugin Project, All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+package Lovers::LoveLetter;
+use strict;
+
+use MT::Object;
+use base qw( MT::Object );
+
+__PACKAGE__->install_properties({
+ column_defs => {
+ 'id' => 'integer not null auto_increment',
+
+ 'love_letter_id' => 'string(255)',
+ 'entry_id' => 'integer not null',
+ 'template_id' => 'integer not null',
+ 'author_id' => 'integer not null',
+
+ 'from' => 'string(255)',
+ 'to' => 'string(255)',
+
+ 'sent_on' => 'datetime',
+ },
+ audit => 1,
+ indexes => {
+ love_letter_id => 1,
+ },
+ default => {
+ sent_on => '00000000000000',
+ },
+ datasource => 'love_letter',
+ primary_key => 'id',
+});
+
+sub mail_param {
+ my $self = shift;
+ my $app = MT->instance;
+ my $param = $self->column_values;
+ if (! $param->{'from'}) {
+ my $author_class = $app->model('author');
+ my $author = $author_class->load($param->{'author_id'});
+ $param->{'from'} =
+ $author->nickname
+ . ' <' . $author->email . '>';
+ }
+
+ $param;
+}
+
+1;
--- /dev/null
+/* CryptoCipherCamellia.js:
+ * 100% Pure JavaScript Camellia 128-bit block cipher library.
+ * This library is public domain.
+ *
+ * Hiroyuki OYAMA, oyama@module.jp, http://module.jp/
+ */
+
+
+var PACKAGE = CryptoCipherCamellia = function() {
+ this.key_length = 128/8;
+ this.blocksize = 128/8;
+ this.kw = new Array(8*4);
+ this.k = new Array(24*8);
+ this.kl = new Array(8*6);
+ this.S1 = [
+ 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65,
+ 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189,
+ 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26,
+ 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77,
+ 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153,
+ 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215,
+ 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34,
+ 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80,
+ 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210,
+ 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148,
+ 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226,
+ 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46,
+ 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89,
+ 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250,
+ 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164,
+ 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158
+ ];
+ this.S2 = [
+ 224, 5, 88,217,103, 78,129,203,201, 11,174,106,213, 24, 93,130,
+ 70,223,214, 39,138, 50, 75, 66,219, 28,158,156, 58,202, 37,123,
+ 13,113, 95, 31,248,215, 62,157,124, 96,185,190,188,139, 22, 52,
+ 77,195,114,149,171,142,186,122,179, 2,180,173,162,172,216,154,
+ 23, 26, 53,204,247,153, 97, 90,232, 36, 86, 64,225, 99, 9, 51,
+ 191,152,151,133,104,252,236, 10,218,111, 83, 98,163, 46, 8,175,
+ 40,176,116,194,189, 54, 34, 56,100, 30, 57, 44,166, 48,229, 68,
+ 253,136,159,101,135,107,244, 35, 72, 16,209, 81,192,249,210,160,
+ 85,161, 65,250, 67, 19,196, 47,168,182, 60, 43,193,255,200,165,
+ 32,137, 0,144, 71,239,234,183, 21, 6,205,181, 18,126,187, 41,
+ 15,184, 7, 4,155,148, 33,102,230,206,237,231, 59,254,127,197,
+ 164, 55,177, 76,145,110,141,118, 3, 45,222,150, 38,125,198, 92,
+ 211,242, 79, 25, 63,220,121, 29, 82,235,243,109, 94,251,105,178,
+ 240, 49, 12,212,207,140,226,117,169, 74, 87,132, 17, 69, 27,245,
+ 228, 14,115,170,241,221, 89, 20,108,146, 84,208,120,112,227, 73,
+ 128, 80,167,246,119,147,134,131, 42,199, 91,233,238,143, 1, 61
+ ];
+ this.S3 = [
+ 56, 65, 22,118,217,147, 96,242,114,194,171,154,117,6, 87,160,
+ 145,247,181,201,162,140,210,144,246,7,167,39,142,178,73,222,
+ 67, 92,215,199,62,245,143,103,31,24,110,175,47,226,133,13,
+ 83,240,156,101,234,163,174,158,236,128,45,107,168,43,54,166,
+ 197,134,77,51,253,102,88,150,58,9,149,16,120,216,66,204,
+ 239, 38,229,97,26,63,59,130,182,219,212,152,232,139,2,235,
+ 10, 44,29,176,111,141,136,14,25,135,78,11,169,12,121,17,
+ 127, 34,231,89,225,218,61,200,18,4,116,84,48,126,180,40,
+ 85,104,80,190,208,196,49,203,42,173,15,202,112,255,50,105,
+ 8, 98,0,36,209,251,186,237,69,129,115,109,132,159,238,74,
+ 195, 46,193,1,230,37,72,153,185,179,123,249,206,191,223,113,
+ 41,205,108,19,100,155,99,157,192,75,183,165,137,95,177,23,
+ 244,188,211,70,207,55,94,71,148,250,252,91,151,254,90,172,
+ 60, 76,3,53,243,35,184,93,106,146,213,33,68,81,198,125,
+ 57,131,220,170,124,119,86,5,27,164,21,52,30,28,248,82,
+ 32, 20,233,189,221,228,161,224,138,241,214,122,187,227, 64, 79
+ ];
+ this.S4 = [
+ 112, 44,179,192,228, 87,234,174, 35,107, 69,165,237, 79, 29,146,
+ 134,175,124, 31, 62,220, 94, 11,166, 57,213, 93,217, 90, 81,108,
+ 139,154,251,176,116, 43,240,132,223,203, 52,118,109,169,209, 4,
+ 20, 58,222, 17, 50,156, 83,242,254,207,195,122, 36,232, 96,105,
+ 170,160,161, 98, 84, 30,224,100, 16, 0,163,117,138,230, 9,221,
+ 135,131,205,144,115,246,157,191, 82,216,200,198,129,111, 19, 99,
+ 233,167,159,188, 41,249, 47,180,120, 6,231,113,212,171,136,141,
+ 114,185,248,172, 54, 42, 60,241, 64,211,187, 67, 21,173,119,128,
+ 130,236, 39,229,133, 53, 12, 65,239,147, 25, 33, 14, 78,101,189,
+ 184,143,235,206, 48, 95,197, 26,225,202, 71, 61, 1,214, 86, 77,
+ 13,102,204, 45, 18, 32,177,153, 76,194,126, 5,183, 49, 23,215,
+ 88, 97, 27, 28, 15, 22, 24, 34, 68,178,181,145, 8,168,252, 80,
+ 208,125,137,151, 91,149,255,210,196, 72,247,219, 3,218, 63,148,
+ 92, 2, 74, 51,103,243,127,226,155, 38, 55, 59,150, 75,190, 46,
+ 121,140,110,142,245,182,253, 89,152,106, 70,186, 37, 66,162,250,
+ 7, 85,238, 10, 73,104, 56,164, 40,123,201,193,227,244,199,158
+ ];
+ this.SIGMA1 = [ 0xA0, 0x9E, 0x66, 0x7F, 0x3B, 0xCC, 0x90, 0x8B ];
+ this.SIGMA2 = [ 0xB6, 0x7A, 0xE8, 0x58, 0x4C, 0xAA, 0x73, 0xB2 ];
+ this.SIGMA3 = [ 0xC6, 0xEF, 0x37, 0x2F, 0xE9, 0x4F, 0x82, 0xBE ];
+ this.SIGMA4 = [ 0x54, 0xFF, 0x53, 0xA5, 0xF1, 0xD3, 0x6F, 0x1C ];
+ this.SIGMA5 = [ 0x10, 0xE5, 0x27, 0xFA, 0xDE, 0x68, 0x2D, 0x1D ];
+ this.SIGMA6 = [ 0xB0, 0x56, 0x88, 0xC2, 0xB3, 0xE6, 0xC1, 0xFD ];
+ return this;
+};
+
+
+
+PACKAGE.prototype._xor_block = function (x, y, l) {
+ var r = new Array(l);
+ for (var i = 0; i < l; i++) {
+ r[i] = x[i] ^ y[i];
+ }
+ return r;
+};
+
+
+PACKAGE.prototype._feistel = function (dist, off, x, k) {
+ var ws = new Array(8);
+ var w = this._xor_block(x, k, 8);
+ ws[0] = this.S1[w[0]];
+ ws[1] = this.S2[w[1]];
+ ws[2] = this.S3[w[2]];
+ ws[3] = this.S4[w[3]];
+ ws[4] = this.S2[w[4]];
+ ws[5] = this.S3[w[5]];
+ ws[6] = this.S4[w[6]];
+ ws[7] = this.S1[w[7]];
+ dist[0+off] ^= ws[0] ^ ws[2] ^ ws[3] ^ ws[5] ^ ws[6] ^ ws[7];
+ dist[1+off] ^= ws[0] ^ ws[1] ^ ws[3] ^ ws[4] ^ ws[6] ^ ws[7];
+ dist[2+off] ^= ws[0] ^ ws[1] ^ ws[2] ^ ws[4] ^ ws[5] ^ ws[7];
+ dist[3+off] ^= ws[1] ^ ws[2] ^ ws[3] ^ ws[4] ^ ws[5] ^ ws[6];
+ dist[4+off] ^= ws[0] ^ ws[1] ^ ws[5] ^ ws[6] ^ ws[7];
+ dist[5+off] ^= ws[1] ^ ws[2] ^ ws[4] ^ ws[6] ^ ws[7];
+ dist[6+off] ^= ws[2] ^ ws[3] ^ ws[4] ^ ws[5] ^ ws[7];
+ dist[7+off] ^= ws[0] ^ ws[3] ^ ws[4] ^ ws[5] ^ ws[6];
+};
+
+
+PACKAGE.prototype._rot_shift = function (dist, off, src, bit, len) {
+ if (bit == 0) {
+ this._move(dist, 0, src, 0, len);
+ return;
+ }
+ var o = Math.floor(bit / 8) + 1;
+ var so = o * 8 - bit;
+ o = o % len;
+ for (var i = 0; i < len; i++) {
+ dist[i+off] = ((src[(i+o)%len] >> so) & 0xff)
+ | ((src[(i+o-1)%len] << (8-so)) & 0xff);
+ }
+};
+
+
+PACKAGE.prototype.setup = function (key) {
+ var kl = new Array();
+ var kr = new Array();
+ var ka = new Array();
+
+ this.key_length = key.length;
+ if (key.length == 16) {
+ kl = key.slice(0, 16);
+ kr = new Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+ }
+ else if (key.length == 24) {
+ kl = key.slice(0, 16);
+ for (var i = 0; i < 8; i++) {
+ kr[i] = key[i+16];
+ kr[i+8] = key[i+16] ^ 0xff;
+ }
+ }
+ else if (key.length == 32) {
+ kl = key.slice(0, 16);
+ kr = key.slice(16, 32);
+ }
+ else {
+ throw "wrong key length: key must be 128, 192 or 256 bit";
+ }
+
+ ka = this._xor_block(kl, kr, 16);
+ this._feistel(ka, 8, ka, this.SIGMA1);
+ this._feistel(ka, 0, ka.slice(8, 16), this.SIGMA2);
+ ka = this._xor_block(kl, ka, 16);
+
+ this._feistel(ka, 8, ka.slice(0, 8), this.SIGMA3);
+ this._feistel(ka, 0, ka.slice(8, 16), this.SIGMA4);
+
+ if (key.length == 16) {
+ this._rot_shift(this.kw, 0, kl, 0, 16);
+
+ this._rot_shift(this.k, 0, ka, 0, 16);
+ this._rot_shift(this.k, 8*2, kl, 15, 16);
+ this._rot_shift(this.k, 8*4, ka, 15, 16);
+
+ this._rot_shift(this.kl, 0, ka, 30, 16);
+
+ this._rot_shift(this.k, 8*6, kl, 45, 16);
+ this._rot_shift(this.k, 8*8, ka, 45, 16);
+ this._rot_shift(this.k, 8*9, kl, 60, 16);
+ this._move(this.k, 8*9, this.k.slice(8*10, 8*10+8), 0, 8);
+ this._rot_shift(this.k, 8*10, ka, 60, 16);
+
+ this._rot_shift(this.kl, 8*2, kl, 77, 16);
+
+ this._rot_shift(this.k, 8*12, kl, 94, 16);
+ this._rot_shift(this.k, 8*14, ka, 94, 16);
+ this._rot_shift(this.k, 8*16, kl, 111, 16);
+
+ this._rot_shift(this.kw, 8*2, ka, 111, 16);
+ }
+ else {
+ var kb = this._xor_block(kr, ka, 16);
+ this._feistel(kb, 8, kb.slice(0, 8), this.SIGMA5);
+ this._feistel(kb, 0, kb.slice(8, 16), this.SIGMA6);
+
+ this._rot_shift(this.kw, 0, kl, 0, 16);
+
+ this._rot_shift(this.k, 0, kb, 0, 16);
+ this._rot_shift(this.k, 8*2, kr, 15, 16);
+ this._rot_shift(this.k, 8*4, ka, 15, 16);
+
+ this._rot_shift(this.kl, 0, kr, 30, 16);
+
+ this._rot_shift(this.k, 8*6, kb, 30, 16);
+ this._rot_shift(this.k, 8*8, kl, 45, 16);
+ this._rot_shift(this.k, 8*10, ka, 45, 16);
+
+ this._rot_shift(this.kl, 8*2, kl, 60, 16);
+
+ this._rot_shift(this.k, 8*12, kr, 60, 16);
+ this._rot_shift(this.k, 8*14, kb, 60, 16);
+ this._rot_shift(this.k, 8*16, kl, 77, 16);
+
+ this._rot_shift(this.kl, 8*4, ka, 77, 16);
+
+ this._rot_shift(this.k, 8*18, kr, 94, 16);
+ this._rot_shift(this.k, 8*20, ka, 94, 16);
+ this._rot_shift(this.k, 8*22, kl, 111, 16);
+
+ this._rot_shift(this.kw, 8*2, kb, 111, 16);
+ }
+};
+
+
+PACKAGE.prototype._flayer = function (dist, x, k) {
+ this._move(dist, 0, x, 0, 8);
+ dist[4+0] ^= (((x[0] & k[0]) << 1) & 0xff) ^ (x[1] & k[1]) >> 7;
+ dist[4+1] ^= (((x[1] & k[1]) << 1) & 0xff) ^ (x[2] & k[2]) >> 7;
+ dist[4+2] ^= (((x[2] & k[2]) << 1) & 0xff) ^ (x[3] & k[3]) >> 7;
+ dist[4+3] ^= (((x[3] & k[3]) << 1) & 0xff) ^ (x[0] & k[0]) >> 7;
+ dist[0] ^= dist[4+0] | k[4+0];
+ dist[1] ^= dist[4+1] | k[4+1];
+ dist[2] ^= dist[4+2] | k[4+2];
+ dist[3] ^= dist[4+3] | k[4+3];
+};
+
+
+PACKAGE.prototype._flayer_1 = function (dist, x, k) {
+ this._move(dist, 0, x, 0, 8);
+ dist[0] ^= x[4+0] | k[4+0];
+ dist[1] ^= x[4+1] | k[4+1];
+ dist[2] ^= x[4+2] | k[4+2];
+ dist[3] ^= x[4+3] | k[4+3];
+ dist[4+0] ^= (((dist[0] & k[0]) << 1) & 0xff) ^ (dist[1] & k[1]) >> 7;
+ dist[4+1] ^= (((dist[1] & k[1]) << 1) & 0xff) ^ (dist[2] & k[2]) >> 7;
+ dist[4+2] ^= (((dist[2] & k[2]) << 1) & 0xff) ^ (dist[3] & k[3]) >> 7;
+ dist[4+3] ^= (((dist[3] & k[3]) << 1) & 0xff) ^ (dist[0] & k[0]) >> 7;
+
+};
+
+
+PACKAGE.prototype.encrypt = function (src) {
+ var l = new Array(8);
+ var r = new Array(8);
+ l = src.slice(0, 8);
+ r = src.slice(8, 16);
+
+ l = this._xor_block(l, this.kw.slice(0, 8), 8);
+ r = this._xor_block(r, this.kw.slice(8, 16), 8);
+ if (this.key_length == 16) {
+ for (var i = 0; i < 18; i += 2) {
+ this._feistel(r, 0, l, this.k.slice(8*i, (8*i)+8));
+ this._feistel(l, 0, r, this.k.slice(8*(i+1), 8*(i+1)+8));
+ if (i == 4) {
+ this._flayer(l, l, this.kl, 0);
+ this._flayer_1(r, r, this.kl.slice(8, 16), 0);
+ }
+ else if (i == 10) {
+ this._flayer(l, l, this.kl.slice(16, 24), 0);
+ this._flayer_1(r, r, this.kl.slice(24, 32), 0);
+ }
+ }
+ }
+ else {
+ for (var i = 0; i < 24; i += 2) {
+ this._feistel(r, 0, l, this.k.slice(8*i, (8*i)+8));
+ this._feistel(l, 0, r, this.k.slice(8*(i+1), 8*(i+1)+8));
+ if (i == 4) {
+ this._flayer(l, l, this.kl, 0);
+ this._flayer_1(r, r, this.kl.slice(8, 16), 0);
+ }
+ else if (i == 10) {
+ this._flayer(l, l, this.kl.slice(16, 24), 0);
+ this._flayer_1(r, r, this.kl.slice(24, 32), 0);
+ }
+ else if (i == 16) {
+ this._flayer(l, l, this.kl.slice(32, 40), 0);
+ this._flayer_1(r, r, this.kl.slice(40, 48), 0);
+ }
+ }
+ }
+ r = this._xor_block(r, this.kw.slice(16, 24), 8);
+ l = this._xor_block(l, this.kw.slice(24, 32), 8);
+
+ return r.concat(l);
+};
+
+
+PACKAGE.prototype.decrypt = function (src) {
+ var l = new Array(8);
+ var r = new Array(8);
+
+ r = src.slice(0, 8);
+ l = src.slice(8, 16);
+
+ r = this._xor_block(r, this.kw.slice(8*2, 8*2+8), 8);
+ l = this._xor_block(l, this.kw.slice(8*3, 8*3+8), 8);
+ if (this.key_length == 16) {
+ for (var i = 16; i >= 0; i -= 2) {
+ this._feistel(l, 0, r, this.k.slice(8*(i+1), 8*(i+1)+8));
+ this._feistel(r, 0, l, this.k.slice(8*i, (8*i)+8));
+ if (i == 12) {
+ this._flayer(r, r, this.kl.slice(8*3, 8*3+8), 0);
+ this._flayer_1(l, l, this.kl.slice(8*2, 8*2+8), 0);
+ }
+ else if (i == 6) {
+ this._flayer(r, r, this.kl.slice(8*1, 8*1+8), 0);
+ this._flayer_1(l, l, this.kl.slice(8*0, 8*0+8), 0);
+ }
+ }
+ }
+ else {
+ for (var i = 22; i >= 0; i -= 2) {
+ this._feistel(l, 0, r, this.k.slice(8*(i+1), 8*(i+1)+8));
+ this._feistel(r, 0, l, this.k.slice(8*i, (8*i)+8));
+ if (i == 18) {
+ this._flayer(r, r, this.kl.slice(8*5, 8*5+8), 0);
+ this._flayer_1(l, l, this.kl.slice(8*4, 8*4+8), 0);
+ }
+ else if (i == 12) {
+ this._flayer(r, r, this.kl.slice(8*3, 8*3+8), 0);
+ this._flayer_1(l, l, this.kl.slice(8*2, 8*2+8), 0);
+ }
+ else if (i == 6) {
+ this._flayer(r, r, this.kl.slice(8*1, 8*1+8), 0);
+ this._flayer_1(l, l, this.kl.slice(8*0, 8*0+8), 0);
+ }
+ }
+ }
+ l = this._xor_block(l, this.kw.slice(8*0, 8*0+8), 8);
+ r = this._xor_block(r, this.kw.slice(8*1, 8*1+8), 8);
+
+ return l.concat(r);
+};
+
+
+/*
+ * Util methods
+ */
+PACKAGE.prototype._print = function (msg) {
+ document.write(msg, "<br />\n");
+};
+
+
+PACKAGE.prototype._print_hex = function (lavel, src, length) {
+ document.write(lavel);
+ for (var i = 0; i < length; i++) {
+ var num = src[i] != null ? src[i].toString(16) : 'xx';
+ document.write(num.length == 1 ? ('0' + num) : num);
+ }
+ document.write("<br />\n");
+};
+
+PACKAGE.prototype._move = function (dist, offd, src, offs, len) {
+ for (var i = 0; i < len; i++) {
+ dist[i+offd] = src[i+offs];
+ }
+}
+
+
+
+
+/*
+ * CryptoModeCBC.js
+ */
+PACKAGE = CryptoModeCBC = function(cipher, key, iv) {
+ this.cipher = cipher;
+ this.cipher.setup(key);
+ this.iv = iv;
+};
+
+
+PACKAGE.prototype.encrypt = function (plain_text) {
+ var pad = this.cipher.blocksize - (plain_text.length % this.cipher.blocksize);
+ for (var i = 0; pad <= this.cipher.blocksize && i < pad; i++) {
+ plain_text = plain_text.concat(pad);
+ }
+ var nblocks = Math.floor(plain_text.length / this.cipher.blocksize);
+ var block = this.iv.slice(0, this.cipher.blocksize);
+ var block2;
+ var result = new Array(this.cipher.blocksize*nblocks);
+ for (var i = 0; i < nblocks; i++) {
+ for (var j = 0; j < this.cipher.blocksize; j++) {
+ block[j] ^= plain_text[i*this.cipher.blocksize + j];
+ }
+ block2 = this.cipher.encrypt(block);
+ block = block2;
+ for (var l = 0; l < this.cipher.blocksize; l++) {
+ result[i*this.cipher.blocksize+l] = block2[l];
+ }
+ }
+
+ return result;
+};
+
+
+PACKAGE.prototype.decrypt = function (cipher_text) {
+ var nblocks = Math.floor(cipher_text.length / this.cipher.blocksize);
+ var result = new Array(this.cipher.blocksize * nblocks);
+ var block = this.cipher.decrypt(cipher_text.slice(0, this.cipher.blocksize));
+ for (var j = 0; j < this.cipher.blocksize; j++) {
+ result[j] = block[j] ^= this.iv[j];
+ }
+ for (var i = 1; i < nblocks; i++) {
+ block = this.cipher.decrypt(cipher_text.slice(this.cipher.blocksize * i, this.cipher.blocksize*i+this.cipher.blocksize));
+ for (var j = 0; j < this.cipher.blocksize; j++) {
+ block[j] ^= cipher_text[this.cipher.blocksize*(i-1)+j];
+ result[this.cipher.blocksize*i+j] = block[j];
+ }
+ }
+ var pad = result[result.length - 1];
+ if (pad <= this.cipher.blocksize) {
+ var cut = true;
+ for (var i = result.length - pad; i < result.length; i++) {
+ if (result[i] == pad)
+ continue;
+ cut = false;
+ }
+ if (cut == true) {
+ return result.slice(0, result.length - pad);
+ }
+ }
+
+ return result;
+};
+
+
+
+PACKAGE = CryptoUtil = {};
+/*
+ * en|decode Unicode <-> UTF-8
+ * See ftp://ftp.isi.edu/in-notes/rfc2279.txt
+ */
+PACKAGE.arrayFromString = function (str) {
+ var result = new Array();
+ for (var i = 0; i < str.length; i++) {
+ var c = str.charCodeAt(i);
+ if (c <= 0x7f) {
+ result.push(c);
+ }
+ else if (c <= 0x07ff) {
+ result.push(0xc0 | (c >>> 6));
+ result.push(0x80 | (c & 0x3f));
+ }
+ else if (c <= 0xffff) {
+ result.push(0xe0 | ( c >>> 12));
+ result.push(0x80 | ((c >>> 6) & 0x3f));
+ result.push(0x80 | ( c & 0x3F));
+ }
+ else if (c <= 0x1fffff) {
+ result.push(0xf0 | (c >>> 18));
+ result.push(0x80 | ((c >>> 12) & 0x3f));
+ result.push(0x80 | ((c >>> 6) & 0x3f));
+ result.push(0x80 | ( c & 0x3f));
+ }
+ else if (c <= 0x03ffffff) {
+ result.push(0xf8 | (c >>> 24));
+ result.push(0x80 | ((c >>> 18) & 0x3f));
+ result.push(0x80 | ((c >>> 12) & 0x3f));
+ result.push(0x80 | ((c >>> 6) & 0x3f));
+ result.push(0x80 | ( c & 0x3f));
+ }
+ else if (c <= 0x7fffffff) {
+ result.push(0xfc | (c >>> 30));
+ result.push(0x80 | ((c >>> 24) & 0x3f));
+ result.push(0x80 | ((c >>> 18) & 0x3f));
+ result.push(0x80 | ((c >>> 12) & 0x3f));
+ result.push(0x80 | ((c >>> 6) & 0x3f));
+ result.push(0x80 | ( c & 0x3f));
+ }
+ else {
+ c = 0xfffd;
+ result.push(0xe0 | ( c >> 12));
+ result.push(0x80 | ((c >> 6) & 0x3f));
+ result.push(0x80 | ( c & 0x3F));
+ }
+ }
+ return result;
+};
+
+
+PACKAGE.stringFromArray = function (list) {
+ var result = new String();
+ for (var i = 0; i < list.length; i++) {
+ var c = list[i];
+ if (c <= 0x07f) {
+ result += String.fromCharCode(list[i] & 0x7f);
+ }
+ else if ((c & 0xe0) == 0xc0) {
+ result += String.fromCharCode( ((list[i] & 0x1f) << 6)
+ | (list[i+1] & 0x3f));
+ i += 1;
+ }
+ else if ((c & 0xf0) == 0xe0) {
+ result += String.fromCharCode( (( list[i] & 0x0f) << 12)
+ | ((list[i+1] & 0x3f) << 6)
+ | (list[i+2] & 0x3f));
+ i += 2;
+ }
+ else if ((c & 0xf8) == 0xf0) {
+ result += String.fromCharCode( (( list[i] & 0x07) << 18)
+ | ((list[i+1] & 0x3f) << 12)
+ | ((list[i+2] & 0x3f) << 6)
+ | (list[i+3] & 0x3f));
+ i += 3;
+ }
+ else if ((c & 0xfc) == 0xf8) {
+ result += String.fromCharCode( (( list[i] & 0x03) << 24)
+ | ((list[i+1] & 0x3f) << 18)
+ | ((list[i+2] & 0x3f) << 12)
+ | ((list[i+3] & 0x3f) << 6)
+ | (list[i+4] & 0x3f));
+ i += 4;
+ }
+ else if ((c & 0xfe) == 0xfc) {
+ result += String.fromCharCode( (( list[i] & 0x01) << 30)
+ | ((list[i+1] & 0x3f) << 24)
+ | ((list[i+2] & 0x3f) << 18)
+ | ((list[i+3] & 0x3f) << 12)
+ | ((list[i+4] & 0x3f) << 6)
+ | (list[i+5] & 0x3f));
+ i += 5;
+ }
+
+ }
+ return result;
+}
+
+
+PACKAGE.arrayFromHex = function (hex) {
+ var res = new Array();
+ for (var i = 0; i < hex.length; i += 2) {
+ res.push(parseInt('0x' + hex.charAt(i) + hex.charAt(i+1)));
+ }
+ return res;
+};
+
+
+
+PACKAGE.hexFromArray = function (list) {
+ var res = new String();
+ for (var i in list) {
+ res += (list[i] > 0xf) ? list[i].toString(16) : '0' + list[i].toString(16);
+ }
+ return res;
+};
+
+
+PACKAGE.BASE64TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "abcdefghijklmnopqrstuvwxyz"
+ + "0123456789+/";
+PACKAGE.base64FromArray = function (list) {
+ var mod = list.length % 3;
+ var total = (list.length / 3) * 4 + (3 - mod) % 3 + 1;
+ total += list.length / 57;
+ if ((list.length % 57) > 0)
+ total++;
+
+ if (total < list.length)
+ return null;
+ var i = 0;
+ var out = new String();
+ while (i < (list.length - mod)) {
+ out += PACKAGE.BASE64TABLE.charAt(list[i++] >> 2);
+ out += PACKAGE.BASE64TABLE.charAt(((list[i-1] << 4) | (list[i] >> 4)) & 0x3f);
+ out += PACKAGE.BASE64TABLE.charAt(((list[i] << 2) | (list[i+1] >> 6)) & 0x3f);
+ out += PACKAGE.BASE64TABLE.charAt(list[i+1] & 0x3f);
+ i += 2;
+ if ((i % 57) == 0)
+ out += "\n";
+ }
+ if (!mod) {
+ if ((i % 57) > 0)
+ out += "\n";
+ return out;
+ }
+ else {
+ out += PACKAGE.BASE64TABLE.charAt(list[i++] >> 2);
+ out += PACKAGE.BASE64TABLE.charAt(((list[i-1] << 4) | (list[i] >> 4)) & 0x3f);
+ if (mod == 1) {
+ out += "==\n";
+ }
+ else {
+ out += PACKAGE.BASE64TABLE.charAt((list[i] << 2) & 0x3f);
+ out += "=\n";
+ }
+ return out;
+ }
+};
+
+
+PACKAGE.BASE64REVTABLE = [
+ -3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+];
+PACKAGE.arrayFromBase64 = function (str) {
+ var out = new Array();
+ var buf = new Array();
+ var p = 0;
+ var pad = 0;
+ var err = false;
+ str = str.replace(/[^a-zA-Z0-9=\/\+]+/g, '');
+ while (pad == 0 && str.length >= p) {
+ var x = PACKAGE.BASE64REVTABLE[str.charCodeAt(p)];
+ p++;
+ if (x == -3) {
+ if (((p - 1) % 4) > 0)
+ err = true;
+ return out;
+ }
+ else if (x == -2) {
+ if (((p - 1) % 4) < 2) {
+ err = true;
+ return out;
+ }
+ else if (((p - 1) % 4) == 2) {
+ if (str.charAt(p) != '=') {
+ err = true;
+ return out;
+ }
+ buf[2] = 0;
+ pad = 2;
+ }
+ else {
+ pad = 1;
+ }
+ }
+ else if (x == -1) {
+ err = true;
+ return out;
+ }
+ else {
+ var y = (p - 1) % 4;
+ if (y == 0) {
+ buf[0] = (x << 2) & 0xff;
+ }
+ else if (y == 1) {
+ buf[0] |= (x >>> 4) & 0xff;
+ buf[1] = (x << 4) & 0xff;
+ }
+ else if (y == 2) {
+ buf[1] |= (x >>> 2) & 0xff;
+ buf[2] = (x << 6) & 0xff;
+ }
+ else if (y == 3) {
+ buf[2] |= x & 0xff;
+ for (var i = 0; i < (3 - pad); i++)
+ out.push(buf[i]);
+ }
+ }
+ }
+ for (var i = 0; i < (3 - pad); i++)
+ out.push(buf[i]);
+ return out;
+};
+
--- /dev/null
+<__trans phrase="It is a love letter from [_1]" params="<mt:Var name="from" />" />
+
+<__trans phrase="Detail of message is here: [_1]" params="<mt:Var name="permalink" />" />
--- /dev/null
+<mt:If name="to" trim="1">
+<__trans phrase="It is a response from [_1]" params="<mt:Var name="to" />" />
+</mt:If>
+
+<mt:If name="ok" trim="1">
+<__trans phrase="OK button was pressed." />
+<mt:Else>
+<__trans phrase="Cancel button was pressed." />
+</mt:If>
+<mt:If name="message">
+<mt:Var name="message" />
+</mt:If>