Skip to content

Commit

Permalink
Merge key generation and encryption chapters
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasDorier committed May 30, 2016
1 parent df0f369 commit e81adbe
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 125 deletions.
12 changes: 8 additions & 4 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@
* [“The Blockchain is more than just Bitcoin”](bitcoin_transfer/the_blockchain_is_more_than_just_bitcoin.md)
* [Spend your coin](bitcoin_transfer/spend_your_coin.md)
* [Proof of ownership as an authentication method](bitcoin_transfer/proof_of_ownership_as_an_authentication_method.md)
* [Key storage and generation](key_storage_and_generation/README.md)
* [Is it random enough?](key_storage_and_generation/is_it_random_enough.md)
* [Key Encryption](key_storage_and_generation/key_encryption.md)
* [Key Generation](key_storage_and_generation/key_generation.md)
* [Key generation and encryption](key_generation/README.md)
* [Is it random enough?](key_generation/key_generation.md#is-it-random-enough)
* [Key Derivation Function](key_generation/key_generation.md#key-derivation-function)
* [Like the good ol’ days](key_generation/key_generation.md#like-the-good-ol-days)
* [BIP38 (Part 2)](key_generation/key_generation.md#bip38-part-2)
* [HD Wallet (BIP 32)](key_generation/key_generation.md#hd-wallet-bip-32)
* [Mnemonic Code for HD Keys (BIP39)](key_generation/key_generation.md#mnemonic-code-for-hd-keys-bip39)
* [Dark Wallet](key_generation/key_generation.md#dark-wallet)
* [Other types of ownership](other_types_of_ownership/README.md)
* [P2PK[H] (Pay to Public Key [Hash])](other_types_of_ownership/p2pk[h]_pay_to_public_key_[hash].md)
* [P2WPKH (Pay to Witness Public Key Hash)](other_types_of_ownership/p2wpkh_pay_to_witness_public_key_hash.md)
Expand Down
1 change: 1 addition & 0 deletions key_generation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Key generation and encryption {#key-generation-encryption}
Original file line number Diff line number Diff line change
@@ -1,6 +1,118 @@
## Key Generation {#key-generation}
## Is it random enough? {#is-it-random-enough}

### Like the good ol’ days {#like-the-good-ol-days}
When you call **new Key()**, under the hood, you are using a PRNG (Pseudo-Random-Number-Generator) to generate your private key. On windows, it uses the **RNGCryptoServiceProvider**, a .NET wrapper around the Windows Crypto API.

On Android, I use the **SecureRandom**, and in fact, you can use your own implementation with **RandomUtils.Random**.

On IOS, I have not implemented it and you need to create your **IRandom** implementation.

For a computer, being random is hard. But the biggest issue is that it is impossible to know if a serie of number is really random.

If a malware modifies your PRNG (and so, can predict the numbers you will generate), you won’t see it until it is too late.

It means that a cross platform and naïve implementation of PRNG (like using computer’s clock combined with CPU speed) is dangerous. But you won’t see it until it is too late.

For performance reason, most PRNG works the same way: a random number, called **Seed**, is chosen, then a predictable formula generates the next numbers each time you ask for it.

The amount of randomness of the seed is defined by a measure we call **Entropy**, but the amount of **Entropy** also depends on the observer.

Let’s say you generate a seed from your clock time.
And let’s imagine that your clock has 1ms of resolution. (Reality is more ~15ms)

If your attacker knows that you generated the key last week, then your seed has
1000 \* 60 \* 60 \* 24 \* 7 = 604800000 possibilities.

For such attacker, the entropy is LOG(604800000;2) = 29.17 bits.

And enumerating such number on my home computer took less than 2 seconds…We call such enumeration “brute forcing”.

However let’s say, you use the clock time + the process id for generating the seed.
Let’s imagine that there are 1024 different process ids.

So now, the attacker needs to enumerate 604800000 \* 1024 possibilities, which take around 2000 seconds.
Now, let’s add the time when I turned on my computer, assuming the attacker knows I turned it on today, it adds 86400000 possibilities.

Now the attacker needs to enumerate 604800000 \* 1024 \* 86400000 = 5,35088E+19 possibilities.
However, keep in mind that if the attacker infiltrate my computer, he can get this last piece of info, and bring down the number of possibilities, reducing entropy.

Entropy is measured by **LOG(possibilities;2)** and so LOG(5,35088E+19; 2) = 65 bits.

Is it enough? Probably. Assuming your attacker does not know more information about the realm of possibilities.

But since the hash of a public key is 20 bytes = 160 bits, it is smaller than the total universe of the addresses. You might do better.

> **Note:** Adding entropy is linearly harder, cracking entropy is exponentially harder
An interesting way of generating entropy quickly is by asking human intervention. (Moving the mouse.)

If you don’t trust completely the platform PRNG (which is [not so paranoic](http://android-developers.blogspot.fr/2013/08/some-securerandom-thoughts.html)), you can add entropy to the PRNG output that NBitcoin is using.

```cs
RandomUtils.AddEntropy("hello");
RandomUtils.AddEntropy(new byte[] { 1, 2, 3 });
var nsaProofKey = new Key();
```

What NBitcoin does when you call **AddEntropy(data)** is:
**additionalEntropy = SHA(SHA(data) ^ additionalEntropy)**

Then when you generate a new number:
**result = SHA(PRNG() ^ additionalEntropy)**

## Key Derivation Function {#key-derivation-function}

However, the most important is not the number of possibilities. It is the time that an attacker would need to successfully break your key. That’s where KDF enters the game.

KDF, or **Key Derivation Function** is a way to have a stronger key, even if your entropy is low.

Imagine that you want to generate a seed, and the attacker knows that there are 10.000.000 possibilities.
Such a seed would be normally cracked pretty easily.

But what if you could make the enumeration slower?
A KDF is a hash function that waste computing resources on purpose.
Here is an example:

```cs
var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 });
RandomUtils.AddEntropy(derived);
```

Even if your attacker knows that your source of entropy is 5 letters, he will need to run Scrypt to check a possibility, which take 5 seconds on my computer.

Bottom line of the story: There is nothing paranoid into distrusting a PRNG, you can mitigate an attack by both adding entropy and also using a KDF.
Keep in mind that an attacker can decrease entropy by gathering information about you or your system.
If you use the timestamp as entropy source, then he can decrease the entropy by knowing you generated the key last week, and that you only use your computer between 9am and 6pm.

In the previous part I talked quickly about a special KDF called **Scrypt.** As I said, the goal of a KDF is to make brute force costly.

So it should be no surprise for you that a standard already exists for encrypting your private key with a password using a KDF. This is [BIP38](http://www.codeproject.com/Articles/775226/NBitcoin-Cryptography-Part).

![](../assets/EncryptedKey.png)

```cs
var privateKey = new Key();
var bitcoinPrivateKey = privateKey.GetWif(Network.Main);
Console.WriteLine(bitcoinPrivateKey); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");
Console.WriteLine(encryptedBitcoinPrivateKey); // 6PYKYQQgx947Be41aHGypBhK6TA5Xhi9TdPBkatV3fHbbKrdDoBoXFCyLK
var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetSecret("password");
Console.WriteLine(decryptedBitcoinPrivateKey); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
Console.ReadLine();
```

Such encryption is used in two different cases:

* You don not trust your storage provider (they can get hacked)
* You are storing the key on the behalf of somebody else (and you do not want to know his key)

If you own your storage, then encrypting at the database level might be enough.

Be careful if your server takes care of decrypting the key, an attacker might attempt to DDOS your server by forcing it to decrypt lots of keys.

Delegate decryption to the ultimate user when you can.

## Like the good ol’ days {#like-the-good-ol-days}

First, why generating several keys?
The main reason is privacy. Since you can see the balance of all addresses, it is better to use a new address for each transaction.
Expand All @@ -20,7 +132,7 @@ However, you have two problems with that:

If you are developing a web wallet and generate key on behalf of your users, and one user get hacked, she will immediately start suspecting you.

### BIP38 (Part 2) {#bip38-part-2}
## BIP38 (Part 2) {#bip38-part-2}

We already saw BIP38 for encrypting a key, however this BIP is in reality two ideas in one document.

Expand Down Expand Up @@ -86,7 +198,7 @@ However, one problem remains:

BIP 32, or Hierarchical Deterministic Wallets (HD wallets) proposes another solution, and is more widely supported.

### HD Wallet (BIP 32) {#hd-wallet-bip-32}
## HD Wallet (BIP 32) {#hd-wallet-bip-32}

Let’s keep in mind the problems that we want to resolve:

Expand Down Expand Up @@ -283,7 +395,7 @@ KeyPath path = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
ExtKey paymentKey = ceoKey.Derive(path);
```

### Mnemonic Code for HD Keys (BIP39) {#mnemonic-code-for-hd-keys-bip39}
## Mnemonic Code for HD Keys (BIP39) {#mnemonic-code-for-hd-keys-bip39}

As you have seen, generating an HD keys is easy. However, what if we want as easy way to transmit such key by telephone or hand writing?

Expand Down Expand Up @@ -311,7 +423,7 @@ hdRoot = mnemo.DeriveExtKey("my password");

Currently supported **wordlist** are, English, Japanese, Spanish, Chinese (simplified and traditional).

### Dark Wallet {#dark-wallet}
## Dark Wallet {#dark-wallet}

This name is unfortunate since there is nothing dark about it, and it attract unwanted attention and worries.Dark Wallet is a practical solution that fix our two initial problems:

Expand Down
1 change: 0 additions & 1 deletion key_storage_and_generation/README.md

This file was deleted.

84 changes: 0 additions & 84 deletions key_storage_and_generation/is_it_random_enough.md

This file was deleted.

30 changes: 0 additions & 30 deletions key_storage_and_generation/key_encryption.md

This file was deleted.

0 comments on commit e81adbe

Please sign in to comment.