Lybero.net - Lybcrypt SDK documentation

Version 2.1.4

Bertrand.Wallrich@lybero.net

2019-01-04

Summary

Introduction

lybcrypt is a cryptographic library for symmetric, asymmetric and asymmetric with quorum encryption/decryption, key management, key signature and web of trust.

Installation

To install the package for using in your application:

and you can use in your app :

Test

Running tests is always a good idea :

for a full test in a browser :

Documentation

All documentation is in README.md

Used Algorithms

Transfer Properties and Constraints

All cryptographic operations are done in web browsers. Users’ cryptographic keys are stored on the server.

All random values (AES keys for each file repository, asymmetric keys) are generated in the user’s web browser. These operations are difficult to attack because they are distributed. If a server is hacked, this does not lead to the disclosure of any secrets.

User account creation

When a user creates an account, a keyStore must be generated in the web browser, associated to him. It will containt public/private key pair for an asymmetric Elgamal cryptographic algorithm. All the keyStore is sent to the central server. The private key is symmetrically encrypted with the AES algorithm and the secret administrator’s password before being sent to the server in the browser.

You can use whatever authentication scheme (including Oauth2, fido u2f double authentication, …) that you want. We provide functions to do pkpbf2 authentication. If the authentication is done successfully, then the private key must be retrieved from the server and it is decrypted in the browser, when necessary. The Perfect Forward Secrecy rule is respected on the server.

# Concepts of commutativity and theshold cryptography (quorum)

Yet another cryptographic Library ?

Not realy. Lybcrypt is not only a cryptographic library, including key management, stores, signature, encryption (of course), but some remarkable concepts and/or way of using them…

Threshold cryptography (quorums)

Threshold cryptography is the way to decipher encrypted data with a group of person with the capability of people. We use this kind of cryptography on elgamal to provide the way of recovering data by a group of trustes (administrators), without introducing a point of failure (like in a simple recovering key).

This is available in lybcryt by building a quorumKey and memberKeys for each administrator. After two steps of initialisation, the quorum can be used.

Commutativity (wanted and accept)

With elGamal cryptosystem, encryption and decryption can be switched :

In a normal way :

 m -> crypt(m)
 decrypt( crypt(m) ) = m

With two users :

 m -> cryptA(m) -> cryptB( cryptA(m) ) 
 decryptB( cryptB( cryptA(m) ) ) = cryptA(m)
 decryptA( cryptA(m) ) = m

But in elgamal, decryptA(m) and cryptB(m) can be switched. This provides :

 m -> cryptA(m) -> cryptB( cryptA(m) )

 cryptB( cryptA(m) ) = cryptA( cryptB(m) )

 decryptB ( decryptA( cryptB( cryptA(m) ) ) )
   = decryptA( decryptB( cryptB( cryptA(m) ) ) )
    = m

OK. But it can be used with the concept of adWanted and acceptWanted

Adding a wanted (addWanted)

For example, Alice has an encrypted data cryptA(m). Bob want to access to this data. He can ask Alice this access. In a normal world, Alice will decrypt cryptA(m) to release m and crypt it with Bob’s public key cryptB(m). This can be seen as unsecured because at a moment the clear data appears.

With commutativity, Bob mean his ask by addWanted with ciphering cryptB( cryptA(m) ). Alice means its acceptation acceptWanted by decrypting cryptB( cryptA(m) ) = cryptA( cryptB(m) ) and the decipher is cryptB(m). The data m is never in clear.

Note : this is a schematic representation. reality is a little bitmore complexe, mixing alpha and beta from crypt for Alice and Bob. This avoid the attack from Bob to give to Alice something to decipher.

HowTo

What is a KeyStore

A keyStore from @lybero/lybcrypt is a realy simple object for using cryptographic primitives into a nodejs browser environement. It propose to avoid complexity and knowledges to developpers for end to end cryptography. It manage :

  • cryptographic keys (asymetric and symetric)
  • cryptographic functions
  • signature and trust (web of trust or PKI)
  • recovery using threshold cryptography
  • (New) Cryptography without password using devices for distribtion of privates keys

Using KeyStores

In your application, you have users. Each user have an uniq userId (a string)

When a user logon, the server provide the keyStore to the client application (in the browser). The best way to do that is to store the keyStore into the user account in the database. Then, in the browser :

For more details see KeyStore API Reference

Rules

This is rules you have to apply when using lybcrypt !

  1. One and only one keyStore per user.
  2. A user can only modify his own keyStore (exept for quorum).
  3. All cryptographic events are in the keyStore.
  4. Cryptographic keys never goes outside of the keyStore.
  5. Application exchange datas with the keyStore for ciphering-decyphering.

