mosaic

module
v0.0.0-...-3a38687 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 20, 2020 License: AGPL-3.0

README

Mosaic

Mosaic is a library doing Attribute Based Encryption (ABE). It is meant to be used as a example of a cryptographic core to be embedded in any solution willing to rely on an ABE scheme of this kind (a Multi-Authority CipherText-Policy scheme, see below).

Please remark

The code is for demonstration purposes only and it is not suitable for embedding in any reliable cryptographic solutions. A quantity of structure which should be needed in any reliable cryptographic solution is missing in the code base (about randomness, hashing functions used, selection of curves and pairings and underlying cryptographic library, hash-to-groups primitives, secure communication, in-memory management of cryptographic calculations and many other issues). Moreover, the code is not fully tested (nor formally verified), nor yet implementing any reliable error management procedure and should not be used in production environments.

The library is under the copyleft license AGPL-3.0.

library is under development (APIs are subject to change) please check for updates

Attribute Based Encryption

Attribute based encryption is about sharing a secret according to attributes and policies. A policy is an expression (boolean or integer-valued with linear constraints) whose variables are called attributes. The cryptographic scheme allows the encryption of a secret according to a given policy, splitting the secret among the attributes mentioned in the policy. The secret could be recovered only by a set of keys corresponding to attributes which satisfy the policy (i.e., make the policy expression evaluate to true).

Those keys are attached to attributes and users (both strings or, in general, hashable objects). Users can obtain these attribute-keys asking some authority for them (so, the secret could only be recovered by those users having enough attributes as to satisfy the policy).

In a sense, attribute based encryption generalizes asymmetric cryptography: the communication is no more 1:1 and the sender (encrypting) could ignore the users allowed to receive (decrypt) her messages.

An example: document sharing

Assume a company wants to manage the access to certain documents among its employees. So, the company instantiate an authority company, so that users can ask this authority for attributes like logistics@company or it@company or topsecret@company. It is up to the authority to decide whether to give a given attribute-key to a user or not.

A user that needs to encrypt some documents can create a policy like logistics@company \/ topsecret@company (meaning that the policy is meant to grant access rights to those user having keys for logistics@company or for topsecret@company), and use this policy to encrypt the documents. Now, the authorization layer to the documents is embedded in the mathematics, meaning that only those users having the appropriate keys will be able to decrypt the documents.

Policy can also include linear constraints on non-negative integer-valued attributes, so, users can ask for attributes like level@company with some value from 0 onwards, to be used in a policy like topsecret@company \/ (level@company > 0 )

The scheme implemented

The code implements the Multi-Authority CipherText-Policy scheme as described in Efficient Statically-Secure Large-Universe Multi-Authority Attribute-Based Encryption by Yannis Rouselakis and Brent Waters.

