Source

p5-rdf-crypt / lib / RDF / Crypt / Encrypter.pm

Full commit
package RDF::Crypt::Encrypter;

use 5.010;
use Any::Moose;
with qw(
	RDF::Crypt::Role::WithPublicKeys
	RDF::Crypt::Role::DoesEncrypt
	RDF::Crypt::Role::ToString
);

use Crypt::OpenSSL::Random qw[random_bytes];
use MIME::Base64 qw[decode_base64 encode_base64];
use RDF::TrineX::Functions -shortcuts;
use MIME::Base64 qw[];
use RDF::TrineX::Functions -shortcuts;
use Sys::Hostname qw[];

use namespace::clean;

BEGIN {
	$RDF::Crypt::Encrypter::AUTHORITY = 'cpan:TOBYINK';
	$RDF::Crypt::Encrypter::VERSION   = '0.002';
}

sub encrypt_bytes
{
	my ($self, $text) = @_;
	
	my $key = $self->public_keys->[-1];
	confess('Public key too small. Must be at least 64 bytes.') unless $key->size >= 64;
	
	my $block_size = $key->size - 16;
	my $v = my $iv = random_bytes($block_size);
	
	my ($scrambled, $last_length) = ('', 0);
	while (length $text)
	{
		my $block   = substr($text, 0, $block_size);
		$text       = substr($text, length $block);
		
		$v = substr($v, 0, length $block)
			if length $block < $block_size;
			
		$last_length = length $block;
		
		$scrambled .= 
			(my $cypher = $key->encrypt("$block" ^ "$v"));
		$v = substr($cypher, 0, $block_size);
	}

	return encode_base64($iv . pack('n', ($block_size - $last_length)) . $scrambled);
}

1;

=head1 NAME

RDF::Crypt::Encrypter - encrypts RDF graphs

=head1 DESCRIPTION

An Encrypter object is created using an RSA public key. The object can be used
to encrypt an RDF graph for a recipient.

=head2 Constructors

=over

=item C<< new_from_file($file) >>

Given a filename containing a DER or PEM encoded RSA public key, constructs
an Encrypter object.

=item C<< new_from_string($str) >>

Given a string containing a DER or PEM encoded RSA public key, constructs
an Encrypter object.

=item C<< new_from_pubkey($key) >>

Given a L<Crypt::OpenSSL::RSA> public key object, constructs an Encrypter object.

=item C<< new_from_webid($uri) >>

Given a WebID with one of more FOAF+SSL public keys, constructs an Encrypter
object. If multiple public keys are associated with the same WebID, then the one
with the largest key size (most secure) is used.

=back

=head2 Object Methods

=over

=item C<< encrypt_model($model) >>

Returns an encrypted serialisation of the data.

The encryption works by serialising the data as RDF/XML, then
encrypting it with C<encrypt_text>.

=item C<< send_model_by_email($model, \%opts) >>

This method only works on objects that were constructed using C<new_from_webid>.
Encrypts the model for the holder of the WebID, and sends it to an address
specified in the WebID profile using foaf:mbox.

Options:

=over

=item * B<sendmail> - hashref of options for L<Mail::Transport::Sendmail>. The
mere presence of this hashref will trigger L<Mail::Transport::Sendmail> to
be used as the delivery method.

=item * B<smtp> - hashref of options for L<Mail::Transport::SMTP>. The
mere presence of this hashref will trigger L<Mail::Transport::SMTP> to
be used as the delivery method.

=item * B<from> - email address for the message to come from.

=item * B<subject> - message subject.

=item * B<filename> - filename for encrypted attachment.

=item * B<headers> - hashref of additional mail headers.

=back

Returns a the message's Message-ID, or undef if unsuccessful.

=item C<< encrypt_text($str) >>

Bonus method - encrypts a literal string which may or may not have anything
to do with RDF.

The return value is a base64-encoded string. The base64-decoded value consists
of: (1) an initialisation vector, sixteen bytes shorter than the size of the
key; (2) a 16-bit big-endian signed integer indicating the length of padding
which was added to the payload of the message during encryption; (3) the payload,
encrypted using cipher-block chaining with OAEP, with block length sixteen bytes
shorter than the key size. These three parts are concatenated together in that
order.

=back

=head1 SEE ALSO

L<RDF::Crypt::Decrypter>.

=head1 BUGS

Please report any bugs to L<http://rt.cpan.org/>.

=head1 AUTHOR

Toby Inkster E<lt>tobyink@cpan.orgE<gt>.

=head1 COPYRIGHT

Copyright 2010 Toby Inkster

This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut