mosaic

module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 5, 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 curve and pairings and underlying cryptographic library, 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.

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 (temporarily using pbc and including parts of the Go wrapper https://github.com/Nik-U/pbc)
  • 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/unicredit/mosaic/abe"

The APIs are designed so that the very external functions has only string type parameters as inputs and outputs (string could be a plain or a json string depending on the function).

The signature is described by a suffix Str (plain string) or Json (json string, for the objects serialized as json strings). Everything binary is encoded to base32. Field values in the schemas are encoded json strings.

signature type
NewRandomOrg(curveJson string) string PbcCurve -> Org
NewRandomAuth(orgJson string) string Org - > AuthKeys
NewRandomUserkey(user string, attr string, authprvJson string) string string, string, AuthPrv -> Userkey
NewRandomSecret(orgJson string, seed string) string Org, string -> string
RewritePolicy(policy string) string string -> string
CheckPolicy(policy string, userattrsJson string) string string, UserAttrs -> string
ExtractAuthsFromPolicy(policy string) string string -> AuthPubs
ExtractPolicyFromCiphertext(ctJson string) string Ciphertext -> string
SelectUserAttrs(user string, policy string, userattrsJson string) string string, string, UserAttrs -> UserAttrs
Encrypt(secret string, policy string, authpubsJson string) string string, string, UserAttrs -> Ciphertext
Decrypt(ctJson string, userattrsJson string) string Ciphertext, UserAttrs -> string
GetCurve(curveStr string) string string -> PbcCurve

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
}
C 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 -buildmode c-shared -o lib/libmosaic.so lib/mosaic.go
export signature json schema for output
newRandomOrg pbcCurveJson -> 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) -> {"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 secretStr, policyStr, authpubsJson -> ciphertextJson json to be used as-is
decrypt ciphertextJson, userattrsJson -> secretStr plain string
getCurve curveStr -> pbcCurveJson 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".

Dependencies

The external dependencies that needs to be available are z3 and 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 pbc and brew install leveldb redis
  • 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_pbc.go pbc library wrapper (to be refactored using interfaces)
crypto.go ABE scheme algorithms
encode.go encode/decode types json
log.go logging
policy.go parsing and policy management
sss.go linear secret sharing scheme
types.go structs
Policy.g4 Antlr4 parser grammar
PolicyLexer.g4 Antlr4 lexer grammar
parser/ policy parser (generated by antlr4 using the ./abe/policy.g4 grammar file)
pbc/pbc_darwin.go pbc wrapper
pbc/pbc_linux.go pbc wrapper
ze/z3.go z3 wrapper

Examples

An ./examples/example.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 examples/example.go

or

docker run -it mosaic:latest go run examples/example.go
Storage

./examples/example.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:
  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.SetupCurve("SS512")         // setting up a curve
service.SetupOrg("org0", "SS512")   // 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
seed := ""                                       // secret will be random
secret := service.NewRandomSecret("org0", seed)  // create a new secret
policy = abe.RewritePolicy(policy)               // simplify policy
auths := abe.ExtractAuthsFromPolicy(policy)      // extracts authorities mentioned in the policy
auths = service.FetchAuthPubs(auths)             // collects public keys of those authorities
secret_enc := abe.Encrypt(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.ExtractPolicyFromCiphertext(secret_enc)     // extract the policy embedded in the ciphertext
userattrs := service.FetchUserAttrs(user)                // collects the available user attributes
userattrs = abe.SelectUserAttrs(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.Decrypt(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 "SS512" or "BN254" (very different setups and timings). Please refer to the pbc manual

Directories

Path Synopsis
abe
log
pbc
+build linux
+build linux
z3
+build cgo
+build cgo

Jump to

Keyboard shortcuts

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