Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

complete bounty#5 #98

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
all: gnoland gnokey goscan logos
all: gnoland gnokey goscan logos gnokeybk

.PHONY: logos goscan gnoland gnokey logos reset test test1 test2 testrealm testrealm1 testrealm2 testpackages testpkgs

Expand All @@ -18,6 +18,10 @@ gnoland:
gnokey:
echo "Building gnokey"
go build -o build/gnokey ./cmd/gnokey
# Key tool
gnokeybk:
echo "Building gnokeybk"
go build -o build/gnokeybk ./cmd/gnokeybk

# goscan scans go code to determine its AST
goscan:
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@

# Bounty5

Problem Definition

https://github.com/gnolang/bounties/issues/15

Solution

https://github.com/piux2/gnobounty5/blob/master/bounty5solution.md

Instruction

https://github.com/piux2/gnobounty5/blob/master/bounty5instruction.md

# Gno

At first, there was Bitcoin, out of entropy soup of the greater All.
Expand All @@ -17,7 +32,7 @@ simulated by the Gnomes of the Greater Resistance.
* Completely deterministic, for complete accountability.
* Transactional persistence across data realms.
* Designed for concurrent blockchain smart contracts systems.

## Status

_Update Aug 26th, 2021: SDK/store,baseapp ported; Plan updated_
Expand All @@ -42,7 +57,7 @@ This is a still a work in a progress, though much of the structure of the interp
and AST have taken place. Work is ongoing now to demonstrate the Realm concept before
continuing to make the tests/files/\*.go tests pass.

