summaryrefslogtreecommitdiff
path: root/lib/DeWeave/Crypto.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DeWeave/Crypto.pm')
-rw-r--r--lib/DeWeave/Crypto.pm126
1 files changed, 126 insertions, 0 deletions
diff --git a/lib/DeWeave/Crypto.pm b/lib/DeWeave/Crypto.pm
new file mode 100644
index 0000000..618e095
--- /dev/null
+++ b/lib/DeWeave/Crypto.pm
@@ -0,0 +1,126 @@
+package DeWeave::Crypto;
+use Moose;
+use namespace::autoclean;
+use MooseX::Types::Moose qw(HashRef Str);
+use MooseX::Types::Structured qw(Tuple);
+use JSON::Any;
+use Try::Tiny;
+use Digest::SHA ();
+use MIME::Base32 'RFC';
+use Crypt::CBC;
+
+has storage => (
+ isa => 'DeWeave::Storage',
+ required => 1,
+ is => 'ro',
+);
+
+has sync_key => (
+ isa => Str,
+ required => 1,
+ is => 'ro',
+);
+
+sub _byte_sync_key {
+ my ($self) = @_;
+
+ my $key = $self->sync_key;
+ $key =~ y{89}{lo};
+ return MIME::Base32::decode($key);
+}
+
+has _hmac_input => (
+ isa => Str,
+ default => 'Sync-AES_256_CBC-HMAC256',
+ is => 'ro',
+);
+
+has _encryption_key => (
+ isa => Str,
+ lazy_build => 1,
+ is => 'ro',
+);
+
+sub _build__encryption_key {
+ my ($self) = @_;
+
+ my $secret = $self->_hmac_input
+ . $self->storage->username . "\x01";
+ return Digest::SHA::hmac_sha256($secret, $self->_byte_sync_key);
+}
+
+has _hmac_key => (
+ isa => Str,
+ lazy_build => 1,
+ is => 'ro',
+);
+
+sub _build__hmac_key {
+ my ($self) = @_;
+
+ my $secret = $self->_encryption_key . $self->_hmac_input
+ . $self->storage->username . "\x02";
+ return Digest::SHA::hmac_sha256($secret, $self->_byte_sync_key);
+}
+
+has _keys => (
+ isa => HashRef[Tuple[Str,Str]],
+ init_arg => undef,
+ lazy_build => 1,
+ is => 'ro',
+ traits => ['Hash'],
+ handles => {
+ _has_collection_keys => 'exists',
+ _get_collection_keys => 'get',
+ },
+);
+
+sub _build__keys {
+ my ($self) = @_;
+
+ my $j = JSON::Any->new;
+
+ my $keys_payload = $self->storage->get_item('crypto/keys');
+ my $struct = $j->decode($keys_payload);
+
+ my $keys = {
+ default => $struct->{default},
+ %{$struct->{collections}},
+ };
+
+ return $keys;
+}
+
+sub keys_for_collection {
+ my ($self,$collection) = @_;
+
+ if ($self->_has_collection_keys($collection)) {
+ return $self->_get_collection_keys($collection);
+ }
+ else {
+ return $self->_get_collection_keys('default');
+ }
+}
+
+sub decrypt {
+ my ($self,$args) = @_;
+
+ my $iv = $args->{IV};
+ my $hmac = $args->{hmac};
+ my $ct = $args->{ciphertext};
+
+ my $cipher = Crypt::CBC->new(
+ -key => $self->_encryption_key,
+ -cipher => 'Crypt::OpenSSL::AES',
+ -iv => $iv,
+ -header => 'none',
+ -padding => 'null',
+ -literal_key => 1,
+ );
+
+ my $pt = $cipher->decrypt($ct);
+ # TODO verify
+ return $pt;
+}
+
+1;