Create a keyStore

It is very simple.

At this point, the keyStore is created with two keys :

  • a elGamal cryptographic key
  • a ECDSA signature key

Both corresponding private keys are protected by the passphrase. You can add / import other keys after.

Crypt and decrypt

Crypt (all in one)

In this example, alice crypt a datastructure for bob (identified by his id bobId )

If the keyStore need the recipient’s keyStore (Bob’ keyStore), it will retrive it ( see manager.setGetPublicKeyStores() )

keyStore encryption
keyStore encryption
  1. Call aliceKeyStore.cryptFor()
  2. The aliceKeyStore call getPublicKeyStoreFromStoragefunc([ bobId ])
  3. This function return Bob’s keyStore,
  4. aliceKeyStore crypt with Bob’s KeyStore public keys.
  5. aliceKeyStore return a shareKeys object.

Decrypt

Decrypt all in one.

If the keyStore need the passphrase for decyphering, it will ask the aplication for that ( see manager.setInterface() )

keyStore deciphering
keyStore deciphering
  1. Call bobKeyStore.decrypt()
  2. The bobKeyStore ask the application (the user) for the passphrase) with call interfaceFunc( {} )
  3. This function return Bob’s passphrase,
  4. bobKeyStore decrypt with the private key.
  5. bobKeyStore return the clear data.

Crypt data (in detail)

In this example, the data is encrypted with a session key (AES) and this session key is encrypted with all recipient keyStore.

If the keyStore need the recipient’s keyStore (Bob’ keyStore), it will retrive it ( see manager.setGetPublicKeyStores() )

Decrypt data (in detail)

In this example, the data is encrypted in two steps : the session key is decrypted by the keyStore, then the data is decrypted by the session key.

If the keyStore need the passphrase for decyphering, it will ask the aplication for that ( see manager.setInterface() )

Signature

To avoid man in the middle attacks, you must know you recipient public key (the identity of your recipient must be proved). For that, his public key must be trusted = be signed by someone you trust.

How it works

A signature is the hash of the public key, “encrypted” by the private key of the signature bi-key. Each keyStore store all signatures. All encrypted keys are automatiquely signed by all signature keys.

keyStore signature
keyStore signature

Then, a keyStore can sign the keyStore of another user (in fact only sign the public key of the signature keys). With this mechanism, each user can sign other user’s keyStore. This is the web of trust.

For example :

keyStore signature
keyStore signature
  1. Alice has signed Bob’s keyStore (his signing key )
  2. Bob has signed Charlie’s keyStore (his signing key )
  3. Charlie, like everyone, has signed his own crypting keys.

In this condition, Alice can be sure that Charlie’s keys has not changed and she can crypt for him without any doubt.

See manager.setApplicationTrustLevel() for details.

Sign a keyStore

This is the way to avoid man-in-the-middle attacks. Sign other users keys. This is the web of trust.

If the keyStore need alice passphrase for signing, it will ask the user for that.

If the keyStore need the recipient’s keyStore (Bob’ keyStore), it will retrive it ( see manager.setGetPublicKeyStores() )

Warning: Alice keystore is modified. It must be saved.

Verify a key

You don’t have to verify the key by yourself. The keysStore will do it internally. however, if you want to do it :

Wanted

wanted is a specific feature of the lybcrypt mandatory for quorums and usefull for ciphering for somebody who has no keys !

It can be understandable as ask someboby the access to an encrypted structure. See Commutativity for mathematic details.

add a wanted

It can be understandable as a sur-crypt of an encrypted ShareKeys object. In this example : I am Zoe, and i want access to the encrypted data for Bob. I’ll ask Bob to give me access.

accept a wanted

It can be understandable as decrypt a sur-crypt on a shareKey i’m owner.of an encrypted ShareKeys object. In this example, i am Bob and Zoe ask me the access to an encrypted structure. i’ll accept and give her the access.

If the keyStore need the passphrase for accepting (because it is a decryption action), it will ask the aplication for that ( see manager.setInterface() )

Quorum

In this example, we will do a quorum group of 3 persons (Alice, Bob, Charlie) with a quorum of 2. Then :

Zoe will crypt data for the quorum group.

Brian will get access from the quorum.

We assume that each person has its own keyStore.

Step1 : Creating a quorum

The quorum is a user, with an id, and a keyStore.

Step2: Create the quorum member key

Now, Alice, Bob and Charlie will create a quorum member key in there keyStores. For alice by example :

Step3: Compute and sign the public Key of the quorum

Now Alice, Bob and Charlie can individualy compute the quorum public key. For alice by example.

At this point, the quorum keyStore is ready and can be used for ciphering.

Quorum ciphering

Crypting for a quorum is as usual. Zoe in our example

Quorum deciphering

A quorum cannot decipher data crypted for him. It can only accept wanted. Il this condition, a user must add a wanted to the quorum. In our example Brian will ask a wanted.

Quorum acceptWanted

Alice accept the wantedby Brian. But it will be not suffisant (we need another acceptwanted administrator).

KeyStore API Reference

Introducing the KeyStore API Reference

This part describe the KeyStore API reference.

For managing keyStores in the application, please see Management API Reference

acceptWanted(shareKeys, userId)

When a user as ask for cryptographic access to a SharedKeys object crypted for you, you can accept (or refuse ) and build a new shareKey object crypted structure for the user.

acceptWanted return a promise

addQuorumMemberShares(quorumKeyId, memberId, secretSharesList)

Not usefull you can use checkMemberQuorumAction after a setContent

Add quorum member shares between administrators of the quorum. This is a part of the initialisation of the quorum.

parameter type Description
 quorumKeyId string The quorum keyId in the keyStore.
 memberId string The userId of the administrator which add the list of SharedKeys object.
 secretSharesList array of strings  The list of SharedKeys object

return a promise which return true if ok.

When this operation is done for each administrator. administrators must do the sequence of :

getQuorumSharesForMe and computeMemberSecret and addQuorumPublicKey

At the end, The keyStore is modified and must be saved.

addQuorumPublicKey(_id, userId, publicKeyString)

Not usefull you can use checkMemberQuorumAction after a setContent

Each administrator add the publicKey to the quorumKey. This key is signed by the administrator himself. When all administrators have done this part, the quorum key is ready for ciphering.

parameter type Description
 quorumKeyId string The quorum keyId in the keyStore.
 memberId string The userId of the administrator which add the list of SharedKeys object.
 publicKeyString string  The quorum public key

This function return a promise which return true if ok, or false if an error occured.

At the end, The keyStore is modified and must be saved.

addWanted(shareKeys, expire = 0)

Ask to have cryptographic access to a SharedKeys object expire is a delay in second. this function modify the shareKeys object.

parameter type Description
 shareKeys ShareKeys The crypted structure.
 expire string int

addwanted return a promise

The shareKeys object is modified. It must be saved.

See acceptWanted for related informations.

changePassphrase(newPassphrase, keyIds, oldPassphrase)

Change the passphrase to protect keys. All parameters are optionals. All missing parameters are

parameter type Description
 newPassphrase string The new passphrase (not mandatory).
 keyIds [string] The list of keys you want to protect (not mandatory)
 oldPassphrase string The current passphrase (not mandatory)

changePassphrase will ask the user for missing parameter. See Manager.setInterfaceFunction()

checkMemberQuorumAction()

Do all initialisation for a quorum. It can modify the keyStore and the keyStore containing the quorum key. Do it after each setContent().

computeMemberSecret(quorumUserId, quorumKeyId, secretSharesList)

This function compute the quorum member secret key, linked with the other members trought the secretSharesList.

parameter type Description
 quorumUserId string The user who has the quorum key in his keyStore.
 quorumKeyId string The quorum keyId in the keyStore.
 secretSharesList array of strings  The list of SharedKeys object

Return a promise which return the publicKey of the quorum, signed by this keyStore.

createElGamalKey()

Create a new cryptographic key (el Gamal). Return the keyId.

At the end, The keyStore is modified and must be saved.

create(passphrase, withDeviceKeyStore = true)

return a promise for creation of the keyStore. It create a keyStore with the first signing ECDSA key and the first crypting elGamal key. Both private keys are protected with the passphrase.

parameter type Description
 passphrase string The passphrase to protect private keys.
 withDeviceKeyStore boolean Do not create device keyStore if on a new device (usefull on server for example).

It create a deviceKeyStore with a elGamal key and a ECDSA key for signing. The elgamal Key is signed by the ECDSA one.

At the end, The keyStore is modified and must be saved.

createQuorumKey(quorum, adminsList)

Create a quorum key in this keyStore.

parameter type Description
 quorum integer  The threshold.
 adminsList array of strings  The list of admins (by userId)

return a promise which return false if error or the keyId (string) created.

Next, each adminstrator must do createQuorumPrivateKey

At the end, The keyStore is modified and must be saved.

createQuorumPrivateKey(quorumKey)

parameter type Description
 quorumKey QuorumKey the key created with createQuorumKey.

Create the quorum member key corresponding to the quorum key object

At the end, The keyStore is modified and must be saved.

Next, each adminstrator must do initAndShare.

createSignKey()

