How Does Bob Encrypt Data For Alice, Using Just Her Email Address?

Go and encrypt …

Photo by Bradford Nicolas on Unsplash

How Does Bob Encrypt Data For Alice, Using Just Her Email Address?

Go and encrypt …

So can you send me an encrypted message by just knowing my ID? Well, IBE (Identity Based Encryption) does this, and the MIRACL library is just perfect in implementing it. Basically atrust authority creates a secret from Alice’s ID, and then passes Alice’s private key using her ID and the secret value:

First we have two curves (G1 and G2) and initially we define a large prime number (q). We then use a special pairing function e() for two points (U and V):

and where U is a point on the G2 curve and V is a point on the G1 curve.

A trust server selects a point on the G2 curve (P), and generates a using a random number (s): sk=s. Next the trust server creates a public key with (and where P is a base point on the G1 curve):

This will be a point on the G1 curve. Bob then takes Alice’s ID and hashes it:

He then creates this as a point on the G2 curve:

This is Alice’s public key. The trust server sends Alice her private key:

Bob takes the plaintext message (M) and creates a random number (r). Next Bob creates the ciphertext of:

Alice then justs uses her private key (dA) and the ciphertext elements (C1, C2) to recover the message with:

dA is Alice’s private key (sQA), QA is her public key, ⊕ operator is EX-OR, and e() is the pairing function. This works because:

Coding

The outline coding using the library from the MIRACL library [here] is

package main
import (
"fmt"
"github.com/miracl/core/go/core"
"github.com/miracl/core/go/core/BN254"
"math/rand"
"time"
"os"
)
func FP12toByte(F *BN254.FP12) []byte {
const MFS int = int(BN254.MODBYTES)
var t [12 * MFS]byte
F.ToBytes(t[:])
return(t[:])
}
func ECPtoByte(F *BN254.ECP2) []byte {
const MFS int = int(BN254.MODBYTES)
var t [12 * MFS]byte
F.ToBytes(t[:],true)
return(t[:])
}
func randval() *core.RAND {
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
rng := core.NewRAND()
var raw [100]byte
for i := 0; i < 100; i++ {
raw[i] = byte(r1.Intn(255))
}
rng.Seed(100, raw[:])
return rng
}
func xor(a []byte, b []byte) []byte{
for i := 0;  i < len(a); i++ {
a[i]=(a[i]^b[i]) & 0xff
}
return a
}
func main() {
AliceID:="myaddress"
msg:="Hello"
argCount := len(os.Args[1:])
if (argCount>1) {msg= os.Args[1]}
if (argCount>2) {AliceID= os.Args[2]}
q := BN254.NewBIGints(BN254.CURVE_Order)
s:=BN254.Randomnum(q,randval())
r:=BN254.Randomnum(q,randval())
sh:=core.NewHASH256()
for i:=0;i < len(AliceID);i++ {
sh.Process(AliceID[i])
}
Q_A:=sh.Hash()
QA := BN254.ECP2_mapit(Q_A)
// Alice's secret key: dA
dA:=BN254.G2mul(QA,s)
P := BN254.ECP_generator()
sP:=BN254.G1mul(P,s)
M := []byte(msg)
pair:=BN254.Ate(QA,sP);  pair=BN254.Fexp(pair)
pair=pair.Pow(r)
C1:=BN254.G1mul(P,r)
C2:=xor(M,FP12toByte(pair))
pair2:=BN254.Ate(dA,C1);  pair2=BN254.Fexp(pair2)
fmt.Printf("Message:\t%s\n\n",msg)
fmt.Printf("Alice ID:\t%s\n\n",AliceID)
fmt.Printf("Alice QA:\t%s\n\n",QA.ToString())
fmt.Printf("Alice private:\t%s\n\n",dA.ToString())
fmt.Printf("s:\t%s\n",s.ToString())
fmt.Printf("r:\t%s\n\n",r.ToString())
fmt.Printf("C1:\t%s\n",C1.ToString())
fmt.Printf("C2:\t%x\n\n",C2)
Cres:=xor(C2,FP12toByte(pair2))
fmt.Printf("Decrypt: %s\n\n",Cres)
fmt.Printf("\nPairing 1 e(QA,sP)^r:\t%x\n",FP12toByte(pair)[:20])
fmt.Printf("Pairing 2 e(dA,C1):\t%x\n\n",FP12toByte(pair2)[:20])
}

A sample run is [here]:

Message: Hello
Alice ID: myaddress
Alice QA: ([22f89695210305ac8cc6f6e3b3f25564127746368f561b0a3d78838655678a04,098626898fd16868774246bd593faf156d659774febc5ff33cc3867ac07909fc],[1dd702f4a45bf6a247f6a5bb71c96d528beeb6860cc9e66baabfe25815ad2e10,130d4187e10b25ac3b6d6bc00bd433bcb02f676777e716f88cf5c3b998f1cb8d])
Alice private: ([030f8ef338489ca72571bebba78fe68f02694da5f7681eddf051f90cf3b49e68,0b62b9e4f27eff39eda74bfc6cfc806e28dd8c4708771f4b474e242314d3c774],[0b195563e2f33f8fbf614054ba7075d5a017d252b5d90b48c61b57b2283343b8,0bba11988e80bfb90b6bb7b097ec1584ebab49fa9303d1f68215d8fc3f46b8de])
s: 12a1dd2f951ac291b81acdc6cb9d506a3add0a8c1eb826e53f018d6b9a6673a0
r: 003a0f064288945a929324d5706c5ead13959e4995cb3df0c7ca8326942a80d4
C1: (098c71ac9f313cb903726cacb1879ff001d078deccc5fd7b0298c1d7e499a68a,0e8f3524936a078417f7dae4d6e562c3ff9bd2f89dedf8f80e0dcab168369f5f)
C2: 468f2ef773
Decrypt: Hello
Pairing 1 e(QA,sP)^r: 0eea429b1c0d4d505706dbd47641af6a2109dcae
Pairing 2 e(dA,C1): 0eea429b1c0d4d505706dbd47641af6a2109dcae

Conclusions

For IoT infrastructures, PKI is just not scalable, and so IBE may fit better.