Skip to content

Latest commit

 

History

History
346 lines (262 loc) · 13.8 KB

README.md

File metadata and controls

346 lines (262 loc) · 13.8 KB

Fuzzy Encryption for Secret Recovery

WARNING: This code relies on copyleft dependencies which may require special attention to use safely within commercial products. Please be take care to ensure you are abiding by the license terms specified in these dependencies.

Fuzzy Encryption for Secret Recovery project is an approach to provide an alternative for unmemorable user-controlled cryptographic keys composed of secret long strings of random numbers and letters. Our project presents a scheme where a user is expected to remember/securely protect a pass-phrase alone, regardless of ordering. This pass-phrase is used to generate cryptographic key material that is used to generate as well as recover cryptographic key(s). Any state information generated by the scheme in order to generate the cryptographic key material from the pass-phrase can be stored in any public repository.

Table of Contents


Introduction

The Fuzzy Vault Key Recovery System allows you to create a virtual vault of cryptographic keys. This vault has a combination consisting of a set of words that are to be randomly selected from a known set (corpus). To recover the keys the user must supply that combination (set of words) to the recovery system. The recovery words can be in any order and they may contain a limited set of errors defined by the system. In this way the user can recover the keys with some allowable errors.

This distribution contains a C++ and a Python implementation of the Fuzzy Vault key recovery scheme. The Python version is included as a demonstration to help understand the C++ implementation. The Python version not intended for general use. The C++ code is intended for general use.

We include two sample applications, demo and loadrand. Demo demonstrates the creation of a secret and then recovery of keys with a different number of errors in the recovery words. This sample application demonstrates that if the number of errors in the recovery words is less than a well defined limit then the keys can be recovered but if there are too many errors then the recovery fails. Loadrand is nearly identical to demo except for the fact that loadrand uses random numbers supplied by the application. This allows the secret generation to bypass the random number generator supplied by the operating system or cryptographic libraries. Loadrand uses what is equivalent to a one-time pad encryption scheme.

C++

This section describes how to build the Fuzzy Vault C++ libraries and how to use them in practice.

Building C++ libraries and examples

There are 3 targets of the the C++ build process: Linux, WASM and Android. These build both the Fuzzy Vault shared libraries, some demonstration examples, and runs one of the examples to verify the build. The build is simple using the supplied scripts.

Building Linux

  cd ./src/scripts/linux
  sudo ./build.sh

Building WASM

The Web Assembly does not have a convenient way of generating random numbers so in this cases it is necessary to include the randomBytes key value pair in the input. To this end the WASM build uses the loadrand test to verify that the build succeeded.

  cd ./src/scripts/android
  sudo ./build.sh

Building Android

  cd ./src/scripts/android
  sudo ./build.sh 23 <Debug|Release>

FuzzyVault APIs

This section describes how to create a C++ application that uses the Fuzzy Vault libraries. This section explains the example in ./src/c++/tests/demo and ./src/c++/tests/loadrand.

Exception handling is manditory

These APIs throw exceptions rather than return an error code. Exceptions will be thrown if the JSON inputs are not correct. Your code should have the following form

  #include "fuzzy.h"
  try {
    call some FuzzyVault APIs
  }
  except (NoSolutionException)  {
    handle this gracefully -- usually user error (eg. wrong recovery words)
    which can happen
  }
  except (exception& e) {
    this is bad perhaps by something nonsensical like negative corpus size
    Check that the input makes sense and tell the user the problem
  }
  except (...) {
    this is really bad probably want to bail
  }

See the sample code for guidance.

The three functions

The libraries (libfuzzyvault.*) expose only three functions:

These are defined in ./src/c++/fuzzyvault/fuzzy.h. Each of these functions use C++-JSON strings for both input and output. We have

gen_params

generates the parameters of the vault in JSON format which is to be passed to gen_keys. It is expected that the architect of the key recovery process defines these parameters one time and then uses them for all clients.

  std::string fuzzy_vault::gen_params(const std::string& input);

gen_params input

a JSON string representing a dictionary of the in one of the two following forms

gen_params normal input

{
    "setSize" : 12,
    "correctThreshold" : 9,
    "corpusSize" : 7776
}

gen_params random input

This input option is provided for use in WASM due to lack of access to random number generation.