Create a new signing key (ECDSA). Return the keyId.

At the end, The keyStore is modified and must be saved.

crypt(data, encryptedFormat = “base64”)

<a name=“-cryptdata,-encryptedformat-=-”base64"">

internal

cryptFor(userId, data, encryptedFormat = “base64”)

<a name=“-cryptforuserid,-data,-encryptedformat-=-”base64"">

Crypt for a user.

parameter type Description
 userId string the recipient user .
 data variable the recipient user .
 encryptedFormat string the encrypted format. see symCrypt for available formats

crypt data for a user with your keyStore. data can be :

  • ArrayBuffer
  • json object
  • string

encryptedFormat can be :

  • raw
  • struct
  • hex
  • base64 (by default)

return an object SharedKeys object or false if an error

cryptSessionKeyFor(sessionKeyId, userId)

Crypt the session key for a user.

decrypt(shareKeys)

Decrypt all in one.

parameter type Description
 shareKeys ShareKeys The crypted structure.

If the keyStore need the passphrase for decyphering, it will ask the aplication for that ( see manager.setInterface() )

decryptSessionKey(shareKeys)

In this example, the data is encrypted in two steps : the session key is decrypted by the keyStore, then the data is decrypted by the session key.

If the keyStore need the passphrase for decyphering, it will ask the aplication for that ( see manager.setInterface() )

deleteDevice(deviceId)

Suppress a device and all its keys.

parameter type Description
 deviceId string The id of the device you want to delete.

You can see all devices list of keys with getInfos() function.

At the end, The keyStore is modified and must be saved.

deleteKey(keyId)

parameter type Description
 keyId string The id of the key you want to delete.

Warning The deletion of a key involve the potential lack of ability to decrypt datas. Prefers revoke. At the end, The keyStore is modified and must be saved.

dropSignature(userId, keyId, myKeyId)

Suppress a signature from your keyStore.

parameter type Description
 userId string The id of the user you want to suppress the signature.
 keyId string his key.
 myKeyId string my key used to sign this user key.

duplicateSessionKey(id)

Create a new session key object with the same AES key. This is usefull to paralelise cryptographic actions.

getContent()

Return a promise with the keyStore content as a JSON object. All private keys returned are protected by the given passphrase.

getInfos()

Return a “comprehensible” structure of the keyStore.

return a promise which return an object containing all information about the keyStore. All its keys (no private parts), devices, signatures, etc…

See getInfos Structure for more details.

getPublicContent()

Return a promise with the keyStore public content as a JSON object. “public” means the keyStore without private keys.

initAndShare(keyId)

Not usefull you can use checkMemberQuorumAction after a setContent

parameter type Description
 keyId string  The quorum member keyId produced by createQuorumPrivateKey.

initAndShare return a promise which return an array of ShareKeys to add to the quorum Key.

Next, the quorum keyStore must do addQuorumMemberShares() for each shareKeysList produced by each administrator.

isModified()

Return true if the keyStore has been modified.

releaseAllKeysWithPassphrase(passphrase)

release all keys with the passphrase. Usefull at login for example to avoid the ask of the privateKey.

parameter type Description
 passphrase string the passphrase to give for release

return a promise.

savePrivateKeyLocaly(keyIdsToSave)

Set the private key int he localStorage.

parameter type Description
 keyIdsToSave [string] The list of keyIs to save localy

For example, you can create a new key and save it localy.

setContent(d, withDeviceKeyStore = true)

Set the keyStore content with a json object. Return a promise

getPublicKeyStoreFromStoragefunc must be a function to retreive public keyStores.

setName( name )

Each keystore as an Id related to the userId (and given at the declaration). It is recommanded to add a human esaly readable name.

At the end, The keyStore is modified and must be saved.

setPreferedKey(keyId)

If you want that everybody crypt only for this key.

parameter type Description
 keyId string My key Id.

At the end, The keyStore is modified and must be saved.

setPublicContent( content )

Set the keyStore content with a json object. It will contain only public keys Return a promise

signUserKey(userId, keyId = undefined)

Sign the user KeyStore (his public key keyId) with your signature key.

The keyStore will ask for passphrase if needed. return true of Ok (and the signature is added) or false if an error occured.

symCipher(id, data, outputFormat)

Symetric encryption with the AES key.

parameter type Description
 id string The session key Id to user
 data variable the data to crypt.
 encryptedFormat string the encrypted format. see symCrypt for available formats

data can be :

  • ArrayBuffer
  • json object
  • string

encryptedFormat can be :

  • raw
  • struct
  • hex
  • base64 (by default)

symDecipher(id, encrypted, inputFormat, outputFormat)

