From 75aa29074f273164a8029d2fd8c963f8de5aea49 Mon Sep 17 00:00:00 2001 From: dakkar Date: Fri, 25 Mar 2011 21:43:42 +0000 Subject: it might even complie --- bin/client | 48 +++++++++++++++ lib/DeWeave/Crypto.pm | 126 ++++++++++++++++++++++++++++++++++++++++ lib/DeWeave/Crypto/KeyBundle.pm | 15 +++++ lib/DeWeave/EDO.pm | 22 +++++++ lib/DeWeave/Storage.pm | 64 ++++++++++++++++++++ lib/DeWeave/WBO.pm | 3 +- 6 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 bin/client create mode 100644 lib/DeWeave/Crypto.pm create mode 100644 lib/DeWeave/Crypto/KeyBundle.pm create mode 100644 lib/DeWeave/Storage.pm diff --git a/bin/client b/bin/client new file mode 100644 index 0000000..26eae71 --- /dev/null +++ b/bin/client @@ -0,0 +1,48 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use FindBin::libs; +use DeWeave::Storage; +use DeWeave::Crypto; +use DeWeave::EDO; +use Getopt::Long; + +my ($server,$username,$password,$sync_key); + +{ +my $p = Getopt::Long::Parser->new( + config => [qw( + no_auto_abbrev + no_getopt_compat + no_gnu_compat + require_order + no_ignore_case + )], +); +die unless $p->getoptions( + 'h|host=s' => \$server, + 'u|user=s' => \$username, + 'p|pass|password=s' => \$password, + 'k|key|sync-key=s' => \$sync_key, +); +} + +my $storage = DeWeave::Storage->new({ + ($server ? (server_uri => $server) : () ), + username => $username, + password => $password, +}); + +my $crypto = DeWeave::Crypto->new({ + storage => $storage, + sync_key => $sync_key, +}); + +use Data::Dump 'pp'; + +my $foo = DeWeave::EDO->from_json( + $storage->get_item('storage/tabs'), + $crypto, +); + +print pp $foo; 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; diff --git a/lib/DeWeave/Crypto/KeyBundle.pm b/lib/DeWeave/Crypto/KeyBundle.pm new file mode 100644 index 0000000..aea89ec --- /dev/null +++ b/lib/DeWeave/Crypto/KeyBundle.pm @@ -0,0 +1,15 @@ +package DeWeave::Crypto::KeyBundle; +use Moose; +use namespace::autoclean; +use MooseX::Types::Moose qw(HashRef Str); +use MooseX::Types::Structured qw(Tuple); + +has _keys => ( + isa => Str, + init_arg => undef, + lazy_build => 1, +); + + + +1; diff --git a/lib/DeWeave/EDO.pm b/lib/DeWeave/EDO.pm index 29a9cee..30fdbf2 100644 --- a/lib/DeWeave/EDO.pm +++ b/lib/DeWeave/EDO.pm @@ -3,6 +3,7 @@ use Moose; use namespace::autoclean; use MooseX::Types::Moose qw(Int Str Num); use JSON::Any; +use Try::Tiny; extends 'DeWeave::WBO'; @@ -24,4 +25,25 @@ has hmac => ( is => 'ro', ); +around BUILDARGS => sub { + my $orig = shift; + my $class = shift; + + my $args = $class->$orig(@_); + return $args unless defined $args->{__crypt}; + + my $decrypted_payload = $args->{__crypt}->decrypt($args); + + if (defined $decrypted_payload) { + try { + my $j = JSON::Any->new; + my $extra_args = $j->decode($decrypted_payload); + + @$args{keys %$extra_args} = + values %$extra_args; + }; + } + return $args; +}; + 1; diff --git a/lib/DeWeave/Storage.pm b/lib/DeWeave/Storage.pm new file mode 100644 index 0000000..0786b7c --- /dev/null +++ b/lib/DeWeave/Storage.pm @@ -0,0 +1,64 @@ +package DeWeave::Crypto; +use Moose; +use namespace::autoclean; +use MooseX::Types::Moose qw(Str); +use LWP::UserAgent; +use MooseX::Types::URI qw(Uri); +use URI::QueryParam; + +has username => ( + isa => Str, + required => 1, + is => 'ro', +); + +has password => ( + isa => Str, + required => 1, + is => 'ro', +); + +has server_uri => ( + isa => Uri, + coerce => 1, + is => 'ro', + default => 'https://weave.thenautilus.net/', +); + +has _useragent => ( + init_arg => undef, + is => 'ro', + lazy_build => 1, +); + +sub _build__useragent { + my ($self) = @_; + + my $ua = LWP::UserAgent->new(); + $ua->env_proxy; + $ua->credentials($self->server_uri->host_port, + $self->username, + $self->password); + $ua->protocols_allowed(['https']); + + return $ua; +} + +sub get_item { + my ($self,$path) = @_; + + my $relative = sprintf '1.0/%s/storage/%s', + $self->username,$path; + my $uri = URI->new_abs($relative,$self->server_uri); + $uri->query_param(full => 1); + my $response = $self->_useragent->get($uri); + + if ($response->is_success) { + return $response->decoded_content; + } + else { + die $response->status_line; + } +} + +1; diff --git a/lib/DeWeave/WBO.pm b/lib/DeWeave/WBO.pm index db89581..3f551dd 100644 --- a/lib/DeWeave/WBO.pm +++ b/lib/DeWeave/WBO.pm @@ -36,7 +36,7 @@ has ttl => ( ); sub from_json { - my ($class,$json)=@_; + my ($class,$json,$crypt)=@_; my $j = JSON::Any->new; @@ -47,6 +47,7 @@ sub from_json { @$args{keys %$extra_args} = values %$extra_args; + $args->{__crypt}=$crypt; }; } -- cgit v1.2.3