NAME

Crypt::SRP - Secure Remote Protocol (SRP6a)

SYNOPSIS

Example 1 - creating a new user and his/her password verifier:

###CLIENT###
my $I = '...'; # login entered by user
my $P = '...'; # password entered by user
my $cli = Crypt::SRP->new('RFC5054-1024bit', 'SHA1');
my ($s, $v) = $cli->compute_verifier_and_salt($I, $P);

#  request to server:  ---> /auth/create_user [$I, $s, $v] --->

                          ###SERVER###
                          my %USERS;  # sort of "user database"
                          die "user already exists" unless $USERS{$I};
                          $USERS{$I}->{salt} = $s;
                          $USERS{$I}->{verifier} = $v;

Example 2 - SRP login handshake:

###CLIENT###
my $I = '...'; # login entered by user
my $P = '...'; # password entered by user
my $cli = Crypt::SRP->new('RFC5054-1024bit', 'SHA1');
my ($A, $a) = $cli->client_compute_A;

#  request[1] to server:  ---> /auth/srp_step1 ($I, $A) --->

                          ###SERVER###
                          my %USERS;  # sort of "user database"
                          my %TOKENS; # sort of temporary "token database"
                          my $v = $USERS{$I}->{verifier};
                          my $s = $USERS{$I}->{salt};
                          my $srv = Crypt::SRP->new('RFC5054-1024bit', 'SHA1');
                          return unless $srv->validate_A_or_B($A);
                          $srv->server_init($I, $v, $s);
                          my ($B, $b) = $srv->server_compute_B;
                          my $token = $srv->random_bytes(32);
                          $TOKENS{$token} = [$I, $A, $B, $b];

#  response[1] from server:  <--- ($B, $s, $token) <---

###CLIENT###
return unless $cli->validate_A_or_B($B);
$cli->client_init($I, $P, $s, $B);
my $M1 = $cli->client_compute_M1;

#  request[2] to server:  ---> /auth/srp_step2 ($M1, $token) --->

                          ###SERVER###
                          my $M2 = '';
                          return unless $M1 && $token && $TOKENS{$token};
                          my ($I, $A, $B, $b) = @{delete $TOKENS{$token}};
                          return unless $I && $A && $B && $b && $USERS{$I};
                          my $s = $USERS{$I}->{salt};
                          my $v = $USERS{$I}->{verifier};
                          return unless $s && $v;
                          my $srv = Crypt::SRP->new('RFC5054-1024bit', 'SHA1');
                          $srv->server_init($I, $v, $s, $A, $B, $b);
                          return unless $srv->server_verify_M1($M1);
                          $M2 = $srv->server_compute_M2;
                          my $K = $srv->get_secret_K; # shared secret

#  response[2] from server:  <--- ($M2) <---

###CLIENT###
if ($M2 && $cli->client_verify_M2($M2)) {
  my $K = $srv->get_secret_K; # shared secret
  print "SUCCESS";
}
else {
  print "ERROR";
}

DESCRIPTION

More info about SRP protocol:

This module implements SRP version 6a.

IMPORTANT: This module performs some big integer arithmetics via Math::BigInt. From performance reasons it is recommended to install Math::BigInt::GMP.

IMPORTANT: This module needs some cryptographically strong random number generator. It tries to use one of the following:

METHODS

Login and password ($I, $P) can be ASCII strings (without utf8 flag) or raw octects. If you want special characters in login and/or password then you have to encode them from Perl's internal from like this: $I = encode('utf8', $I) or $P = encode('utf8', $P)

All SRP related variables ($s, $v, $A, $a, $B, $b, $M1, $M2, $S, $K) are raw octects (no BigInts no strings with utf8 flag).

  • new

    my $srp = Crypt::SRP->new($group, $hash);
    # $group ... 'RFC5054-1024bit' or 'RFC5054-1536bit' or 'RFC5054-2048bit' or
    #            'RFC5054-3072bit' or 'RFC5054-4096bit' or 'RFC5054-6144bit' or
    #            'RFC5054-8192bit'
    # $hash  ... 'SHA1' or 'SHA256' or 'SHA384' or 'SHA512'
  • client_init

    $srp->client_init($I, $P, $s, $B);
    #or
    $srp->client_init($I, $P, $s, $B, $A, $a);
  • client_compute_A

    my ($A, $a) = $srp->client_compute_A();
    #or
    my ($A, $a) = $srp->client_compute_A($a_len);
  • client_compute_M1

    my $M1 = $srp->client_compute_M1($B)
  • client_verify_M2

    my $valid = $srp->client_verify_M2($M2);
  • compute_verifier

    my $v = $srp->compute_verifier($I, $P, $s)
  • compute_verifier_and_salt

    my ($s, $v) = $srp->compute_verifier_and_salt($I, $P);
    #or
    my ($s, $v) = $srp->compute_verifier_and_salt($I, $P, $s_len)
  • server_init

    $srp->server_init($I, $v, $s);
    #or
    $srp->server_init($I, $v, $s, $A, $B, $b);
  • server_compute_B

    my ($B, $b) = $srp->server_compute_B();
    #or
    my ($B, $b) = $srp->server_compute_B($b_len);
  • server_verify_M1

    my $valid = $srp->server_verify_M1($M1);
  • server_compute_M2

    my $M2 = $srp->server_compute_M2();
  • get_secret_S

    my $S = $srp->get_secret_S();
  • get_secret_K

    my $K = $srp->get_secret_K();
  • validate_A_or_B

    my $valid = validate_A_or_B($A);
    #or
    my $valid = validate_A_or_B($B);
  • random_bytes

    my $rand = $srp->random_bytes();
    #or
    my $rand = $srp->random_bytes($len);

COPYRIGHT

Copyright (c) 2013 DCIT, a.s. http://www.dcit.cz / Karel Miko