Symetric decryption with the AES key.

parameter type Description
 id string The session key Id to user
 encrypted variable the encrypted data
 inputFormat string the encrypted format. see symCrypt for available formats
 outputFormat string the encrypted format. see symCrypt for available formats

outputFormat can be :

  • string
  • raw

symGenerateKey(id, keyStore, keyIds)

Generate a random AES Key.

updateKeyStoreByMember(userId, keyStore)

Soon

preferedCryptKey = keyId

Set a prefered key for ciphering. In case of more than one available cipher key, you can choose the key to give to other people. otherwhise, they will crypt with all available keys.

You can see the keyStore list of keys with getInfos function.

At the end, The keyStore is modified and must be saved.

protectPrivateKeyWithPassphrase( keyId, passphrase )

Crypt the private key with an AES encryption.

parameter type Description
 keyId string the key Id to protect.
 passphrase string A passphrase.

At the end, The keyStore is modified and must be saved.

verifySignature(userId, keyId)

Verify the signature for a user and a keyId. return a promise which return true if the key is signed by you or by another person you trust.

The keyStore can ask for other public keyStores to find a trust path to the recipient userId. # Management API Reference

Introducing the Management API Reference

The lybcrypt keyStore is designed to be as most separate as possible from the application. All privates keys never get out of the keyStore for example. This separation is designed to work like a “HSM” in the browser, and will work in a separated worker or in a extension.

But for some task, the keyStore need to ask for assets to the application. Some functions must be provided to the keyStore for that. A uniq object is dedicated for that :

This part describe the management reference, see KeyStore Howto.

getApplicationTrustLevel()

see setApplicationTrustLevel()

getMaxAttempt()

see setMaxAttempt()

getTrustPathLength()

see setTrustPathLength()

startDebugOn(String)

Start the debug at the first debug message containing this String.

by default, without any settings, the debug function do a console.log().

setApplicationTrustLevel(TRUSTLEVEL)

Trustlevel is one protection against man in the middle attack. The question is to trust the recipient public key : Is it realy Bob behind the Bob’s public key in the app ?

The only way is web of trust or PKI (Public Key Infrastructure) : Bob’s public key is signed by someone you trust (you at the maximum).

The trustlevel describe keyStores behavior in case of untrusted public keys.

The application trustlevel can be set as followed :

The available levels are :

Level Numeric Description
TRUSTLEVEL.dontcare 0 Can crypt for everybody withoutknowledge about his public key.
TRUSTLEVEL.medium 1 If you don’t know anything about the recipient public key, ask the user for a confirmation to cipher for this person. In this case, the keystore propose to sign the recipient public key too.
TRUSTLEVEL.paranoid 2 If the recipient public key isn’t sign by you or somebody you trust, the cryptFor func will return an error

setDebug(Boolean)

Start or stop the debug.

setDebugFunc(Function)

You can provide the lybcrypt a debug function. This function is global and will be called by each keyStores.

by default, without any settings, the debug function do a console.log().

setErrorFunc(Function)

You can provide the lybcrypt an error function, called in case of error. This function is global and will be called by each keyStores in memory.

be default, without any settings, the error function do a console.error().

Warning The errorFunc given must return false.

setGetPublicKeyStores(Function)

This function is the way to a given keyStore to get anotther public keyStore (for ciphering) by example.

its scope is local to each keyStore and is given at the constructor

parameter type Description
 userIds Array of strings The list of wanted keyStores

This function must return a promise, which return a array of object ( keyStore public content ).

In this example, this is the minimal REST api to get keyStores from the database. Note : The server side is not describe in this example. Note : This function must probably do some tests and verifications.

The keyStore do some caching to not ask a lot of time the same keyStore.

This function is called when :

  • ciphering for someone (the recipient keyStore is needed). See cryptFor.
  • signing someone key. See signKey.
  • In quorum initialisation. See initAndShare.

Warning : Without this function, keyStores will not work correctly.

setInterface(Function)

This function manage the interface with the user when the keyStore need some choice or information by the user (like i need your passphrase)

By default, lybcrypt provide an html/javascript interface, but it will probably be not in agreement with you application. You can replace this function with your func.

Global structure

ASK.CRYPTKEYCHOICE

This is the choice for decyphering. In some case, data are encrypted with more than one key and ther is some choice. The user can chose : * A list of key (keyId) he want to use for deciphering (at least one) * Giving a passphrase for each of them (it can have different passphrase for each keys) * Giving a uniq passhrase to use with all selected keys.

Example in a console.log style, but you can do some angular, react, jquery or whatever you want !

