Simply IBE (Identity Based Encryption)

So how do you properly identify a device? Well, typically, we put a private key on the device and then expose the public key through PKI…

Simply IBE (Identity Based Encryption)

So how do you properly identify a device? Well, typically, we put a private key on the device and then expose the public key through PKI (Public Key Infrastructure) to everyone else. But what if that private key is discovered? Well, another device can then spoof the device, as they can now sign messages with the stolen private key. And, can we control the secure connections between two devices and so that only trusted devices can communicate with each other?

Overall, PKI is perhaps not that good in some instances when it comes to things that are not related to the Web and email. For many applications for large-scale IoT, we might need to create a trust infrastructure and have a trust server which can manage connections between devices. One solution for this is Identity Based Encryption (IBE) [1], and which allows the public key of a device to be based on its identity.

Simply IBE

So, can we simply illustrate IBE (Identity Based Encryption) in a few basic steps? Let’s try:

  1. Alice gets Bob’s ID (Qid). Normally this would be something like the hash of Bob’s email address.
  2. The trust server then selects a secret (s) and creates a public key of sU, and where U is a point on the curve. Alice will receive sU in order to send to Bob.
  3. Alice then selects a random value (r) and creates a pairing of e(sU,Qid)^r. She use this to encrypt the symmetric key she will use for the encrypted message.
  4. Bob uses a private key of sQid and generates the same key with e(rU,sQid). He uses this to decrypt the encrypted key.

Neither Bob nor Alice knows the secret (s) and where only Bob will know the private key for his ID. This will be provided by the trust server.

This works because pair-based cryptography supports these pairings:

e(sU,Qid)^r=e(U,sQid)^r=e(rU,sQid)=e(rU,sQid)

An outline of the code using the MIRACL library [here] is [here][2]:

package main
import (
"fmt"
"github.com/miracl/core/go/core/BN254"
"os"
"strconv"
"math/rand"
"time"
"crypto/sha256"
)
func FP12toByte(F *BN254.FP12) []byte {
const MFS int = int(BN254.MODBYTES)
var t [12 * MFS]byte
F.ToBytes(t[:])
return(t[:])
}

func main() {
BobID:="bob"
s:=31 // Secret server key
rand.Seed(time.Now().UnixNano())
r:=rand.Intn(4294967296)
argCount := len(os.Args[1:])

if (argCount>0) {BobID= (os.Args[1])}
if (argCount>1) {s,_= strconv.Atoi(os.Args[2])}
h := sha256.New()
h.Write([]byte(BobID))
PbobID := h.Sum(nil)


U := BN254.ECP_generator()
V := BN254.ECP2_generator()

priv1:=BN254.G1mul(U,BN254.NewBIGint(s))
priv2:=BN254.G2mul(V,BN254.FromBytes(PbobID))
key_alice := BN254.Ate(priv2,priv1)
key_alice = BN254.Fexp(key_alice)
key_alice = BN254.GTpow(key_alice,BN254.NewBIGint(r))

priv3:=BN254.G1mul(U,BN254.NewBIGint(r))
priv4:=BN254.G2mul(V,BN254.FromBytes(PbobID))
priv4=BN254.G2mul(priv4,BN254.NewBIGint(s))
key_bob := BN254.Ate(priv4,priv3)
key_bob= BN254.Fexp(key_bob)

fmt.Printf("\nBob ID: %s, Secret: %d, Random: %d\n",BobID,s,r)

fmt.Printf("\nPairing: %s\n",key_alice.ToString())
fmt.Printf("\nAlice uses key (first 20 bytes):\t0x%x\n",FP12toByte(key_alice)[:20])
fmt.Printf("Bob uses key (first 20 bytes):\t0x%x\n",FP12toByte(key_bob)[:20])

if key_bob.Equals(key_alice) { fmt.Printf("\nPairing 1 [e(sV,Qid)^r] is equal to Pairing 2 [e(rV,sQid)]")}
}

A sample run is [here]:

Bob ID: bob@home, Secret: 99, Random: 1964639580
Pairing: [[[1cacae94b91ed2ab6c01d2b90615ffcdb3ddadb0a15ef2534572d75429aa8b9e,03d57facdc2b1192967059846585950d13f16f34aa2a2a957cc84747c4918baa],[212a86b9611493f47895916551c4bfe3d7ea8813b3b83fa55194f99affbdb9a0,0dcb049c002aaebf25af97b1c3c897ddfece7f925655c207ed73d30d08873da4]],[[1f704648268d49a61f3d186352a7ca044b279d2783a22abd143f42b0f95cfa21,18bf82dd579ed56cdc23dccde23b523e10afac5697c4946464ffa38262afa9ec],[1f72aba7c189936b6e10e9e04bdc3a4f3c610c9d99199bdfb64a2a54f8263bcd,2015a1cdb36f86fb593799074e316226d7be5f0eae94ab2f4d8adab7d3ad8f43]],[[0505925d153269cf1f098a98cac61446684cca4ad776694a7d22e18cc322a803,1ff552888960f51e8aafc37f13561c940ec05ed05ea7ce9e1b7b730e66419177],[1cdaf6921edfbba779743484f6a08f7487a03363bfd682e2e82e79c6d68be109,0a5dbc358073682e2c8af23233b8a2051c2c98d93b2f579e18350bcd926cb863]]]

Alice uses key (first 20 bytes): 0x1cacae94b91ed2ab6c01d2b90615ffcdb3ddadb0
Bob uses key (first 20 bytes): 0x1cacae94b91ed2ab6c01d2b90615ffcdb3ddadb0

Pairing 1 [e(sV,Qid)^r] is equal to Pairing 2 [e(rV,sQid)]

In this case, Bob and Alice have the same encryption key and can now create a secret tunnel for their communications.

Conclusions

I might be wrong, but PKI does scale well in applications where you need to define a strong trust infrastructure and have it controlled by a trust server. The IBE approach is one way for the trust server to hold Bob’s secret without giving it away.

References

[1] Shamir, A. (1984, August). Identity-based cryptosystems and signature schemes. In Workshop on the theory and application of cryptographic techniques (pp. 47–53). Springer, Berlin, Heidelberg [here].

[2] Buchanan, William J (2023). Pair-based cryptography IBE with MIRACL. Asecuritysite.com. https://asecuritysite.com/ibe/mir_ibe