Identity-based Encryption

CrowdNotifier uses a specific identity-based encryption scheme, to ensure all security and privacy properties. In particular, CrowdNotifier uses a slight modification of the FullIdent Boneh-Franklin scheme [BF01] given by the following algorithms. (The only modification is that the randomness \(r\) now also depends on the identity \(\id\), which is passed to \(\ibedec\) for verification purposes.)

Mathematical description

  • \(\pp \gets \ibecommonsetup(1^\secpar)\). On input of security parameter \(\secpar\), generate a type III set of bilinear groups \(\group_1, \group_2, \group_T\) generated by respectively \(\generator_1, \generator_2, \generator_T\) all of prime order \(\grouporder\) and let \(\pairsym: \group_1 \times \group_2 \to \group_T\) be the corresponding pairing. Generate the following hash-functions (modeled as random oracles): \(\hash_1: \{0,1\}^* \to \group_1^*\) a hash function mapping points to the group \(\group_1^*\), \(\hash_T : \group_T \to \{0,1\}^{2\secpar}\) mapping group elements from the target group, \(\hash_3: \{0,1\}^{2\secpar} \times \bins \times \bins \to \{0,1\}^{2\secpar}\), and \(\hash_4: \{0,1\}^{2\secpar} \to \mathcal{K}\) mapping into the key-space of the authenticated encryption scheme. Setup outputs \(\pp = ((\group_1, \group_2, \group_T, \generator_1, \generator_2, \generator_T, \grouporder, \pairsym), \hash_1, \hash_T, \hash_3, \hash_4)\).

  • \((\masterpk, \mastersk) \gets \ibekeygen(\pp)\). Pick random \(\mastersk \gets \Zp\) and set \(\masterpk = g_2^{\mastersk} \in \group_2.\) Return \((\masterpk, \mastersk)\).

  • \(\skid \gets \ibekeyder(\masterpk, \mastersk, \id)\). On input of a master public key \(\masterpk\), a master private key \(\mastersk\), and an identity \(\id \in \{0, 1\}^*\); outputs private key \(\skid = \hash_1(\id)^{\mastersk} \in \group_1\).

  • \(\ctxt \gets \ibeenc(\masterpk, \id, m)\). On input of a master public key \(\masterpk\), an identity \(\id \in \bins\), and a message \(m\), proceed as follows. Check that \(\masterpk \in \group_2^*\). Pick a random key \(x \gets \{0, 1\}^{2\secpar}\) and compute

\[ \begin{align}\begin{aligned}c_1 &= g_2^r,\\c_2 &= x \oplus \hash_T( \pairsym(\hash_1(\id), \masterpk)^r),\\c_3 &= \aeenc(H_4(x), m)\end{aligned}\end{align} \]

where \(r = \hash_3(x, m, \id)\). Return \(\ctxt = (c_1, c_2, c_3)\).

  • \(m \gets \ibedec(\id, \skid, \ctxt)\). On input of an identity \(\id\), a private key \(\skid\), and a ciphertext \(\ctxt\), proceed as follows. Parse \(\ctxt\) as \((c_1, c_2, c_3)\) and return \(\bot\) if parsing fails. Check that \(\skid \in \group_1^*\), and compute \(x' = c_2 \oplus \hash_T( \pairsym(\skid, c_1) )\) and \(m' = \aedec(H_4(x'), c_3)\). Return \(\bot\) if \(m' = \bot\). Finally, compute \(r' = \hash_3(x', m', \id)\) and check that \(c_1 = g_2^{r'}\). If this check fails, return \(\bot\), otherwise, return \(m'\).

Implementation of IBE in CrowdNotifier

The following is a list of pseudo-codes describing how the above methods can be implemented:

  • IBE.CommonSetup using mcl.init:

    mcl.init(mcl.BLS12_381)
    
  • IBE.KeyGen:

    msk = new mcl.Fr();
    msk.setByCSPRNG();
    
    mpk = mcl.mul(baseG2, msk);
    
  • IBE.KeyDer(msk, id):

    skid = mcl.mul(h1(id), msk)
    
  • IBE.Enc(mpk, id, m):

    x = randombytes_buf(NONCE_LENGTH);
    
    r = h3(x, id, m);
    c1 = mcl.mul(baseG2, r);
    
    c2_pair = ht(mcl.pow(mcl.pairing(h1(id), mpk), r));
    c2 = xor(x, c2_pair);
    
    nonce = randombytes_buf(crypto_secretbox_NONCEBYTES);
    
    c3 = crypto_secretbox_easy(m, nonce, h4(x));
    
  • IBE.Dec(id, skid, ctxt = (c1, c2, c3)):

    x_p = xor(c2, ht(mcl.pairing(skid, c1)));
    msg_p = crypto_secretbox_open_easy(c3, nonce, h4(x_p));
    // or return _I_ on error
    
    r_p = h3(x_p, id, msg_p);
    c1_p = mcl.mul(baseG2, r_p);
    
    if (!c1.isEqual(c1_p)) {
      return _I_;
    }
    
    // Check that skid is in G1*
    if (!skid.isValidOrder() || skid.isZero()) {
      return _I_;
    }
    
    return msg_p;
    

With the following helper methods:

  • h1(id):

    h1 = mcl.hashAndMapToG1(id)
    
  • h3(x_p, id, msg_p):

    h3 = new mcl.Fr();
    // The '+' concatenates the binary arrays
    h3.setHashOf(x_p + id + msg_p);
    
  • h4(id):

    h4 = crypto_hash_sha256(id)
    
  • ht(gt):

    ht = crypto_hash_sha256(gt.serialize())
    
  • xor(a, b):

    c[i] = a[i] ^ b[i]
    
  • baseG2:

    baseG2 = new mcl.G2();
    baseG2.setStr(
           '135270106958746661818713911601106014489002995279277524021990864' +
           '4239793785735715026873347600343865175952761926303160 ' +
           '305914434424421370997125981475378163698647032547664755865937320' +
           '6291635324768958432433509563104347017837885763365758 ' +
           '198515060228729193556805452117717163830086897821565573085937866' +
           '5066344726373823718423869104263333984641494340347905 ' +
           '927553665492332455747201965776037880757740193453592970025027978' +
           '793976877002675564980949289727957565575433344219582');
    

Serialization of Keys

The master public key \(\masterpk\) consists of a single element in \(\group_2\). We serialize it using the mcl serialization function.