This project is a C++ implementation of the lightweight Key-Policy Attribute-Based Encryption (KP-ABE) scheme from [1].
The scheme has significant performance advantages[2] over other schemes by relying on elliptic curve cryptography as opposed to bilinear pairings. Its security is proved in the attribute-based selective-set model.
The implementation can run on a ESP32 device with slight modifications. I removed these modifications for simplicity, but if you are interested in running it on an ESP32, open an issue and I will add it.
The project depends on:
- gmp - The GNU Multiple Precision Arithmetic Library
- pbc - Pairing-Based Cryptography Library
- mbedcrypto from mbedtls
- (for the tests only) Boost.Test
The include and library paths for the above can be seen in the SConstruct.py in the
INCLUDES
and LIBPATH
variables. Go ahead and change them if necessary.
The project compiles with scons in the root directory. Just run:
scons -f SConstruct.py
This generates the static library libkpabe
, but it's straightforward to compile with
your code without using a library. The above also produces the tests (kpabe_test
) and a
simple example program (main
).
The reason that this is compiled as a static library and that it uses mbedtls instead of some other common crypto is because the project had to run on a ESP32 device.
Here is a simple example of generating a key and a secret and then using the key to recover the secret.
// Setup the scheme
PrivateParams priv;
PublicParams pub;
vector<int> attributeUniverse {1, 2, 3, 4, 5};
setup(attributeUniverse, pub, priv);
// Create an access policy and derive a key for it.
// (1 OR 2) AND (3 OR 4)
Node orNodeLeft(Node::Type::OR, {1, 2});
Node orNodeRight(Node::Type::OR, {3, 4});
Node root(Node::Type::AND, {orNodeLeft, orNodeRight});
auto key = keyGeneration(priv, root);
// Create an attribute-based secret (attributes 1 and 3).
element_s secret;
vector<int> encryptionAttributes {1, 3};
auto Cw = createSecret(pub, encryptionAttributes, secret); // Decryption parameters
// Recover secret
element_s recovered;
recoverSecret(key, Cw, attributes, recovered);
element_cmp(&secret, &recovered); // should be ==0
for(auto& attrCiPair: Cw) { //clean up
element_clear(&attrCiPair.second);
}
// Secret cannot be recovered if the policy is not satisfied by the encryption attributes.
encryptionAttributes = {1};
Cw = createSecret(pub, encryptionAttributes, secret);
try {
recoverSecret(key, Cw, encryptionAttributes, recovered);
} catch(const UnsatError& e) {
cout << "Unsatisfied" << endl;
}
// Clean up (this should happen as part of destruction, so my bad)
for(auto& attrDiPair: key.Di) {
element_clear(&attrDiPair.second);
}
for(auto& attrCiPair: Cw) {
element_clear(&attrCiPair.second);
}
I would like to change at least a few things in the API, should I find the time. Suggestions are always welcome.
There is also a python implementation of this scheme as part of Charm.
It should be possible to use the same attribute more than once in a policy - e.g. ((1 OR 2) AND (1 OR 3)). However, the current implementation does not allow this.
[1] X. Yao, Z. Chen and Y. Tian, “A lightweight attribute-based encryption scheme for the Internet of Things,” Future Generation Computer Systems, vol. 49, pp. 104-112, 2015. link
[2] S. Zickau, D. Thatmann, A. Butyrtschik, I. Denisow and A. Küpper, “Applied Attribute- based Encryption Schemes,” in 19th International ICIN Conference - Innovations in Clouds, Internet and Networks, Paris, 2016. link