Brethren,

I have a threaded Perl ICB client which features client-side end-to-end encryption. It's been working fine for years using Crypt::DH and Crypt::Blowfish (plus supporting modules of course). Crypt::DH is used to create a shared one-time key for Blowfish. I just tried to update my application to use Crypt::DH::GMP, in order to improve performance and reduce the number of module dependencies, and I'm running into an error that I don't fully understand.

Here are the relevant bits of code:

use Module::Load::Conditional qw[can_load check_install requires]; $Module::Load::Conditional::VERBOSE = 1; my $crypt_mods = {'Crypt::DH::GMP' => undef, 'Crypt::CBC' => undef, 'Crypt::Blowfish' => undef, 'Digest::SHA' => undef, 'MIME::Base64' => undef, 'Compress::Zlib' => undef}; if (can_load(modules => $crypt_mods, verbose => 1)) { $encryption_avail = 1; } my ($DH_public, $DH_public2, $DH_private, $DH_secret); [...] sub create_public_key { my $to = lc($_[0]); my $from = lc($_[1]); my $player = $_[2]; my ($DH, $p, $g, $i, $public, @chars); @chars = split(//,($player ? $to : $from)); $g = ord(shift(@chars)); while (scalar @chars) { $g += ord(shift(@chars)); } @chars = split(//, ($player ? $from : $to)); $i = ord(shift(@chars)); while (scalar @chars) { $i += ord(shift(@chars)); } $i %= scalar(@EICB_PRIMES); $p = $EICB_PRIMES[$i]; $DH = Crypt::DH::GMP->new; $DH->g($g); $DH->p($p); $DH->generate_keys; $DH_public = $DH->pub_key; $DH_private = $DH->priv_key; } sub create_secret_key { my $to = lc($_[0]); my $from = lc($_[1]); my $player = $_[2]; my ($DH, $p, $g, $i, $public, @chars); @chars = split(//,($player ? $to : $from)); $g = ord(shift(@chars)); while (scalar @chars) { $g += ord(shift(@chars)); } @chars = split(//,($player ? $from : $to)); $i = ord(shift(@chars)); while (scalar @chars) { $i += ord(shift(@chars)); } $i %= scalar(@EICB_PRIMES); $p = $EICB_PRIMES[$i]; $DH = Crypt::DH::GMP->new; $DH->g($g); $DH->p($p); $DH->priv_key($DH_private); $DH->generate_keys; $DH_secret = $DH->compute_secret($DH_public2); } [...] sub do_crypt_command { my ($who, $args, $time) = @_; my @args = split(/\s+/, $args); my $command = shift (@args); if ($command == $EICB_DH_INIT) { create_public_key($who, $cur_nick, 0); $connection->sendpriv($who, sprintf('%s%s %s', $EICB_CRYPT_PREFIX, $EICB_DH_REPLY, $DH_public)); } elsif ($command == $EICB_DH_REPLY) { $DH_public2 = shift(@args); create_public_key($who, $cur_nick, 1); $connection->sendpriv($who, sprintf('%s%s %s', $EICB_CRYPT_PREFIX, $EICB_DH_REPLY2, $DH_public)); create_secret_key($who, $cur_nick, 1); } elsif ($command == $EICB_DH_REPLY2) { $DH_public2 = shift(@args); create_secret_key($who, $cur_nick, 0); my $sha1 = Digest::SHA->new; $sha1->add($logbuffer[rand(scalar @logbuffer)]); my $key = $sha1->b64digest; $session_keys{lc($who)} = $key; encrypt(\$key, $cipher, $DH_secret); $connection->sendpriv($who, sprintf('%s%s %s', $EICB_CRYPT_PREFIX, $EICB_SESSION_KEY, $key)); timestamp($time) if ($timestamps_active); icb_print ($output_window, 'sbrkt', "%s", "[="); icb_print ($output_window, 'status', "%s", "SECURE"); icb_print ($output_window, 'sbrkt', "%s", "=]"); icb_print ($output_window, 'status', " Session key for user %s established\n", $who); $tabhist{lc($who)} = time(); } [...]

Logic flow is as follows: When client A requests an encrypted session with client B, A sends B a cleartext message containing an EICB_DH_INIT request. If B has encryption enabled, B calls create_public_key( ) and sends its public key back to A in a EICB_DH_REPLY message. A receives the EICB_DH_REPLY message, calls create_public_key( ) to create its own public key, and sends that back to B in a EICB_DH_REPLY2 message. A and B then both call create_secret_key( ), and B generates a one-time Blowfish session key and sends it back to A encrypted using the shared DH secret.

Using Crypt::DH, all of this works. Using Crypt::DH::GMP, create_public_key( ) works, but create_secret_key( ) fails at the $DH->priv_key($DH_private) statement:

Thread 3 terminated abnormally: Usage: Crypt::DH::GMP::priv_key(dh) at + ./icbm line 2434.

I'm not quite sure what I need to change here. The limited documentation in Crypt::DH::GMP does not make any mention of any change in usage of the priv_key( ) method.

Can anyone point out what I'm doing wrong?


In reply to Usage problem with Crypt::DH::GMP::priv_key( ) by Llew_Llaw_Gyffes

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.