Hidding Attributes in ABE: DIPPE (Decentralized Inner-Product Predicate Encryption)
With Attribute-Based Encryption (ABE) [2], we allow users with certain attributes to decrypt data. This might relate to their location or their rights to log into a network. Two key features of this are to provide multiple authorities in providing the attributes (multi-authority — MA-ABE) and in hiding the access policy used. With DIPPE (Decentralized Inner-Product Predicate Encryption) [1], we can perform both multi-authority provided attributes, and also access policy hiding. This provides a decentralised approach to ABE.
For policy hiding, DIPPE uses a decentralized inner-product predicate encryption scheme, where we have a policy vector and a user vector that is orthogonal. For this, their inner product should be zero.
If we have two vectors of u and v, then they are orthogonal if their inner product is zero:
⟨u,v⟩=0
For example, if we have:
Thus:
⟨u,v⟩=(0×1)+(−1×1)+(1×1)+(0×−3)+(0×−4)=0
The basic steps are:
Setup. This takes an input parameter and then creates public parameters (pp):
a, err := abe.NewDIPPE(3)
AuthSetup. This takes the public parameters and an authority index i, and outputs the authority’s secret key (sk) and public key (pk):
// create authorities and their public keys
auth := make([]*abe.DIPPEAuth, vecLen)
pubKeys := make([]*abe.DIPPEPubKey, vecLen)
for i := range auth {
auth[i], err = a.NewDIPPEAuth(i)
if err != nil {
fmt.Printf("New authority generation failed: %v\n", err)
}
pubKeys[i] = &auth[i].Pk
}
GenKey. This takes the public parameters, the authority index (i), the secrete key, the public parameters from other authorities, a user global ID, and the attribute vector, and outputs a secret key:
// Define GID for the user
userGID := "Bob"
// Setup user vector. To decrypt, the users and policy vector must be orthogonal
v=toArray(vector2)
userVector := data.Vector([]*big.Int{big.NewInt(v[0]), big.NewInt(v[1]),
big.NewInt(v[2]), big.NewInt(v[3]), big.NewInt(v[4])})
// Generate keys from authorities
userKeys := make([]data.VectorG2, vecLen)
for i := range auth {
userKeys[i], err = auth[i].DeriveKeyShare(userVector, pubKeys, userGID)
if err != nil {
fmt.Printf("User key generation failed: %v\n", err)
}
}
Encrypt. We can then encrypt with the public keys and a policy vector:
v:=toArray(vector1)
policyVector := data.Vector([]*big.Int{big.NewInt(v[0]), big.NewInt(v[1]),
big.NewInt(v[2]), big.NewInt(v[3]), big.NewInt(v[4])})
// encrypt the message with the chosen policy give by a policy vector,
cipher, err := a.Encrypt(msg, policyVector, pubKeys)
if err != nil {
fmt.Printf("Encryption failure: %v\n", err)
}
Decrypt. We can then decrypt the cipher using the user keys, the user vector and the userGID:
msgRecovered, err := a.Decrypt(cipher, userKeys, userVector, userGID)
The full code is [here]:
package main
import (
"fmt"
"os"
"github.com/fentec-project/gofe/abe"
"github.com/fentec-project/gofe/data"
"math/big"
"strings"
"strconv"
)
func toArray(s string) []int64 {
strs := strings.Split(s, " ")
a := make([]int64, len(strs))
for i := range a {
a[i],_ = strconv.ParseInt(strs[i], 10, 64)
}
return a
}
func main() {
msg:="Hello"
vector1:="1 -1 1 0 0"
vector2:="0 1 1 -3 4"
argCount := len(os.Args[1:])
if (argCount>0) { msg= (os.Args[1]) }
if (argCount>1) { vector1= (os.Args[2]) }
if (argCount>2) { vector2= (os.Args[3]) }
a, err := abe.NewDIPPE(3)
if err != nil {
fmt.Printf("New scheme generation failed: %v\n", err)
}
vecLen := 5
// create authorities and their public keys
auth := make([]*abe.DIPPEAuth, vecLen)
pubKeys := make([]*abe.DIPPEPubKey, vecLen)
for i := range auth {
auth[i], err = a.NewDIPPEAuth(i)
if err != nil {
fmt.Printf("New authority generation failed: %v\n", err)
}
pubKeys[i] = &auth[i].Pk
}
// Policy vector
v:=toArray(vector1)
policyVector := data.Vector([]*big.Int{big.NewInt(v[0]), big.NewInt(v[1]),
big.NewInt(v[2]), big.NewInt(v[3]), big.NewInt(v[4])})
// encrypt the message with the chosen policy give by a policy vector,
cipher, err := a.Encrypt(msg, policyVector, pubKeys)
if err != nil {
fmt.Printf("Encryption failure: %v\n", err)
}
// Define GID for the user
userGID := "Bob"
// Setup user vector. To decrypt, the users and policy vector must be orthogonal
v=toArray(vector2)
userVector := data.Vector([]*big.Int{big.NewInt(v[0]), big.NewInt(v[1]),
big.NewInt(v[2]), big.NewInt(v[3]), big.NewInt(v[4])})
// Generate keys from authorities
userKeys := make([]data.VectorG2, vecLen)
for i := range auth {
userKeys[i], err = auth[i].DeriveKeyShare(userVector, pubKeys, userGID)
if err != nil {
fmt.Printf("User key generation failed: %v\n", err)
}
}
// Decryption by the user
msgRecovered, err := a.Decrypt(cipher, userKeys, userVector, userGID)
if err != nil {
fmt.Printf("Decryption failed: %v\n", err)
}
fmt.Printf("Policy vector: %v\nUser vector: %v\n\n",policyVector,userVector)
fmt.Printf("Message: %v\nRecovered %v",msg, msgRecovered)
}
And some examples are:
- Msg: “Hello”, Security: [1 -1 1 0 0] User: [0 1 1 -3 4] Try!. Orthogonal.
- Msg: “Hello”, Security: [1 -2 1 0 1] User: [1 1 1 -3 4] Try!. Not orthogonal
- Msg: “Hello”, Security: [4 -3 2 1 0] User: [1 1 1 -3 4] Try!. Orthogonal.
- Msg: “Hello”, Security: [4 -3 2 1 1] User: [1 1 1 -3 4] Try!. Not orthogonal.
References
[1] Michalevsky, Y., & Joye, M. (2018). Decentralized policy-hiding ABE with receiver privacy. In Computer Security: 23rd European Symposium on Research in Computer Security, ESORICS 2018, Barcelona, Spain, September 3–7, 2018, Proceedings, Part II 23 (pp. 548–567). Springer International Publishing.
[2] Sahai, A., & Waters, B. (2005). Fuzzy identity-based encryption. In Advances in Cryptology–EUROCRYPT 2005: 24th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Aarhus, Denmark, May 22–26, 2005. Proceedings 24 (pp. 457–473). Springer Berlin Heidelberg.