Skip to content

Latest commit

 

History

History
263 lines (193 loc) · 8.58 KB

README.md

File metadata and controls

263 lines (193 loc) · 8.58 KB

MSecret — Experimental Key Derivation Utility

crates.io Build Status Documentation dependency status MSRV


This project includes both:

  1. A specification (with test vectors) for deterministically deriving various types of data (bytes, integers, primes, etc.) and cryptographic keys (RSA, ECC, etc.) from a symmetric master secret.
  2. A reference implementation written in Rust, including a helpful command-line utility and library.

⚠️ WARNINGS ⚠️

Use this project at your own risk. As with anything experimental and cryptographic, there are some caveats to understand before using this project:

⚠️ BEHAVIOR SUBJECT TO CHANGE ⚠️

The MSecret specification and the included reference implementation should be considered EXPERIMENTAL AND SUBJECT TO CHANGE until the specification is declared final. Any changes to the derivation specification will change the output of the resulting keys. Also, any mistakes in the implementation of the specification may also lead to incorrect results.

If you need to ensure that any keys you derive from the included reference tool will always derive to the same key in later revisions, you should avoid using this software until the specification and test vectors are finalized.

⚠️ NOT AUDITED ⚠️

Neither the reference source code nor the test vectors have been audited for correctness.

⚠️ SIDE-CHANNEL ATTACKS ⚠️

The reference source code has not been hardened against side-channel attacks.

How it works

In MSecret, secrets are defined to be 256-bits long. The MSecret specification defines methods for how various types of cryptographic keys (RSA, EC, etc) and other values (integers, pseudo-random byte strings, etc.) can be deterministically derived from a 256-bit secret.

In addition to deriving cryptographic keys and other values, also defined is a way to derive other 256-bit secrets from a "label". These derivations may be chained together to form a "keypath", allowing for a hierarchical structure of derived keys. This allows for complex forms of domain separation.

Defined Pseudo-random Derivations

  1. Other 256-bit symmetric secrets, via a label/keypath
  2. Byte strings of arbitrary length
  3. Integers with a maximum value
  4. Prime numbers of a given bit length
  5. RSA public/private keys of a given bit length
  6. ECC public/private keys for arbitrary curves, including Ed25519 and X25519
  7. Various styles of passwords
  8. Bitcoin addresses and associated private keys

Secret Management

Secrets can be generated randomly or derived from a passphrase using argon2id. Secrets can also be split up into an arbitrary number of "shares", from which a subset can be used to recover the secret (m-of-n secret sharing).

Keypaths

Keypaths are strings of labels separated by slashes ("/"), making them appear like the path in a file system: i.e. "/A/1/CA/com.example/2023-06-23". The key derivations are performed hierarchically, so that the secret at the path "/A/1" could be exported and later used to derive the secret at "CA/com.example/2023-06-23".

Chains of the same label are supported via a special notation. The following keypaths are all equivalent:

  • /x/x/x/x
  • /x@4
  • /x/x@3
  • /x@2/x@2

Command-Line Tool

To install the command-line tool msecretctl, first make sure that your rust development environment is installed and up-to-date. To install from scratch, read the instructions here. To update an existing installation, use rustup:

$ rustup update

Then you can grab the latest version of msecretctl:

$ cargo install msecret

You should now be able to use the msecretctl tool.

Usage Example

The included reference implementation includes a command-line utility called msecretctl which can be used to derive various secrets. It has an interactive mode which can be entered by simply running it.

Here is an example of using the tool to generate a new root secret and split it into 5 shares (where any three could reconstruct it):

$ cargo build --release
$ target/release/msecretctl

> secret generate
Created XvvjqeUihQncbhsVQBtToB

/> secret share 3 5
ARhqDQyLeN1K92xHxYkWhVHbGRsjLdduhPDPT6L2FsroNfT
ErtgQEvsXKA9TgYRnjqE2s4NFhwbPd4e5YVwDU3X6cCDoZ9
NvBfSVbkqmN37jxa8689S8htmPXnxaqvdH13FkaDLaAdWb3
Sf1GNofy4vvij3Z4uziDuxuc54ZSGiwY9MQ9fJQcWdkLSEi
aL1RKsJPN9ZsSPhifiJGz5PSB35HRTy7kNitYYHw8LAEUHA

We then go on to derive two private keys for X.509 certificates:

/> cd /A/1/CA/com.example/2023-06-23