Note In case of a quorum key, answer.globalPassphrase in not mandatory (there is no passphrase for quorum keys). It becomes the passphrase to enter on each device. So it is choosen by the user at this point.

ASK.SIGNKEYCHOICE

This is the choice when signing keys. If the user has more than one key, he must choose one or more, ang give passhrase(s). The user can chose : * A list of key (keyId) he want to use for sign (at least one) * Giving a passphrase for each of them (it can have different passphrase for each keys) * Giving a uniq passhrase to use with all selected keys.

Example in a console.log style, but you can do some angular, react, jquery or whatever you want !

ASK.QUORUMMEMBERDECRYPT

On the second (or third or more) device, during a quorum decryption, the device ask the user for comfirmation and a passphrase (if given at the ASK.CRYPTKEYCHOICE step).

ASK.CRYPTFORUNTRUST

If you want to cryptFor a untrusted user (ie a user with public keys not signed by you or by someone you trust), when the trustLevel of the application id TRUSTLEVEL.medium, the keyStore will ask confirmation for ciphering and ask if you want to sign this user public Key.

setLoadTempoSharesToStorage(Function)

When using device quorums, you need to have an exchange beetween devices for deciphering ShareKeys. This is the loading function for sharing ShareKeys.

setLogFunc(Function)

You can provide the lybcrypt a log function to get Logs of keyStore actions. This function is global and will be called by each keyStores in memory.

be default, without any settings, the log function do a console.log().

setMaxAttempt(Integer)

When a keyStore ask the user to enter a passphrase, it accepts this number of errors before returning an error.

The default value is 3.

setProgressFunc(Function)

when a keyStore is working ( ciphering, deciphering, doing any task), it can inform the application by sending an object (see progress object)

setSaveKeyStoreFunc(Function)

When a keyStore is modified (adding a key, changing some parameters, adding or removing a signature…) the keyStore is modified and must be saved. Give your function to save the keyStore.

setSaveKeyStoreFunc server side

On the server side (REST API), you can save keyStore as you save your application objects. Some rules can be apply for security :

  • Saving a keyStore must be authenticated.
  • A user can only save his own keyStore. Never save the keyStore of another user.
  • If you have a memberKey, you can only update the keyStore containing the quorumKey related to the memberKey.

setSaveTempoSharesToStorage(Function)

When using device quorums, you need to have an exchange beetween devices for deciphering ShareKeys. This is the saving function for sharing ShareKeys.

setTrustPathLength(Integer)

Lybcrypt work with a web of trust between users :

  • Bob has signed Alice’s public key
  • Alice has signed Charlie’s public key

In consequence, Bob can trust Alice’s publicKey with a path length of 2

Because we believe tha an infinite web of trust is not human representative, we can adjust the number of go-betweens.

The default value is 3.

setWithPassphraseManager(Boolean)

PassphraseManager is the ability to keep the global passphrase in memory for a laps of time.

The default value is true.

Crypto API Reference

Introduction

lybcrypt is a cryptographic library for symmetric, asymmetric and asymmetric with quorum encryption/decryption. It contains:

  • Symmetric cryptography
    • AES-128-CBC
    • AES-256-CBC

It can use both internal cryptographic routines (nodejs) and browser routines if available (windows.crypto). For asymmetric cryptography, windows.crypto is 6-7 times faster than nodesjs. But it becomes visible only when processing data over 10 kilobytes.

  • Hash
    • SHA-256
    • SHA-512
  • Password encryption
    • pbkdf2
  • Asymmetric signature
    • ECDSA signature P256 curve with SHA-256
    • ECDSA signature P256 curve with SHA-512
  • Asymmetric encryption
    • ElGamal encryption (modp5, modp14, modp15, modp16, modp17, modp18, modp22, modp23, modp24)
    • RSA_OAEP (Warning)

Hash

Hash produces a hashed string from a text, and allows to verify the hash value.

hash (string)

To hash a String :

verify (src, hashedString)

To verify a hash :

Password

Password is used for authentication.

pkpbf2 (string)

To register (change) a password for a user :

pkpbf2Verify (string, object)

To register (change) a password for a user :

SymCrypt

Input formats

Output format to cipher - input format to decipher

  • raw : The data is an object like
  • hex : The data is a string encoded as
  • base64 : The data is a string encoded as
  • struct : The data is an object like

Output format to decipher

  • raw : The data is Uint8Array
  • string : The data is a UTF8 string

generate()

To generate internally a symmetric key.

extract()

To extract a key :

wrapKeyFromPassphrase(string)

To derivate a AES key from a string ( typically a pass-phrase)

cipher(clearData, [outputFormat])

  • clearData=string|ArrayBuffer
  • outputFormat = please see Formats “base64”|“hex”|“raw”|“struct” (“base64” by default)

