#!/usr/bin/perl use strict; use warnings; use Math::BigInt lib => 'GMP'; my $g = new Math::BigInt('5'); # typically 2 or 5 my $p = new Math::BigInt( "537139360602477525125655043677356597740" . "672426915294213641576278281056255413159" . "9074907426010737503501" # any 100+ digit prime will do ); my $a = new Math::BigInt(join("", map(chr(48+int rand 10), 1 .. 50))); # $a is the lhs secret my $b = new Math::BigInt(join("", map(chr(48+int rand 10), 1 .. 50))); # $b is the rhs secret my ($A, $B, $Kab, $Kba); print "g=$g\n"; # $p and $g generate a group print "p=$p\n"; # cyclic group G print "a=$a\n"; # $p and $g are chosen in the clear print "b=$b\n"; print "\n"; # it's safe to send A=g^a mod p in the clear $A = $g->copy->bmodpow( $a, $p ); # it's safe to send B=g^b mod p in the clear $B = $g->copy->bmodpow( $b, $p ); # g^b^a mod p should be equal to g^a^b mod p $Kba = $B->copy->bmodpow( $a, $p ); $Kab = $A->copy->bmodpow( $b, $p ); # so we both know the secret without transmitting it! # magic! print "These better be equal:\n\t$Kab\n\t$Kba\n\n"; #### use Crypt::PBC; my $pairing = new Crypt::PBC("params_d.txt"); my $P = $pairing->init_G2->random; # generator in G2 my $s = $pairing->init_Zr->random; # master secret my $P_pub = $pairing->init_G2->pow_zn($P, $s); # master public key #### use Digest::SHA1 qw(sha1); my $ID_i = q(node_id=16186); my $Q_i = $pairing->init_G1->set_to_hash( sha1($ID_i) ); print "ID_i=$ID_i\nQ_i=", $Q_i->as_hex, "\n"; #### my $d_i = $pairing->init_G1->pow_zn( $Q_i, $s ); # the private key corresponding to $Q_i #### use Crypt::CBC; use Crypt::Blowfish; my $g_i = $pairing->init_GT->e_hat( $Q_i, $P_pub ); my $r = $pairing->init_Zr->random; my $rP = $pairing->init_G2->pow_zn( $P, $r ); my $W1 = $g_i->clone->pow_zn( $r ); my $C1 = new Crypt::CBC({header=>'randomiv', key=>$W1->as_bytes, cipher=>"Blowfish"}); my @m = ($rP, $C1->encrypt("LOL! Funny URL: blither blather message")); # Note that the message is a two tuple, not just the ciphertext. # We transmit @m in the clear. No worries. my $W2 = $pairing->init_GT->e_hat( $d_i, $m[0] ); my $C2 = new Crypt::CBC({header=>"randomiv", key=>$W2->as_bytes, cipher=>"Blowfish"}); my $txt = $C2->decrypt( $m[1] ); print "W1 =? W2\nW1=", substr($W1->as_base64, 0, 80), "\nW2=", substr($W2->as_base64, 0, 80), "\n"; print "And here's the original message: $txt\n\n"; #### $pairing = new Crypt::PBC("params_a.txt"); $P = $pairing->init_G2->random; # generator in G2 $s = $pairing->init_Zr->random; # master secret $P_pub = $pairing->init_G2->pow_zn($P, $s); # master public key my $Q_0 = $pairing->init_G1->set_to_hash( sha1("node_id=22609") ); # tye my $Q_1 = $pairing->init_G1->set_to_hash( sha1("node_id=9073") ); # merlyn my $d_0 = $pairing->init_G1->pow_zn( $Q_0, $s ); my $d_1 = $pairing->init_G1->pow_zn( $Q_1, $s ); my $K_01_a = $pairing->init_GT->e_hat( $Q_0, $d_1 ); # merlyn's version of K_01 my $K_01_b = $pairing->init_GT->e_hat( $d_0, $Q_1 ); # tye's version print "K_01 (these better be the same):\n\t", substr($K_01_a->as_base64, 0, 80), "\n\t", substr($K_01_b->as_base64, 0, 80), "\n"; my $K_10_a = $pairing->init_GT->e_hat( $Q_1, $d_0 ); # tye's version of K_10 my $K_10_b = $pairing->init_GT->e_hat( $d_1, $Q_0 ); # merlyn's version print "K_10 (these also better be the same):\n\t", substr($K_10_a->as_base64, 0, 80), "\n\t", substr($K_10_b->as_base64, 0, 80), "\n\n"; #### # We can construct authenticated ciphers: my $authcipha = new Crypt::CBC({header=>"randomiv", key=>$K_01_a->as_bytes, cipher=>"Blowfish"}); my $authciphb = new Crypt::CBC({header=>"randomiv", key=>$K_01_b->as_bytes, cipher=>"Blowfish"}); # or we can use the secrets to construct authentic clear-text messages: my @verifiable_message; SCOPE1: { my $msg = "This is verifiable."; my $sha = new Digest::SHA1; $sha->add( $msg ); $sha->add( $K_01_a->as_bytes ); my $MAC = $sha->digest; @verifiable_message = ( $msg, $MAC ); } SCOPE2: { my $sha = new Digest::SHA1; $sha->add( $verifiable_message[0] ); $sha->add( $K_01_b->as_bytes ); my $MAC = $sha->digest; print "Verified message from ID_0: $verifiable_message[0]\n\n" if $MAC eq $verifiable_message[1]; } #### my $ID_c = 'node_id=1382'; # chromatic is looking to join our IBE my $Q_c = $pairing->init_G1->set_to_hash( sha1($ID_c) ); my $x_c = $pairing->init_Zr->random; my $X_c = $pairing->init_G2->pow_zn( $P, $x_c ); my $req = $X_c->as_bytes; # we transmit $X_c in the open along with our request for $d_c # the TA then builds our private key and constructs a secret $W_0. # IRL, the TA would calculate $Q_c on its own ... my $dtmp = $pairing->init_G1->pow_zn( $Q_c, $s ); my $W_0 = $pairing->init_GT->e_hat( $pairing->init_G2->set_to_bytes($req)->pow_zn( $s ), # only the TA can make this $P_pub ); my $cipher0 = new Crypt::CBC({header=>"randomiv", cipher=>"Blowfish", key=>$W_0->as_bytes}); my $reqfil = $cipher0->encrypt( $dtmp->as_bytes ); # Back at the $ID_c node, we can recover our private key # from $reqfil like so: my $W_1 = $pairing->init_GT->e_hat( $P_pub, $P_pub )->pow_zn($x_c); my $cipher1 = new Crypt::CBC({header=>"randomiv", cipher=>"Blowfish", key=>$W_1->as_bytes}); my $d_c = $pairing->init_G1->set_to_bytes( $cipher1->decrypt( $reqfil ) ); print "I have aquired my key from the TA over a secure authentic channel:\n\t", substr($dtmp->as_base64, 0, 80), "\n\t", substr($d_c->as_base64, 0, 80), "\n\n"; #### # $P is chosen the same way as the examples above, so we'll just use that. my $N = 10; # the number of PAs, plus the TA my @s = map( $pairing->init_Zr->random, 1 .. $N ); my @P = map( $P->clone->pow_zn( $_ ), @s ); my $Y = $P->clone; $Y->pow_zn( $_ ) for @s; # The TA calculates P0 := $s[0]$P and transmits to the first PA who # calculates P1 := $s[1]$P[0] and so on. Notice the in-efficiency? # Hint: $P[0] == ($P->clone->pow_zn($s[0])). In fact, @P isn't needed # at all, unless you're combining shared-secrets with secure key # distribution. # $Q_0 (tye) and $Q_1 (merlyn) are defined above ... $d_0 = $Q_0->clone; $d_0->pow_zn( $_ ) for @s; $d_1 = $Q_1->clone; $d_1->pow_zn( $_ ) for @s; $K_01_a = $pairing->init_GT->e_hat( $Q_0, $d_1 ); $K_01_b = $pairing->init_GT->e_hat( $d_0, $Q_1 ); print "[Y] authenticated secret is the same:\n\t", substr($K_01_a->as_base64, 0, 80), "\n\t", substr($K_01_b->as_base64, 0, 80), "\n\n"; $r = $pairing->init_Zr->random; $rP = $P->clone->pow_zn( $r ); $W1 = $pairing->init_GT->e_hat( $Q_0, $Y )->pow_zn( $r ); $W2 = $pairing->init_GT->e_hat( $d_0, $rP ); print "[Y] un-authenticated secret is the same:\n\t", substr($W1->as_base64, 0, 80), "\n\t", substr($W2->as_base64, 0, 80), "\n\n";