Make sure you have >=[go1.15](https://golang.org/doc/install) installed, and then try this:
Make sure you have >=[go1.15](https://golang.org/doc/install) installed, and then try this:

```bash
> git clone git@github.com:gnolang/gno.git
Expand Down
180 changes: 180 additions & 0 deletions bounty5instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@


## Install

git clone https://github.com/piux2/gnobounty5

cd gnobounty5

make all

My code is based on

The codebase committed on Dec 9, 2021
https://github.com/gnolang/gno/tree/5a1ea776cac472a42e3b0ecf4d32ebc1ede289f9


## Testing data

#### Primary Key:

name: test1

mnemonic:

source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast

passphrase: test 1

generated address and pubkey

test1 (local) - addr: g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5
pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pq0skzdkmzu0r9h6gny6eg8c9dc303xrrudee6z4he4y7cs5rnjwmyf40yaj

#### Backup Key

name: test1

mnemonic:

curious syrup memory cabbage razor emotion ketchup best alley cotton enjoy nature furnace shallow donor oval tornado razor clock roof pave enroll solar wrist

generated multisig address and pubkey

test1 (backup local- multisig address) - addr: g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv
multisig pub:
[0]gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pq0skzdkmzu0r9h6gny6eg8c9dc303xrrudee6z4he4y7cs5rnjwmyf40yaj
[1]gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zp7xtkykvttvcxnz9n74hfd8t4tav3t7l33p5trvyeuxd3ea8d95vhp767p


## Instructions

#### Start from here if you have not created primary key yet, otherwise skip to the next step
Note: Enter words within < >. Do not enter brackets

./build/gnokeybk add test1 --recover
Enter a passphrase to encrypt your key to disk: <test1>

Enter your bip39 mnemonic
<source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast>

test1 (local) - addr: g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pq0skzdkmzu0r9h6gny6eg8c9dc303xrrudee6z4he4y7cs5rnjwmyf40yaj, path: <nil>


#### Start from here if you have created primary key yet.
Back up your primary key to a seperate backup keybase

./build/gnokeybk bkkey test1
Enter a passphrase to encrypt your key to disk: <test1>

Enter your backup bip39 mnemonic, which should be different from you primary mnemonic, or hit enter to generate a new one
<curious syrup memory cabbage razor emotion ketchup best alley cotton enjoy nature furnace shallow donor oval tornado razor clock roof pave enroll solar wrist>

Backup key is created for primary key address
g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5

Backup key's multisig address is
g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv

### check and list primary key and backup key. both share the same name

./build/gnokeybk listbk

Keybase primary
0. test1 (local) - addr: g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pq0skzdkmzu0r9h6gny6eg8c9dc303xrrudee6z4he4y7cs5rnjwmyf40yaj, path: <nil>


---------------------------
Keybase backup
0. test1 (local) - addr: g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pq0skzdkmzu0r9h6gny6eg8c9dc303xrrudee6z4he4y7cs5rnjwmyf40yaj | gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zp7xtkykvttvcxnz9n74hfd8t4tav3t7l33p5trvyeuxd3ea8d95vhp767p | , path: <nil>



### Sign transactions with the backup key

Launch the gnoland chain in a separate terminal

./build/gnoland

Check both keys are available on-chain. these are preconfigured accounts in genesis.
In the real case, you will have to send the token to your backup key address, which is a multisig address.

Before you sign and broadcasted messages. these two accounts on chain do not have pub keys published on the chain yet.

./build/gnokeybk query "auth/accounts/g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"

height: 0
data: {
"BaseAccount": {
"address": "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5",
"coins": "1000000gnot",
"public_key": null,
"account_number": "0",
"sequence": "0"
}
}

./build/gnokeybk query "auth/accounts/g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv"

height: 0
data: {
"BaseAccount": {
"address": "g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv",
"coins": "1000000gnot",
"public_key": null,
"account_number": "1",
"sequence": "0"
}
}



Now let's use the backup key to sign and broadcast the signed transaction
This transaction is created by test1 following the examples in https://github.com/gnolang/gno/tree/master/examples/gno.land/r/boards

Let's sign it with the backup key. The account number is set in genesis. We need to increment sequence number each time we sign a transaction. The signer's address will be replaced by the backup key multisig address.

./build/gnokeybk signbk test1 --txpath addpkg.avl.unsigned.json --chainid "testchain" --number 1 --sequence 0 > addpkg.avl.signed.json

Enter password.
<test1>

### broadcast transactions

./build/gnokeybk broadcast addpkg.avl.signed.json

$ OK!

The transaction is successfully broadcasted and accepted by the chain.

We query the backup key account on chain. The multisig pub key is published.


.build/gnokeybk query "auth/accounts/g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv"

height: 0
data: {
"BaseAccount": {
"address": "g16ptpek560p53qdmeja7vm2crc0gpgtqyzfuthv",
"coins": "999898gnot",
"public_key": {
"@type": "/tm.PubKeyMultisig",
"threshold": "2",
"pubkeys": [
{
"@type": "/tm.PubKeySecp256k1",
"value": "A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"
},
{
"@type": "/tm.PubKeyEd25519",
"value": "+MuxLMWtmDTEWfq3S066r6yK/fjENFjYTPDNjnp2low="
}
]
},
"account_number": "1",
"sequence": "1"
}
}


DONE!
125 changes: 125 additions & 0 deletions bounty5solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
## Problem Definition

here is the problem definition

https://github.com/gnolang/bounties/issues/15


## Solution Breakdown


>Defend against hacking issues that may arise from hardware wallet providers.

hardware wallet provider may not use a RAND number to generate mnemonic. The attacker could use each number in a pre-existing sequence and a counter stored on devices to generate mnemonics that look random but is not. For example, use pre-existing sequence in Pi, Prime number, or even block hash in the major blockchain.

> Defend against potential weaknesses in the Secp256k1 algorithm. For example, Satoshi's "2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1" constant is potentially flawed.

we can use the ed25519 algorithm to create a backup key and store it in a separate key base.

> Defend against potential weaknesses in bip32's HMAC-SHA512 function. SHA256 is somewhat economically tested by the Bitcoin hashing algorithm and mining incentives, so the goal here is to provide an alternative that relies primarily on sha256.


> Defend against potential weaknesses in bip39's PBKDF2 function (which also relies on HMAC-SHA512). For example, the PBKDF2 function may have a limited range of outputs, which limits the private keyspace.

We can use a real hkdf with an extract-then-expand scheme.
https://en.wikipedia.org/wiki/HKDF

It is standardized in RFC5869 by Internet Engineering Task Force.

https://datatracker.ietf.org/doc/html/rfc5869

The primitive is implemented in golang.
https://pkg.go.dev/golang.org/x/crypto/hkdf


>Continue to allow the usage of hardware signing devices, and bip32/39 and secp256k1 algorithms for day-to-day usage.

Create a 2/2 multi-sig combined from primary key and backup key
Use a single command to sign transactions with a 2/2 multi-sig. No need to sign a transaction twice and no need to combine two signatures to gather.


## Implementation explained.

This bounty#5 implementation uses the following priorities to resolve conflicts

Security > Useability > Simple implementation

I extended gnokey to gnokeybk which is backward compatible

#### bkkey sub command:

it generates a backup key:

- Create a backup key using a mnemonic generate on an air gap computer
- Use ed25519 and HKDF to generate a backup key
- Store the backup key in a separate key base file. It provides additional security. We can even move the backup key store from the air-gap computer to a USB stick after we complete the signing task.

- The backup key info is multi-sig info. It contains ed25519 key and multisig pubkeys that combine primary pubkey and backup pubkey. Since the attacking point for multi-sig is at the time of combining two keys, we need to make sure only the person holding the primary key can create this backup key info. This is very IMPORTANT.

- This implementation introduces a primary key signature in backup key info. It uses the primary key to sign the backup info including name, ed25519 privkey armor, and combined multisig pubkeys. The signature and the primary pubkey are used to prove that the backup info is created by the primary key holder. If the backup key store is altered, it will give errors




#### listbk sub command:

It lists the primary key and backup key from two different key stores.

#### sign sub command:
It retrieves the primary key and backup key from Keystore sign the transaction, combine signatures in one transaction with multisig pubkeys. During the process, it also verifies the backup key integrity stored in the backup key store.

#### changes in the forked code base.

To minimize the impact to the code base before the implementation is reviewed. I wrote all the relevant files in gno/pkgs/crypto/keys/backup_keybase.go and gno/cmd/gnokeybk/
once we review it and approve the implementation. these codes can be merged back to the existing framework.

There are two additional minor updates on the forked code base.
Registered infoBk package
github.com/gnolang/gno/pkgs/package.go


Added backup key multisig address in genesis state
github.com/gnolang/gno/cmd/gnoland/main.go


## Discussions.
> I propose that we allow for the registration of an alternative key based on ed25519 as a backup key that is not used but can be used in case of emergencies when issues arise with the default bip32/39/sec256k1 keys.


This part is tricky since on-chain verification needs to decide if it requires verifying two signatures or just one. Maybe we can force users to use the backup key (two signatures)to sign contracts once it is generated and registered on the Chain. To transfer funds, we may not need to be strict and allow the use of either primary key( one signature) or backup key (a multisig with two signatures)

> Tooling should be provided to allow this alternative backup key to be generated on an air-gapped computer, without the aid of a specialized crypto signing device.

Agree, done

> The (primary) mnemonic for the secp256k1 key must be separate from the (secondary) mnemonic for the ed25519 key, because hardware crypto signers ask for the mnemonic to set up the device, and the second mnemonic should only be entered on air-gapped general computers.

Agree, done

> In Gno, instead of relying on the memo field, we can add a "RegisterAccount" sdk.Msg to provide the backup ed25519 pubkey-hash, and furthermore, we can require the user to register their account w/ backup key before actually using their secp256k1 keys. This way, users can just use a hardware wallet to generate a secp256k1 address to receive funds but are incentivized to register a ed25519 pubkey.

Suggest to store backup multisig key address in registeredAccount

> In the case of issues with the bip32/39/secp256k1 system, the gno.land chain can fork and just use the ed25519 key. Users who have not yet registered an ed25519 backup key would either end up losing their tokens, or possibly the tokens would have to be distributed with real-world KYC etc to catch the hacker who may be trying to reclaim them on the gno.land fork -- this assuming that we come up with a reasonable way to protect the privacy of users while also keeping the recovery accountable. Users who register their account with a backup key would not be affected, and if there are no issues with bip32/39/secp256k1, none of this matters.

With existing implementation and force using the backup once it is generated, we do not need to fork the chain even we know the primary keys are compromised.


> 24-words -> standard kdf & hd derivation -> secp256k1 address
> 24-words (different) -> sha256-based-kdf -> ed25519 address

Agree, done.

> And finally, the gnokey command should be updated to make all of this easier. I like the approach taken by #11 and #14; there just needs to be another gnokey subcommand that bundles these two together (and explains everything, and requires different mnemonics) and produces an unsigned msg for account registration on gno, as well as MEMO-based airdrop-registration on cosmos.

Agree, users can recover the cosmos key on gnoland first and then generate a backup key. The generated backup key address can be stored in "RegisterAccount" sdk.Msg and broadcast to the chain. This way chain can key a record of who generated backup.

## Assumptions, Limitations, and Further Discussions

When the attack happens we probably do not know in advance. We will only discover it after the primary key is distributed and used widely.


For security reasons, no backup key should be altered or recreated. Since the bad guy can create a backup key as well and submit registration transactions to the chain. There is no way to prevent it on Chain. So we are under the assumption that users create backup keys before bad guys take the action


Due above open issues and assumptions, when a backup key is recognized on the chain, the chain should only accept the tx signed by backup key multisig
Loading