To cypher a buffer (Arraybuffer) or a String

decipher( encrypted, inputFormat, ouputFormat, [rawKey])

  • encrypted = encrypted data (string or struct)
  • inputFormat = “raw”|“hex”|“struct”|“base64” (by default) see Formats
  • ouputFormat = “string”|“raw”

To cypher a buffer (Arraybuffer) or a String

useWindowCrypto

  • By default True

You can avoid using windows.crypto by setting :

ElGamal

To use ElGamal :

generateKeys()

To generate Keys for a user :

cryptPrivateKeyWithPassphrase(passphrase)

  • passphrase is a String

To protect the private Key with a passphrase. Return a struct corresponding to a pkpbf2 symetric encryption with AES of the privateKey.

importKeys(encryptedPrivateKeyStruct, [publicKeyString] )

  • encryptedPrivateKeyStruct = struct produced by cryptPrivateKeyWithPassphrase
  • publicKeyString = String. The corresponding publicKey

Import keys

publicKeyString = String

Import a public key (but warning, this is not a promise)

releasePrivateKey(passphrase)

  • passphrase is a string

To release the privateKey from passphrase

genSessionKey()

Please better use :

combinedCrypt( string, recipientPublicKey )

To cypher a text (String) for someone:

combinedDecrypt( dataCrypt, dataKey, keylen, salt, iteration, hash)

To decypher a text : (suppose to have a private Key registered):

Example

This is example for ElGamal with symmetric encryption.

Combined cyphering

Combined decyphering

For compatibility with wrapKeyFromPassphrase

Quorum cryptography

This part is dedicated to quorum encryption / decryption. All examples will be done with 3 administrators and a quorum of 2.

Initialisation

A quorum group has members and a public key. An initialisation phase is necessary between the different quorum members. The quorum members must previously have ElGamal public and private keys. A quorum polynomial must be worked out for each member of the quorum.

Once the polynomial is initialised for each quorum group member, a common quorum public key is built by exchanging the public key part of each member of the group to the other members.

The equality of the quorumPublicKey between all the members of the quorum group has then to be tested. Each member of the quorum works out a specific secret shared string for each other member. These shared secret strings must be stored by the different members of the quorum.

Once these operations are done, the quorum group is initialised.

quorumInitPolynome(max, quorum)

  • max is the number of persons in the quorum group.
  • quorum is the number of persons necessary to allow the deciphering of an encrypted data.

quorumAddToPublicKey(aMemberPublicPartString)

  • aMemberPublicPartString is part of the ElGamal data of a user, and was added by the quorumInitPolynome function.

The output of the function is the property publicKeyString.

quorumGetAdminSecretShareString(quorumMemberIndex)

Each quorum member will work out a SecretShareString for each other member of the quorum group in using the index of this other member.

quorumAddToMySecret(secretSharedString)

The SecretShareString that was processed by the other member of a quorum group for the current member must be stored by this member.

Full initialisation sequence

Each administrator must initialise its polynomial and related values. Each administrator must have a different index. Here we initialise the administrator numbered 1 (var me=1). Then, we work out the SecretShareString for each other quorum group member, and we crypt it as well as the publicPart of the public key of the quorum group using the public key of the other quorum group member.

Once these values were created, they must be shared with the corresponding quorum group member:

Once this is done, the different quorum group members must create their local version of the quorum public key and verify that they have the same quorum group public key.

This is done in decrypting with their private key the values that were previously provided to them by the other members.

Encryption and decryption with the quorum group

As the quorum members share the public key of the quorum group, you just need the public key of any member to do the encryption.

An AES session key has to be generated. This session key is used to crypt the information, and is itself protected by the public key.

crypt(string)

To cypher for a quorum, it is similar to a standard combined cyphering activity. The public key (publicKey) generated during the quorum initialisation section.

quorumSurcryptAlpha

Now the quorum group can be used to decrypt the information. At least quorum members of the quorum group must proceed to a surcrypt of the encrypted information.

The different members of the quorum group will proceed to the partial decryption. That’s the aim of the function quorumSurcryptAlpha. They will share these partial decryption in a common structure.

quorumDecrypt

Once quorum surcryptAlpha have been done, it is possible to proceed to the final decryption of the AES key.

In this example, each admin (only 2 of them) does the following sequence (surcrypt the alpha)

Structures API Reference

getInfos Structure

This is the object returned by the function ( see keyStore.getInfos() )

getInfos devices

The devices sub structure is composed by a set of keyStores getInfos() structure (one per device). Keys are ids of devices.

getInfos keys