/A/1/CA/com.example/2023-06-23> ecc private prime256v1
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP9sNI1FKOOT0Pm56bpbXAP/aQiCu+nlXus1OcZYlt4xoAoGCCqGSM49
AwEHoUQDQgAE1YGpnNePZH5u6apTZpUP7/9W1xaJ8x5JNxqPxyh8gf6B2xStFB7q
UIVkSB54IZGHuuQKkYwfCjT69zDGVRwt7A==
-----END EC PRIVATE KEY-----

/A/1/CA/com.example/2023-06-23> cd ../../net.example.com/2023-06-23

/A/1/CA/net.example/2022-00-21> ecc private prime256v1
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBDh1+5kobZT/IuuLx3KyLsaFqSF7WDVAC91/Ih9LzpeoAoGCCqGSM49
AwEHoUQDQgAEU3lNhlWMkmVN6MEbWFIbCRH9uE4I5bxt+WSHn/vUpk9weJ/LJ4vt
q9Wc+L1K/7QKbkJ2T0S+0PsNfQWWN2aDog==
-----END EC PRIVATE KEY-----

/A/1/CA/net.example/2022-00-21> exit

$

If we need to recover these private keys later, we can use any three of the above shares to recover the key:

$ target/release/msecretctl

> secret recover
Enter Share: Sf1GNofy4vvij3Z4uziDuxuc54ZSGiwY9MQ9fJQcWdkLSEi
Enter Share: ARhqDQyLeN1K92xHxYkWhVHbGRsjLdduhPDPT6L2FsroNfT
Enter Share: NvBfSVbkqmN37jxa8689S8htmPXnxaqvdH13FkaDLaAdWb3
Enter Share:
Imported XvvjqeUihQncbhsVQBtToB

/> cd /A/1/CA/com.example/2023-06-23

/A/1/CA/com.example/2023-06-23> ecc private prime256v1
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP9sNI1FKOOT0Pm56bpbXAP/aQiCu+nlXus1OcZYlt4xoAoGCCqGSM49
AwEHoUQDQgAE1YGpnNePZH5u6apTZpUP7/9W1xaJ8x5JNxqPxyh8gf6B2xStFB7q
UIVkSB54IZGHuuQKkYwfCjT69zDGVRwt7A==
-----END EC PRIVATE KEY-----

/A/1/CA/com.example/2023-06-23>

You could also export/share just the key at /A/1...

/A/1/CA/com.example/2023-06-23> cd /A/1

/A/1> secret id
EhK8TqdqrJ6xBaxEYx2mmb

/A/1> secret share 2 3 -f words
light-conan-flame--valid-input-poncho--bronze-falcon-jacob--piano-frame-popular--ticket-sharp-smoke--burger-status-father--cobra-ship-marion--water-shake-alien--except-private-fax
saint-queen-video--elite-martin-amber--canal-ferrari-jamaica--escape-soprano-dinner--honey-food-infant--paper-george-jumbo--cotton-vision-madonna--radio-rodent-episode--rainbow-citizen-ego
sonata-tropic-mask--voice-edgar-cool--cotton-reptile-alien--meaning-carol-common--dynasty-joker-bamboo--poker-educate-random--lion-nova-demand--smile-escort-kilo--basket-ocean-fax

/A/1> q

$

...and then derive the ECC keys from that:

$ target/release/msecretctl

> secret recover
Enter Share: sonata-tropic-mask--voice-edgar-cool--cotton-reptile-alien--meaning-carol-common--dynasty-joker-bamboo--poker-educate-random--lion-nova-demand--smile-escort-kilo--basket-ocean-fax
Enter Share: light-conan-flame--valid-input-poncho--bronze-falcon-jacob--piano-frame-popular--ticket-sharp-smoke--burger-status-father--cobra-ship-marion--water-shake-alien--except-private-fax
Enter Share:
Imported EhK8TqdqrJ6xBaxEYx2mmb

/> cd CA/com.example/2023-06-23

/CA/com.example/2023-06-23> ecc private prime256v1
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP9sNI1FKOOT0Pm56bpbXAP/aQiCu+nlXus1OcZYlt4xoAoGCCqGSM49
AwEHoUQDQgAE1YGpnNePZH5u6apTZpUP7/9W1xaJ8x5JNxqPxyh8gf6B2xStFB7q
UIVkSB54IZGHuuQKkYwfCjT69zDGVRwt7A==
-----END EC PRIVATE KEY-----

/CA/com.example/2023-06-23>

Future Work

  • Finalize specification
  • Smart card support with permissions
  • Keypath maps
  • Additional asymmetric key formats

License

Apache 2.0; see LICENSE for details.