Skip to content

Commit

Permalink
add support for PrivateBin format v2
Browse files Browse the repository at this point in the history
  • Loading branch information
grawity committed Nov 27, 2019
1 parent 175cf3e commit afdc394
Showing 1 changed file with 106 additions and 8 deletions.
114 changes: 106 additions & 8 deletions getpaste
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,36 @@ sub follow {
# }}}
# decoders {{{

sub decode_base58 {
my ($str, $alpha) = @_;
# Source: https://metacpan.org/pod/Encode::Base58

use bigint;
use integer;

my @alpha = split(//, $alpha);
my $i = 0;
my %alpha = map { $_ => $i++ } @alpha;

my $decoded = 0;
my $multi = 1;
my $base = @alpha;

while (length $str > 0) {
my $digit = chop $str;
$decoded += $multi * $alpha{$digit};
$multi *= $base;
}

return $decoded->to_bytes;
}

sub decode_privatebin_base58 {
my ($str) = @_;

return decode_base58($str, "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
}

sub decode_sour_base64 {
my ($str) = @_;

Expand Down Expand Up @@ -637,6 +667,64 @@ sub unwrap_openssl_aes {
return Crypt::Mode::CBC->new("AES")->decrypt($data, $key, $iv);
}

sub unwrap_privatebin_v2 {
eval {
require Crypt::AuthEnc::GCM;
require Crypt::KeyDerivation;
} or _die("missing Perl package 'CryptX'");

Crypt::AuthEnc::GCM->import(":all");
Crypt::KeyDerivation->import("pbkdf2");

# serialization: JSON
# key derivation: PBKDF2-SHA256
# encryption: AES256-GCM

my ($data, $passwd) = @_;

if ($data->{v} != 2) {
_die("incorrect paste format version ".$data->{v});
}

my $cparams = $data->{adata}->[0];
my $ct = decode_base64($data->{ct});
my $iv = decode_base64($cparams->[0]);
my $salt = decode_base64($cparams->[1]);
my $iter = $cparams->[2];
my $ks = $cparams->[3] / 8;
my $ts = $cparams->[4] / 8;
my $cipher = $cparams->[5];
my $mode = $cparams->[6];
my $comp = $cparams->[7];

unless ($cipher eq "aes") {
_die("unsupported cipher ".$cipher);
}
unless ($mode eq "gcm") {
_die("unsupported cipher mode ".$mode);
}
unless ($comp eq "zlib") {
_die("unsupported compression ".$comp);
}

my $ikey = decode_privatebin_base58($passwd);
my $dkey = pbkdf2($ikey, $salt, $iter, "SHA256", $ks);

my $hdr = encode_json($data->{adata});
my $tag = substr($ct, -$ts, $ts, "");

if ($mode eq "gcm") {
$data = gcm_decrypt_verify("AES", $dkey, $iv, $hdr, $ct, $tag)
// _die("decryption failed");
}
if ($comp eq "zlib") {
$data = decompress_deflate($data);
}
$data = decode_json($data)->{paste};

return $data;
}

sub unwrap_sjcl {
eval {
require Crypt::AuthEnc::CCM;
Expand Down Expand Up @@ -904,14 +992,24 @@ sub dl_privatebin {
my $body = get($url) // return;
$body = decode_json($body);

my $data = $body->{data};
$data = unwrap_sjcl($data, $frag);
$data = decode_base64($data);
# The example code that comes with js-deflate mistakenly encodes binary
# data as UTF-8, and of course PrivateBin just used it verbatim.
$data = encode("latin1", decode("utf-8", $data));
$data = decompress_deflate($data);
return $data;
if ($body->{v} == 2) {
my $data = $body;
$data = unwrap_privatebin_v2($data, $frag);
return $data;
}
elsif ($body->{data}) {
my $data = $body->{data} // $body;
$data = unwrap_sjcl($data, $frag);
$data = decode_base64($data);
# The example code that comes with js-deflate mistakenly encodes binary
# data as UTF-8, and of course PrivateBin just used it verbatim.
$data = encode("latin1", decode("utf-8", $data));
$data = decompress_deflate($data);
return $data;
}
else {
_die("unrecognized PrivateBin format (did they change things up again?)");
}
}

sub dl_riseup {
Expand Down

0 comments on commit afdc394

Please sign in to comment.