The keys sub structure is composed by a set of keys :

getInfos manager

getInfos signatures

Progress Object

This is the object given to the progressFuncion ( see management.setProgressFunc() )

SharedKeys

This is the structure of the SharedKeys object.

Each share is a Share object.

Share

key status

key types

key usages

Cryptography algorithms and quorums

Creating and encrypting datas

When encrypted data set by a user, the keyStore in the web browser generates an AES256 key randomly m.

The AES256 m key is then encrypted (ElGamal 2048, 4096 or 8192 depending on configuration) with the user’s public key creating the file repository and stored on the server. A random salt r is used.

m -> (α,β) = ((g^r mod(p), (Y^r .m)mod(p))

The browser sends to the server the data encoded by the ElGamal algorithm (α,β) . Your application must handle the unencrypted identification metadata (a repository / data set identifier number, including eventually a repository name if necessary; the description, the identifier, the login and the name of each user and quorum groups sharing the repository, the date of creation, the date of last modification and the identifier of the last person who modified the informations).

Decrypting

When a user accesses a data set, (α,β) are retrieved, then the key m is decrypted :

β / ( (α ^ S) mod(p) ) -> m

Algorithms associated with quorum groups

Preliminary note

The following calculations are largely inspired by the article: Distributed ElGamal à la Pedersen - Application to Helios par Véronique Cortier (CNRS/LORIA, France), David Galindo (CNRS/LORIA, France), Stéphane Glondu (INRIA Nancy Grand-Est, France) et Malika Izabachène (CNRS/LORIA, France) publié dans WPES 2013 - Proceedings of the 12th ACM workshop on privacy in the electronic society - 2013, Nov 2013, Berlin, Germany. ACM, pp.131-142, 2013.

Initialization of a quorum group

Step 0: creation of the quorum

A right to create a quorum group exists. At least the administrator of the site has this right.

Before using the quorum group, the following configuration parameters must be selected:

  • The name of the quorum group,
  • The list of secret administrators,
  • The quorum associated (the number of Secret Administrators required for recovery with this quorum group).

All these parameters are sent to the server.

Step 1: Generate bi-keys for each secret administrator

If the different administrators do not yet have an account and thus ElGamal bi-keys, they must create an account in order to have an ElGamal key.

Once all secret administrators in the quorum group have a dual key, initialization of the quorum group can continue.

Step 2: Exchange cryptographic parameters

When the secrets administrator n°rank is logging in, he retrieves the base information (identification number, login name, bi-key) and his rank rank in the quorum group.

Each administrator then generates a polynomial of degree quorum decreased by 1 in a discrete integer space.

A part of the public key of the quorum group is calculated by each member of the group. Each secrets administrator rank works out for each other administrator i a specific value using its polynom and the rank of the other administrator. He stores the associated data.

The list of values encrypted with the public key of the corresponding secrets administrator (of rank i) is stored.

Step 3: Generation of the public key of the quorum group

Once all values and are received by the server, the values are exchanged by the different secrets administrators. They work out the public key of the quorum group in decrypting with their private key the different and combining them.

The server provides this quorum group public key as soon as requested. When encryption is required for the quorum group, this public key is used as described above.

Recovery of a secret

Recovering a secret is done through a quorum of secret administrators operating independently of each other, but in the same configurable time window (for example 1 hour).

Step 0: Partial decryption of a secret administrator

The web browser of the secrets administrator of rank rank retrieves all information regarding the quorum group which are all public keys of the secrets administrators and all .

Thanks to its private key, it can decipher and get all provided by all administrators i. He can then compute the secret for the current secret administrator numbered rank.

Step 1: retrieval of the encrypted information

The secret administrator recovers all the information of the secret currently decrypted. This includes α.

Step 2: Over-Encryption

The rank rank administrator’s browser works out Crank as a polynom . It sends Crank to the server, encrypted for each administrator using the rank administrator’s public key. The server stores all enci(Crank). Each member of quorum waits for all these values. We note the set of administrators participating in the quorum τ and the set of indices corresponding to:

τ =[i1, …, iquorum] .

Once the quorum reached, the server returns to each quorum secrets administrator i who took part to the quorum, the values enci(Crank) (with τ ), and β the data encrypted with the session key m.

Step 3: Local decryption

The rank j administrator’s browser works out the session key m:

m is the session key needed to decrypt the encrypted data. Once decrypted the data can be made available to the secret administrator.

In the previous description, we considered that the person requesting a recovery is one of the secrets administrators. However, it can be a third party. In this case, β is encrypted with the public key of the person making the request, and the requester makes the final decryption (step 3 above). The secret administrators can’t decrypt the data.