{
    "setSize" : 12,
    "correctThreshold" : 9,
    "corpusSize" : 7776,
    "randomBytes": [
      "3218C8B6681167BC81BBCA7523FE...E089FA0E2E04",
      "E9DA670216EBDA73F1626012E645...B4C314729D29",
      "C765880C27EC4EED06155B85C43D...F0B3E2E1EFBE"
    ]
}

gen_params input key value pairs

The input json string will contain 3 or 4 key value pairs which are described here.

setSize

setSize is the number of words that must be selected from the corpus. This is equal to the number of words that are supplied at the time of the call to gen_keys.

correctThreshold

correctThreshold is the minimum number of words that need to be correct to successfully recover the keys.

corpusSize

corpusSize is the number of unique words in the set that the recovery words are chosen from

randomBytes

randomBytes is an optional key value pair. If this field is present then the strings of upper-cases hexadecimal characters define random numbers to be used during the generation of the parameters. Each two consecutive characters in each string represents a bytes. Each string must contain an even number of characters. The number of bytes represented must be greater than or equal to 4 * (setSize + 8). This parameter is normally missing.

gen_params output

The return value of gen_secret is a string containing a JSON dictionary of the following form.

{
  "setSize": 12,
  "correctThreshold": 9,
  "corpusSize": 7776,
  "prime": 7789,
  "extractor": [ 1223, 81, 1257, 2529, 2115,  ... 5130, 416 ],
  "salt": "CF339C756CFAA7715018C8FFF97343454  ... 94DABBC8D36"
}

gen_secret

takes the parameters generated by a previous call to gen_params as input and returns a secret in the form of a JSON string that will be passed into gen_keys at a later time.

std::string fuzzy_vault::gen_secret(
  const std::string& params,
  const std::string& words
  );
}

gen_secret arguments

params

params is a JSON string returned by gen_params

words

words is a JSON string representing a list of setSize unique integers in the range 0 .. corpusSize - 1 as specified in params. The words JSON string looks like

{ 78, 2643, 1178, ... }

gen_secret output

The gen_secret call outputs a string containing the secret which has the following form

{
  "setSize": 12,
  "correctThreshold": 9,
  "corpusSize": 7776,
  "prime": 7789,
  "extractor": [ 1223, 81, 1257, 2529, ...  5130, 416 ],
  "salt": "CF339C756CFAA7715018C8FFF97343 ... DABBC8D36",
  "sketch": [ 967, 5576, 1719, 6542, 2717, 7711 ],
  "hash": "73E8AB1883CB093F1C546D69DC87EC0FE658 ... FA975745"
}

It is up to the application to store the secret and guaranteed that it will not be modified. The secret will be one of the arguments

gen_keys

std::string fuzzy_vault::gen_keys(
  const std::string& secret,
  const std::string& recovery_words,
  int key_count
);

Generates a list of keys

To generate keys the caller must supply a set words (integers) meets the minimum threshold for matching words specified in gen_secret. This means that the input words must be unique, the number of words must be equal to setSize, every word must be greater than or equal to zero and less than corpusSize and the number of words matching the original set must be greater that or equal to correctThreshold. If all of these conditions are met then a list of keys of size key_count is returned to the user in the form of a JSON string.

All calls to this function will return the same sequence of keys.

gen_keys arguments

secret

A JSON string returned by gen_secret.

recovery_words

a list of unique integers. These integers represent a guess of the original words passed into gen_secret.

key_count

key_count a positive integer specifying the number of keys to be returned

gen_keys output

A JSON string representing a list of recovered keys. The returned string has the form

[
    "B4263013BC29B964F6FB62FEB7119 ... ACBDC55A8C24A4ED78185936E76C8CD",
    "23568650436339CCA498D396D9EFD ... BB4B1CD2D97D869A3745080E323D62F",
    "E4CCD887D50179DD4B0BB57E95010 ... 4A35C1AA2B4C606B82C319C8A1D9B61",
    "6FEABCC8DDD8FA6557C7D096FA612 ... 1419E5EE7F0ED739CA9FA4E03393E44",
    "B075330F188F8C1795B715165B67F ... D11FC1B2D206D2E29D99EE3A020B150"
]

Each key is represented as a large hexadecimal string all upper case. Each string is a representation of an array of bytes. Each bytes is represented by two consecutive hexadecimal characters, the lowest byte starting at the left. A byte is as represented by two characters in the 'obvious' way. For example '08' represents a byte value of 8. Typically the keys represent 512 bits or 64 bytes so they each have a length of 128 characters.