/ethereum-keys-sgx

An ethereum key pair generator & transaction signer/sender using Intel SGX & Rust.

Primary LanguageRustMIT LicenseMIT

A Pure Rust Implementation of an Elliptic Curve Keypair Generator in an Intel SGX Enclave

✒️ Notes:

More specifically, an Secp256k1 key-pair generator & message/transaction signer where both the enclave and the app are written in pure Rust. Made possible by the fantastic Rust SGX Software Developer Kit by Baidux Labs: https://github.com/baidu/rust-sgx-sdk

Update #4: Now with a branch that can import private keys! (See the import-secret branch...)

Update #3: Now with full transaction sending capabilities!

Update #2: Now with full transaction-signing capabilities!

Update #1: Now with replay-attack protection!

 

📃 CLI Usage:

    Intel SGX Ethereum Key Management CLI.
        Questions: greg@oraclize.it

    Usage:  ethkey_sgx                                              [-h | --help]
    
            ethkey_sgx generate                                     [--keyfile=<path>]

            ethkey_sgx show public                                  [--keyfile=<path>]

            ethkey_sgx show secret                                  [--keyfile=<path>]

            ethkey_sgx show address                                 [--keyfile=<path>] 

            ethkey_sgx destroy                                      [--keyfile=<path>]

            ethkey_sgx show nonce                                   [--keyfile=<path>] [--chainid=<uint>] 

            ethkey_sgx sign msg <message>                           [--keyfile=<path>] [-n | --noprefix]

            ethkey_sgx verify <address> <message> <signature>       [--keyfile=<path>] [-n | --noprefix]

            ethkey_sgx sendtx      [--to=<address>] [--value=<Wei>] [--keyfile=<path>] [--gaslimit=<uint>]
                                   [--gasprice=<Wei>] [--nonce=<uint>] [--data=<string>] [--chainid=<uint>]
                                   
            ethkey_sgx sign tx     [--to=<address>] [--value=<Wei>] [--keyfile=<path>] [--gaslimit=<uint>]
                                   [--gasprice=<Wei>] [--nonce=<uint>] [--data=<string>] [--chainid=<uint>]

    Commands:

        generate            ❍ Generates an secp256k1 keypair inside an SGX enclave, encrypts
                            them & saves to disk as either ./encrypted_keypair.txt in the
                            current directory, or at the passed in path.

        show secret         ❍ Log the private key from the given encrypted keypair to the console.

        show nonce          ❍ Retrieves the current nonce of the keypair in a given keyfile, for
                            the network specified via the chain ID parameter:
                                1  = Ethereum Main-Net (default)
                                3  = Ropsten Test-Net
                                4  = Rinkeby Test-Net
                                42 = Kovan Test-Net

        sign tx             ❍ Signs a transaction with the given parameters and returns the raw 
                            data ready for broadcasting to the ethereum network. If no nonce is
                            supplied, the tool will attempt to discover the nonce of the given
                            keypair for the network the transaction is destined for. See below
                            for the parameter defaults.

        sendtx              ❍ Signs a transaction per the above instructions, then sends the 
                            transaction to an Infura node for broadcasting to the chosen network.
                            Returns the transactions hash if successful.

        sign msg            ❍ Signs a passed in message using key pair provided, otherwise uses
                            default keypair if it exists. Defaults to using the ethereum message
                            prefix and ∴ signatures are ECRecoverable.

       verify               ❍ Verify a given address signed a given message with a given signature. 

       destroy              ❍ Destroys a given key file's monotonic counters, rendering the keyfile
                            unusable, before erasing the encrypted keyfile itself. Use with caution!

    Options:

        -h, --help          ❍ Show this usage message.

        --keyfile=<path>    ❍ Path to desired encrypted keyfile [default: ./encrypted_keypair]

        --to=<address>      ❍ Destination address of transaction [default: ]

        --value=<Wei>       ❍ Amount of ether to send with transaction in Wei [default: 0]

        --gaslimit=<uint>   ❍ Amount of gas to send with transaction [default: 210000]

        --gasprice=<Wei>    ❍ Gas price for transaction in Wei [default: 20000000000]

        --chainid=<uint>    ❍ ID of desired chain for transaction [default: 1]

        --nonce=<uint>      ❍ Nonce of transaction in Wei [default:  -1]

        --data=<string>     ❍ Additional data to send with transaction [default:  ]

        -n, --noprefix      ❍ Does not add the ethereum message prefix when signing or verifying 
                            a signed message. Messages signed with no prefix are NOT ECRecoverable!

 

🔧 Build it Yourself:

❍ Pull requisite files:

Pull the Rust SGX SDK Docker image

❍ sgx-nuc@~$ docker pull baiduxlab/sgx-rust

Clone this Repo

❍ sgx-nuc@~$ git clone https://gitlab.com/gskapka/secp256k1-enclave-rust.git

 

❍ Prepare the Docker Container:

If using SIMULATION mode:

❍ sgx-nuc@~$ sudo docker run -v /path/to/secp256k1-enclave-rust:/root/keygen -ti baiduxlab/sgx-rust

Else if using HARDWARE mode:

❍ sgx-nuc@~$ sudo docker run -v/path/to/secp256k1-enclave-rust:/root/keygen -ti --device /dev/isgx baiduxlab/sgx-rust

Rebuild the tool chain:

❍ sgx-nuc-docker@~# rustup default nightly-2018-10-01-x86_64-unknown-linux-gnu

Add required components:

❍ sgx-nuc-docker@~# rustup component add rust-src

Finally, if using HARDWARE mode, import the service:_

❍ sgx-nuc-docker@~# /opt/intel/libsgx-enclave-common/aesm/aesm_service &

 

❍ Prepare the keygen:

In the ❍ sgx-nuc-docker@~/keygen directory inside the docker, first ensure the desired mode (SW or HW) is set correctly inside the Makefile:

    // ... Beginning of file ...

    ######## SGX SDK Settings ########

    SGX_SDK ?= /opt/intel/sgxsdk
    SGX_MODE ?= HW                // <-- This option. HW for Hardware or SW for software.
    SGX_ARCH ?= x64

    // ... Remainder of file ...

Next, set the environment variable inside the docker to the desired mode:

❍ sgx-nuc-docker@~/keygen# export SGX_MODE=HW

Then build the project:

❍ sgx-nuc-docker@~/keygen# make

And finally run it to see the usage notes:

❍ sgx-nuc-docker@~/keygen# cd bin && ./ethkey_sgx

 

📋 To Do List:

✅ Refactor to lib crate.

✅ Make CLI with Docopt.

🔲 Remotely attest!

🔲 Save key files as their corresponding address names!

🔲 Add more tests!

✅ Make ECRecoverable sigs.

🔲 Stream to the enc. to allow file encryption.

🔲 Add rudimentary password protection.

🔲 Use mister enclave instead of mister signer!

🔲 Make threaded to have vanity addresses (can limit tried?)

✅ Abstract out generic enclave funcs (mem. allocing etc)

✅ Separate the app from the SDK repo enclave to make it lean and mean.

✅ Add transaction signing.

🔲 Make a stand alone binary for D/L.

🔲 Make a getter for enclave measurement.

🔲 Remove show public since it's useless.

🔲 Remove ability to show private key for prod. usage.

🔲 Make a nonce getter.

✅ Add a monotonic counter to the key accesses.

✅ Add a monotonic counter to tx signing events.

✅ Add SGX time checks to stop replay attacks.

 

📚 Resources:

Here's some stuff about the EDL file

Here's some stuff about the Makefile syntax: