#!/util/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 ); my \$C2 = new Crypt::CBC({header=>"randomiv", key=>\$W2->as_bytes, cipher=>"Blowfish"}); my \$txt = \$C2->decrypt( \$m ); 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 ); \$sha->add( \$K_01_b->as_bytes ); my \$MAC = \$sha->digest; print "Verified message from ID_0: \$verifiable_message\n\n" if \$MAC eq \$verifiable_message; } ##``````## 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\$P and transmits to the first PA who # calculates P1 := \$s\$P and so on. Notice the in-efficiency? # Hint: \$P == (\$P->clone->pow_zn(\$s)). 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"; ```