Crypt-OPAQUE

 view release on metacpan or  search on metacpan

README.pod  view on Meta::CPAN

=head1 NAME

L<Crypt::OPAQUE> 

=head2 PROTOCOL

L<https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque/>

=head1 FUNCTION

=head2 create_cleartext_credentials
 
 my $cleartext_credentials = create_cleartext_credentials($s_pub, $c_pub, $s_id, $c_id);

=head2 store

 my $store_r = store($randomized_pwd, $s_pub, $s_id, $c_id, $Nn, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func, $mac_func);

=head2 recover

 my $recover_r = recover($randomized_pwd, $s_pub, $envelope, $s_id, $c_id, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func, $mac_func);

=head2 create_registration_request

README.pod  view on Meta::CPAN

  my $randomize_pwd = derive_random_pwd($ec_params, $pwd, $blind, $evaluate_element, $hash_name, $harden_func);

=head2 create_credential_request
  
  my $cred_req_r = create_credential_request($request, $s_pub, $oprf_seed, $credential_identifier, $DSI, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func, $point_compress_t);

=head2 create_credential_response

   my $cred_res_r = create_credential_response($request, $s_pub, $oprf_seed, $credential_identifier, $DSI, $envelope, $masking_key, $Nn, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func, $point_compress_t, $pack_func);

=head2 recover_credentials

    my $recover_r = recover_credentials($cred_request, $cred_response, $pwd, $c_id, $s_id, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func, $mac_func, $pwd_harden_func, $unpack_func);

=cut

lib/Crypt/OPAQUE.pm  view on Meta::CPAN

use Crypt::OpenSSL::Bignum;
use Crypt::OpenSSL::ECDSA;
use Crypt::OPRF;

#use Smart::Comments;

our $VERSION = 0.012;

our @ISA    = qw(Exporter);
our @EXPORT = qw/
  create_cleartext_credentials
  store
  recover
  create_registration_request
  create_registration_response
  finalize_registration_request
  derive_random_pwd
  create_credential_request
  create_credential_response
  recover_credentials
  /;

our @EXPORT_OK = @EXPORT;

sub recover_credentials {

  my (
    $cred_request, $cred_response,   $pwd, $c_id, $s_id, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func,
    $mac_func,     $pwd_harden_func, $unpack_func
  ) = @_;

  my $evaluate_element = hex2point( $cred_request->{ec_params}{name}, unpack( "H*", $cred_response->{Z} ) );
  my $randomized_pwd =
    derive_random_pwd( $cred_request->{ec_params}, $pwd, $cred_request->{blind}, $evaluate_element, $hash_name, $pwd_harden_func );
  ### randomized_pwd: unpack("H*", $randomized_pwd)

lib/Crypt/OPAQUE.pm  view on Meta::CPAN

  my $recover_r = recover(
    $randomized_pwd, $s_pub, $envelope, $s_id, $c_id, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func,
    $mac_func
  );
  $recover_r->{s_pub} = $s_pub;
  ### recover s_pub: unpack("H*", $s_pub)
  ### recover c_priv:  $recover_r->{c_priv}->to_hex
  ### recover export_key: unpack("H*", $recover_r->{export_key})

  return $recover_r;
} ## end sub recover_credentials

sub create_credential_response {
  my (
    $request,   $s_pub, $oprf_seed, $credential_identifier, $DSI, $envelope, $masking_key, $Nn, $Nseed, $group_name, $info, $DST,
    $hash_name, $expand_message_func, $point_compress_t, $pack_func
  ) = @_;
  ### blindElement: unpack("H*", $request->{data})
  ### s_pub: unpack("H*", $s_pub)
  ### oprf_seed: unpack("H*", $oprf_seed)
  ### $credential_identifier

lib/Crypt/OPAQUE.pm  view on Meta::CPAN

  ( $blind, $blindedElement ) =
    blind( $pwd, $blind, $DSI, $group_name, $type, $hash_name, $expand_message_func, $clear_cofactor_flag );

  my $ec_params          = get_ec_params( $group_name );
  #my $blindedElement_hex = sn_point2hex( $group_name, $blindedElement, 2 );
  my $blindedElement_hex = Crypt::OpenSSL::EC::EC_POINT::point2hex($ec_params->{group}, $blindedElement, 2, $ec_params->{ctx}); 
  my $request            = { data => pack( "H*", $blindedElement_hex ) };
  return { request => $request, blind => $blind, ec_params => $ec_params };
}

sub create_cleartext_credentials {
  my ( $s_pub, $c_pub, $s_id, $c_id ) = @_;

  $s_id //= $s_pub;
  $c_id //= $c_pub;

  my $cleartext_credentials = join(
    "", $s_pub,
    map { i2osp( length( $_ ), 2 ) . $_ } ( $s_id, $c_id ) );

  return $cleartext_credentials;
}