Specifically, the implementation

  • is based on elliptic curves pairings, powered by miracl (recommended) (code included in this repo) or pbc (including parts of the Go wrapper https://github.com/Nik-U/pbc) [rf. to config file later in this doc]
  • uses linear secret sharing schemes as explained in section G of Decentralizing Attribute-Based Encryption by Allison Lewko and Brent Waters
  • allows numerical expressions in policies (see paragraph below) using a bag-of-bits representation of attributes as in Ciphertext-Policy Attribute-Based Encryption by John Bethencourt, Amit Sahai, Brent Waters
  • uses z3 to verify, simplify and rewrite policies (it could use z3 also to solve and get hints from policies)
  • collects the authorities into organizations: policy are allowed to mention only attributes from authorities within a given organization
  • uses an elementary hash-to-group function to map attribute and user strings to the group

Syntax for attributes and policies:

  • boolean attributes are in the form attribute@authority (cfr. notation already used in Charm)
  • integer-valued attributes are written attribute=value@authority
  • policies are arbitrary expressions in attributes with operators /\ (AND) and \/ (OR)
  • policies allow == < <= > >= between an attribute (on the left) and a numerical value (on the right)
  • supporting also S-expressions for policies

APIs

To use the library in a Go environment

import "github.com/marcellop71/mosaic/abe"

Core Go APIs are wrapped by JSON APIs so that every function has only string type parameters as inputs and outputs (string could be a plain or a JSON string depending on the function).

Everything binary is encoded to base32 (both JSON strings and field values in JSON objects).

Given the JSON APIs, the library could also be exported as a shared object (resulting in libmosaic.h and libabe.so in ./lib usable by many languages). The wrapping is trivial because there are only char* in each signature.

go build -tags=z3,miracl -buildmode c-shared -o lib/libmosaic.so lib/mosaic.go

(or lib/mosaic_pbc.go)

GO API GO API (JSON) C API
NewRandomOrg (lib string, curve Curve) Org NewRandomOrgJson(string, string) string newRandomOrg
NewRandomAuth(org Org) AuthKeys NewRandomAuthJson(string) string newRandomAuth
NewRandomUserkey(user string, attr string, authprv AuthPrv) Userkey NewRandomUserkeyJson(string, string, string) string newRandomUserkey
NewRandomSecret(org Org, seed string) Point NewRandomSecretJson(string, string) string newRandomSecret
AuthPubsOfPolicy(policy string) AuthPubs AuthPubsOfPolicyJson(string) string authpubsOfPolicy
PolicyOfCiphertext(ct Ciphertext) string PolicyOfCiphertextJson(string) string policyOfCiphertextJson
SelectUserAttrs(user string, policy string, userattrs Userattrs) Userattrs SelectUserAttrsJson(string, string, string) string selectUserAttrs
Encrypt(secret Point, policy string, authpubs AuthPubs) string EncryptJson(string, string, string) string encrypt
Decrypt(ct Ciphertext, userattrs Userattrs) Point DecryptJson(string, string) string decrypt
RewritePolicy(policy string) string RewritePolicy(string) string rewritePolicy
CheckPolicy(policy string, userattrs Userattrs) string CheckPolicyJson(string, string) string checkPolicy
GetPbcCurve(curve string) Curve GetPbcCurve(string) string getPbcCurve

RewritePolicy and CheckPolicy needs z3 support, while GetPbcCurve needs pbc. Please remark that the support by z3 and miracl (or pbc) is managed by the build tags "z3", "miracl" and "pbc". For example, run the example with

go run -tags=z3,miracl examples/ex_JsonAPI.go

Here, the signature is described by a suffix Str (plain string) or Json (json string, for the objects serialized as json strings).

export signature json schema for output
newRandomOrg libStr, CurveJson (empty if not pbc) -> orgJson json to be used as-is
newRandomAuth orgJson -> authkeysJson { "authpub": "authority public key json string", "authprv": "authority private key json string"}
newRandomUserkey userStr, attrStr, authprvJson -> userattrsJson {"user": "user string", "coeff": {"attribute0": [], ...}, "userkey": {"attribute0": "userkey json string", ...}}
newRandomSecret orgJson, seedStr -> secretStr plain string
rewritePolicy policyStr -> policyStr plain string
checkPolicy policyStr, userattrsJson (possibly empty) -> string {"sat", "unsat"} plain string
extractAuthsFromPolicy policyStr -> authpubsJson {"authpub": {"authority0": "authority public key", "authority1": "authority public key json string", ...}}
extractPolicyFromCiphertext ciphertextJson -> policyStr plain string
selectUserAttrs userStr, policyStr, userattrsJson -> userattrsJson {"user": "user string", "coeff": {"attribute0": [], ...}, "userkey": {"attribute0": "userkey json string", ...}}
encrypt secretJson, policyStr, authpubsJson -> ciphertextJson json to be used as-is
decrypt ciphertextJson, userattrsJson -> secretStr plain string
getPbcCurve (only for pbc) curveStr -> CurveJson json to be used as-is

The json strings returned by getCurve, newRandomOrg and encrypt are meant to be used as-is: stored somewhere or re-fed into the relevant functions.

An application needs to interact only with authkeysJson, authpubsJson and userattrsJson. authkeysJson holds the public and private keys for a new authority. authpubsJson is a json holding in the key 'authpub' the association between an authority (name) and its corresponding public key, while userattrsJson holds the associations between an attribute and its use (coefficent) in the key "coeff" and between an attribute and its corresponding user key in the key "key".


type Org struct { ... } // organization
type AuthPub struct { ... } // authority public params
type AuthPrv struct { ... } // authority private params
type Userkey struct { ... } // user key
type Ciphertext struct { ... } // ciphertext encrypting the msg

type AuthKeys struct { // authority public and private keys
	AuthPub string `json:"authpub"` // type AuthPub
	AuthPrv string `json:"authprv"` // type AuthPrv
}

type AuthPubs struct { // map of authorities public keys
	AuthPub map[string]string `json:"authpub"` // type AuthPub
}

type UserAttrs struct { // map of user attributes
	User string `json:"user"` // user
	Coeff map[string][]int `json:"coeff"` // attr -> its coefficients
	Userkey map[string]string `json:"userkey"` // Userkey
}
Dependencies

The only external dependency that needs to be available is z3 (optionally, also pbc).

Internally, the Go packages used are: logrus for logging and antlr4 for parsing.

The examples (not the library, see below) use

Dependencies or database support could be easily installed:

  • mac os: brew install z3 and brew install leveldb redis (in case also, brew install pbc)
  • linux: see ./docker/Dockerfile
Docker

You can build a docker images with everything:

./docker/build_image.sh

Source is made up of 2 Go packages:

  • abe: core package defining basic types and the cryptographic scheme
  • service: service package defining interactions with databases

The file structure of the core lib is the following:

file description
arith_miracl.go miracl interface
arith_pbc.go pbc interface
crypto.go ABE scheme algorithms and JSON APIs
policy_z3.go policy management using z3
policy.go parsing and policy management
sss.go linear secret sharing scheme
types.go structs and their serialization
Policy.g4 antlr4 parser grammar
PolicyLexer.g4 antlr4 lexer grammar
log/ logging
miracl/ miracl core library (Go version)
parser/ policy parser (generated by antlr4 using the ./abe/policy.g4 grammar file)
pbc/ pbc library wrapper
z3/ z3 library wrapper

Examples

An ./examples/ex_GoAPI_noservice_noz3.go is there to show how the APIs could be used. The aim is to encrypt a secret according to a given policy (iterating over a small set of policies) and recover it (if feasible), according to a selection of attributes given to a user.

go run -tags=z3,miracl examples/ex_GoAPI_noservice_noz3.go

or

docker run -it mosaic:latest go run -tags=z3,miracl examples/ex_GoAPI_noservice_noz3.go
Storage

./examples/ex_GoAPI_noservice_noz3.go is an application using the github.com/mosaic/abe package and a ./mosaic/service package to handle some storage for the keys, the attributes and the users. The service package implemented can use Leveldb or a Redis server. Details in the configuration file ./examples/config.yaml

config:
  arithmetic:
    library: miracl
    curve: BN254
    seed: abcdef
  storage:
    redis:
      local0:
        addr: "127.0.0.1:6379"
        password: ""
    leveldb:
      local0:
        name: "mosaic.db"
  active:
    type: "leveldb"
    label: "local0"
Workflow

The workflow implemented in the example is basic. Using attribute based encryption for a document sharing application could mean that an encryptor:

  • creates a random secret
  • uses this secret to encrypt (symmetric) a document
  • creates a policy string describing access to the document
  • creates an encrypted version secret_enc of the secret according to the policy
  • shares the encrypted document and the secret_enc + an hashed version of the secret secret_hash

now if a user needs to access the document:

  • user asks an authority for its keys corresponding to a given attribute
  • user decrypts the secret_enc into a clear secret
  • user checks if she can recover the secret_hash
  • user uses this secret to decrypt the document
Setup curve, organization and authorities
service.SetupOrg("org0", "miracl", "BN254", seed) // setting up an organization (hosting a set of authorities) onto a given curve
service.SetupAuth("auth0", "org0")  							// setting up an authority into a given organization
Using boolean policies
policy := "A@auth0 /\\ (B@auth0 /\\ (C@auth0 \\/ D@auth0))" // a policy as a standard boolean expression

// encrypting
secret := service.NewRandomSecret("org0")  				   // create a new secret
policy = abe.RewritePolicy(policy)               	   // simplify policy
auths := abe.AuthPubsOfPolicyJson(policy)      		   // extracts authorities mentioned in the policy
auths = service.FetchAuthPubs(auths)             		 // collects public keys of those authorities
secret_enc := abe.EncryptJson(secret, policy, auths) // encrypts the secret into a ciphertext

// user asking for keys
user := "marcello.paris@gmail.com"
service.SetupUserkey(user, "A@auth0") // for the user creates a key corresponding to the given attribute
service.SetupUserkey(user, "B@auth0") // for the user creates a key corresponding to the given attribute
service.SetupUserkey(user, "C@auth0") // for the user creates a key corresponding to the given attribute
service.SetupUserkey(user, "D@auth0") // for the user creates a key corresponding to the given attribute

// decrypting
policy = abe.PolicyOfCiphertextJson(secret_enc)              // extract the policy embedded in the ciphertext
userattrs := service.FetchUserAttrs(user)                    // collects the available user attributes
userattrs = abe.SelectUserAttrsJson(user, policy, userattrs) // select which user attributes (if any) are useful for the given policy
userattrs = service.FetchUserkeys(userattrs)                 // collects user keys corresponding to the useful attributes
secret_dec := abe.DecryptJson(secret_enc, userattrs)         // decrypts the ciphertext into the secret plaintext
Integer-valued attributes
policy := "(A@auth0 > 1) /\\ B@auth0"
...
service.SetupUserkey(user, "A=5@auth0")

Curves and pairings

Use "BN254" or "BLS12381" or "BN462" if using miracl (recommended) or use "SS512" or "BN254" if using pbc.

Let the pairing be G1 x G2 -> GT

The scheme encrypts a point in GT as:

  • a point on GT (the point to be encrypted perturbed by a secret)
  • a bags of 4-points tuples (i.e., bag of points on GT x G1 x G1 x G2) [one tuple for each attribute-leave in the policy]

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL