WWW-Suffit

 view release on metacpan or  search on metacpan

lib/WWW/Suffit/JWT.pm  view on Meta::CPAN

        secret => "MySecret",
        payload => {foo => 'bar'},
    );
    my $token = $jwt->encode->token or die $jwt->error;
    my $payload = $jwt->decode($token)->payload;
    die $jwt->error if $jwt->error;

    use WWW::Suffit::RSA;
    my $rsa = WWW::Suffit::RSA->new(key_size => 1024);
    $rsa->keygen;
    my $private_key = $rsa->private_key;
    my $public_key = $rsa->public_key;
    my $jwt = WWW::Suffit::JWT->new(
        private_key => $private_key,
        payload => {foo => 'bar'},
        algorithm => 'RS512',
    );
    my $token = $jwt->encode->token or die $jwt->error;
    my $payload = $jwt->public_key($public_key)->decode($token)->payload;
    die $jwt->error if $jwt->error;

=head1 DESCRIPTION

JSON Web Token for Suffit authorization

lib/WWW/Suffit/JWT.pm  view on Meta::CPAN

The epoch time value before which the JWT value should not be considered valid.
This value (if set and not undefined) will be used as the C<nbf> key in the payload
or was extracted from the payload during the most recent decoding.

=head2 payload

Payload - second part of JWT structure

The payload is a user data structure to be encoded. This must be a hash reference only.

=head2 private_key

The RSA private key to be used in edcoding an asymmetrically signed JWT. See L<WWW::Suffit::RSA>

=head2 public_key

The RSA public key to be used in decoding an asymmetrically signed JWT. See L<WWW::Suffit::RSA>

=head2 secret

The symmetric secret used in encoding an symmetrically HMAC

lib/WWW/Suffit/JWT.pm  view on Meta::CPAN

Returns the HMAC SHA signature for the given size and string.
The L</secret> attribute is used as the symmetric key.
The result is base64url encoded!
This method is provided mostly for the purposes of subclassing.

=head2 sign_rsa

    my $signature = $jwt->sign_rsa($size, $string);

Returns the RSA signature for the given size and string.
The L</private_key> attribute is used as the private key.
The result is base64url encoded!
This method is provided mostly for the purposes of subclassing.

=head2 verify_hmac

    my $bool = $jwt->verify_hmac($size, $string, $signature);

Returns true if the given HMAC size algorithm validates the given string and signature.
The L</secret> attribute is used as the HMAC passphrase.
The signature is base64url encoded!

lib/WWW/Suffit/JWT.pm  view on Meta::CPAN


use constant DEFAULT_ALGORITHM => 'HS256';

has 'token'; # Result token
has 'secret' => ''; # For HMAC
has 'algorithm' => DEFAULT_ALGORITHM(); # By default
has 'expires'; # Expire time
has 'not_before'; # Time "not before"
has 'iat' => 0; # Payload iat param
has 'jti' => 0; # Payload jti param
has 'private_key'; # For RSA
has 'public_key'; # For RSA
has 'error' => ''; # Error string
has 'header' => sub { {} }; # Header (first part of JWT)
has 'payload' => sub { {} }; # Payload (second parg of JWT)

# Regexps
my $re_hs = qr/^HS(\d+)$/; # HMAC
my $re_rs = qr/^RS(\d+)$/; # RSA

sub encode {

lib/WWW/Suffit/JWT.pm  view on Meta::CPAN


    # Sign!
    my $sign = $f->($concat, $secret) // '';
    return '' unless length $sign;
    return encode_base64url($sign);
}
sub sign_rsa {
    my ($self, $size, $concat) = @_;

    # Get RSA private key
    my $private_key = $self->private_key;
    $self->error('Private key (private_key) not specified') && return unless $private_key;

    # Create RSA object
    my $rsa = WWW::Suffit::RSA->new(private_key => $private_key);

    # Sign!
    my $sign = $rsa->sign($concat, $size) // '';
    unless (length($sign)) {
        $self->error($rsa->error);
        return;
    }
    return _b64_to_b64url($sign);
}
sub verify_hmac {

lib/WWW/Suffit/RSA.pm  view on Meta::CPAN


WWW::Suffit::RSA - The RSA encryption and signing subclass

=head1 SYNOPSIS

    use WWW::Suffit::RSA;

    my $rsa = WWW::Suffit::RSA->new;

    $rsa->keygen(2048);
    my $private_key = $rsa->private_key;
    my $public_key = $rsa->public_key;

    my $b64_cipher_text = $rsa->encrypt("test");
    my $plain_text = $rsa->decrypt($b64_cipher_text);

    my $signature = $rsa->sign("Text", 256) or die $rsa->error;
    $rsa->verify("Text", $signature, 256) or die $rsa->error || "Incorrect signature";

=head1 DESCRIPTION

lib/WWW/Suffit/RSA.pm  view on Meta::CPAN


    $rsa->error($new_error);
    my $error = $rsa->error;

Sets/gets the error string

=head2 keygen

    $rsa->keygen( $key_size );
    my $public_key = $rsa->public_key;
    my $private_key = $rsa->private_key;

Create a new private/public key pair (the public exponent is 65537).
The argument is the key size, default is 2048

=head2 private_key

The RSA private key to be used in edcoding an asymmetrically signed data

=head2 public_key

The RSA public key to be used in decoding an asymmetrically signed data

=head2 sign

    my $signature = $rsa->sign($string, $size);

Returns the RSA signature for the given size and string.
The L</private_key> attribute is used as the private key.
The result is not yet base64 encoded.
This method is provided mostly for the purposes of subclassing.

=head2 verify

    my $bool = $rsa->verify($string, $signature, $size);

Returns true if the given RSA size algorithm validates the given string and signature.
The L</public_key> attribute is used as the public key.
This method is provided mostly for the purposes of subclassing.

lib/WWW/Suffit/RSA.pm  view on Meta::CPAN


use constant {
    KEY_SIZE        => 2048,
    SHA_SIZE        => 256,
    KEY_SIZES_MAP   => [512, 1024, 2048, 4096],
    SHA_SIZES_MAP   => [224, 256, 384, 512],
};

has 'key_size'      => KEY_SIZE; # RSA key size
has 'sha_size'      => SHA_SIZE; # RSA SHA size
has 'private_key'   => ''; # RSA private key
has 'public_key'    => ''; # RSA public key
has 'error'         => ''; # Error string

sub keygen {
    my $self = shift;
    my $key_size = shift || $self->key_size || KEY_SIZE;
    $self->error(''); # Flush error string first

    # Correct key size
    $key_size = KEY_SIZE
        unless grep {$_ == $key_size} @{(KEY_SIZES_MAP)};

    my $rsa = Crypt::OpenSSL::RSA->generate_key($key_size);
    my $private_key = $rsa->get_private_key_string;
       $self->private_key($private_key);
    my $public_key = $rsa->get_public_key_string;
       $self->public_key($public_key);

    return $self;
}
sub encrypt {
    my ($self, $text) = @_;
    $self->error(''); # Flush error string first
    $self->error('The text for encrypting is not specified') && return unless $text;

lib/WWW/Suffit/RSA.pm  view on Meta::CPAN

    }

    return b64_encode($rsa_pub->encrypt($text), '');
}
sub decrypt {
    my ($self, $cipher) = @_;
    $self->error(''); # Flush error string first
    $self->error('The ciphertext for decryption is not specified') && return unless $cipher;

    # Get RSA private key
    my $private_key = $self->private_key // '';
    $self->error('Private key not specified') && return unless length $private_key;

    # Create RSA object
    my $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($private_key);

    my $plaintext = eval {$rsa_priv->decrypt(b64_decode($cipher))} // '';
    if ($@) {
        chomp $@;
        $self->error($@);
        return;
    }

    return $plaintext;
}
sub sign {
    my ($self, $text, $size) = @_;
    $size ||= $self->sha_size || SHA_SIZE;
    $self->error(''); # Flush error string first

    # Get RSA private key
    my $private_key = $self->private_key // '';
    $self->error('Private key not specified') && return unless length $private_key;

    # Correct sha size
    $size = SHA_SIZE
        unless grep {$_ == $size} @{(SHA_SIZES_MAP)};

    # Create RSA object
    my $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($private_key);

    my $m = $rsa_priv->can("use_sha${size}_hash");
    $self->error('Unsupported SHA hash size') && return unless $m;
    $rsa_priv->$m; # Switch to alg

    # Sign!
    return b64_encode($rsa_priv->sign($text), '');
}
sub verify {
    my ($self, $text, $signature, $size) = @_;

t/03-rsa.t  view on Meta::CPAN

# under the same terms as Perl itself.
#
#########################################################################
use Test::More tests => 4;
use WWW::Suffit::RSA;

my $rsa = WWW::Suffit::RSA->new(key_size => 512);

# Key gen
$rsa->keygen;
my $private_key = $rsa->private_key;
my $public_key = $rsa->public_key;
ok(length $private_key // '', 'Private key');
ok(length $public_key // '', 'Public key');

# Encrypt/Decrypt
{
    my $plaintext = "My test string";
    my $ciphertext = $rsa->encrypt($plaintext);
    my $outtext = $rsa->decrypt($ciphertext);
    is $plaintext, $outtext, 'RSA Encrypt/Decrypt strings' or diag $rsa->error;
}

t/05-jwt.t  view on Meta::CPAN

    # Empty hmac key
    $jwt = WWW::Suffit::JWT->new(secret => "");
    $decoded_payload = $jwt->decode($token)->payload;
    like $jwt->error, qr/Symmetric\skey\s\(secret\)\snot\sspecified$/,
        "Decodes JWTs (HMAC) with empty hmac secret" or diag $jwt->error;
}

# Generate RSA keys
my $rsa = WWW::Suffit::RSA->new(key_size => 512);
$rsa->keygen;
my $private_key = $rsa->private_key;
my $public_key = $rsa->public_key;
ok(length $private_key // '', 'Private RSA key');
ok(length $public_key // '', 'Public RSA key');

# RSA
{
    my $payload = {
            foo => 'bar',
            baz => 'qux',
        };
    my $jwt = WWW::Suffit::JWT->new(
            private_key => $private_key,
            public_key  => $public_key,
            payload     => $payload,
            algorithm   => 'RS256',
        );

    # Encode token
    my $token = $jwt->encode->token;
    ok $token, 'Encodes JWTs (RSA)' or diag $jwt->error;
    #note $token;
    #note explain $jwt;



( run in 0.270 second using v1.01-cache-2.11-cpan-a5abf4f5562 )