sub store {
  my ( $randomized_pwd, $s_pub, $s_id, $c_id, $Nn, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func, $mac_func ) =
    @_;

  my $envelope_nonce_bn = ( ref( $Nn ) eq 'Crypt::OpenSSL::Bignum' ) ? $Nn : random_bn( $Nn );
  my $envelope_nonce    = $envelope_nonce_bn->to_bin;

  my $hash_func   = EVP_get_digestbyname( $hash_name );

lib/Crypt/OPAQUE.pm  view on Meta::CPAN

  ### auth_key: unpack("H*", $auth_key)

  my $seed = Crypt::KeyDerivation::hkdf_expand( $randomized_pwd, $hash_name, $Nseed, $envelope_nonce . "PrivateKey" );
  ### seed: unpack("H*", $seed)

  my $c_ec_key_r = derive_key_pair( $group_name, $seed, $info, $DST, $hash_name, $expand_message_func );
  my $c_priv     = $c_ec_key_r->{priv_bn};
  my $c_pub      = $c_ec_key_r->{pub_bin};
  ### c_priv: $c_priv->to_hex

  my $cleartext_credentials = create_cleartext_credentials( $s_pub, $c_pub, $s_id, $c_id );
  ### cleartext_credentails: unpack("H*", $cleartext_credentials)

  my $auth_tag = $mac_func->( $envelope_nonce . $cleartext_credentials, $auth_key );

  my $envelope = { auth_tag => $auth_tag, nonce => $envelope_nonce };

  return {
    envelope              => $envelope, c_pub => $c_pub, masking_key => $masking_key,
    export_key            => $export_key,
    c_priv                => $c_priv, auth_key => $auth_key,
    cleartext_credentails => $cleartext_credentials,
  };
} ## end sub store

sub recover {
  my (
    $randomized_pwd, $s_pub, $envelope, $s_id, $c_id, $Nseed, $group_name, $info, $DST, $hash_name, $expand_message_func,
    $mac_func
  ) = @_;

  my $hash_func = EVP_get_digestbyname( $hash_name );

lib/Crypt/OPAQUE.pm  view on Meta::CPAN

  ### export_key: unpack("H*", $export_key)

  my $seed = Crypt::KeyDerivation::hkdf_expand( $randomized_pwd, $hash_name, $Nseed, $envelope->{nonce} . "PrivateKey" );
  ### seed: unpack("H*", $seed)

  my $c_ec_key_r = derive_key_pair( $group_name, $seed, $info, $DST, $hash_name, $expand_message_func );
  my $c_priv     = $c_ec_key_r->{priv_bn};
  my $c_pub      = $c_ec_key_r->{pub_bin};
  ### c_priv: $c_priv->to_hex

  my $cleartext_credentials = create_cleartext_credentials( $s_pub, $c_pub, $s_id, $c_id );
  my $expected_tag          = $mac_func->( $envelope->{nonce} . $cleartext_credentials, $auth_key );

  if ( $envelope->{auth_tag} ne $expected_tag ) {
    croak "not match envelope.auth_tag";
  }

  return {
    export_key => $export_key,
    c_priv     => $c_priv,
    c_ec_key_r => $c_ec_key_r,
  };

t/04.register.t  view on Meta::CPAN

    my ($r) = @_;
    my $s_pub = substr $r, 0, 33;
    my $nonce = substr $r, 33, 32;
    my $auth_tag = substr $r, 65, 32;
    ### r: unpack("H*", $r)
    ### s_pub: unpack("H*", $s_pub)
    ### nonce: unpack("H*", $nonce)
    ### auth_tag: unpack("H*", $auth_tag)
    return [ $s_pub, $nonce, $auth_tag ];
};
my $recover_r = recover_credentials($cred_req_r, $cred_res_r, $pwd, $c_id, $s_id, $Nseed, $group_name, $finalize_info, $finalize_DST, $hash_name, $expand_message_func, $mac_func, $pwd_harden_func, $unpack_func);
is($recover_r->{c_priv}->to_hex, 'D1D280F712E4EBF3C881C686E13C281BC3A3FAB30A00411A350F4F8B7A1EA550', 'recover_credentials');
is($recover_r->{export_key}, pack("H*", '77869b0d11debf6fc88c1d192dde9546baf528b2f70c2aea89960fc2178586da'), 'recover_credentials');

done_testing;

1;

t/05.sigma_i.t  view on Meta::CPAN

    my ($r) = @_;
    my $s_pub = substr $r, 0, 33;
    my $nonce = substr $r, 33, 32;
    my $auth_tag = substr $r, 65, 32;
    ### r: unpack("H*", $r)
    ### s_pub: unpack("H*", $s_pub)
    ### nonce: unpack("H*", $nonce)
    ### auth_tag: unpack("H*", $auth_tag)
    return [ $s_pub, $nonce, $auth_tag ];
};
my $recover_r = recover_credentials($cred_req_r, $a_recv_cred_res_r, $pwd, $id_a, $a_recv_msg2_r->{id_b}, $Nseed, $group_name, $finalize_info, $finalize_DST, $hash_name, $expand_message_func, $mac_func, $pwd_harden_func, $unpack_func);
is($recover_r->{export_key}, pack("H*", '77869b0d11debf6fc88c1d192dde9546baf528b2f70c2aea89960fc2178586da'), 'recover_credentials');

is($recover_r->{c_priv}->to_hex, 'D1D280F712E4EBF3C881C686E13C281BC3A3FAB30A00411A350F4F8B7A1EA550', 'recover_credentials');

my $a_recover_a_s_priv_pkey = gen_ec_key($group_name, $recover_r->{c_priv}->to_hex);
write_key_to_pem("$Bin/a_recover_c_s_priv.pem", $a_recover_a_s_priv_pkey );

my $a_recover_b_s_pub_pkey = gen_ec_pubkey($group_name, unpack("H*", $recover_r->{s_pub}));
write_pubkey_to_pem("$Bin/a_recover_b_s_pub.pem", $a_recover_b_s_pub_pkey );
my $a_verify_msg2 = a_verify_msg2(
    $msg1_r, $a_recv_msg2_r, "$Bin/a_recover_b_s_pub.pem",
  \&encode_cbor, 
  $mac_func,



( run in 0.281 second using v1.01-cache-2.11-cpan-4d50c553e7e )