2019-12-26 19:12:08 -06:00
---
id: key-manager
title: Key Manager
---
### Key Manager
2020-12-16 17:27:56 -06:00
The key manager module's goal is to encapsulate all private key interactions with the [wallet ](../wallet/wallet.md ) project.
2019-12-26 19:12:08 -06:00
2020-08-27 14:11:24 -05:00
As of this writing, there is only one type of `KeyManager` - [`BIP39KeyManager` ](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager ).
2019-12-27 10:09:04 -06:00
2020-08-27 14:11:24 -05:00
The [`BIP39KeyManager` ](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager ) stores a [`MnemonicCode` ](/api/org/bitcoins/core/crypto/MnemonicCode ) on disk which can be decrypted and used as a hot wallet.
2019-12-27 10:09:04 -06:00
Over the long run, we want to make it so that the wallet project needs to communicate with the key-manager to access private keys.
2019-12-26 19:12:08 -06:00
This means that ALL SIGNING should be done inside of the key-manager, and private keys should not leave the key manager.
This makes it easier to reason about the security characteristics of our private keys, and a way to provide a uniform interface for alternative key storage systems (hsm, cloud based key storage, etc) to be plugged into the bitcoin-s library.
#### Creating a key manager
The first thing you need create a key manager is some entropy.
2020-08-27 14:11:24 -05:00
A popular way for bitcoin wallet's to represent entropy is [BIP39 ](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki ) which you [can use in bitcoin-s ](/api/org/bitcoins/core/crypto/BIP39Seed )
2019-12-26 19:12:08 -06:00
You can generate a `MnemonicCode` in bitcoin-s with the following code
2020-03-10 12:49:22 -05:00
```scala mdoc:to-string
2019-12-26 19:12:08 -06:00
import org.bitcoins.core.crypto._
//get 256 bits of random entropy
val entropy = MnemonicCode.getEntropy256Bits
val mnemonic = MnemonicCode.fromEntropy(entropy)
//you can print that mnemonic seed with this
println(mnemonic.words)
```
Now that we have a `MnemonicCode` that was securely generated, we need to now create `KeyManagerParams` which tells us how to generate
generate specific kinds of addresses for wallets.
`KeyManagerParams` takes 3 parameters:
1. `seedPath` there is where we store the `MnemonicCode` on your file system
2020-08-27 14:11:24 -05:00
2. [`purpose` ](/api/org/bitcoins/core/hd/HDPurpose ) which represents what type of utxo this `KeyManager` is associated with. The specification for this is in [BIP43 ](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki )
3. [`network` ](/api/org/bitcoins/core/config/NetworkParameters ) what cryptocurrency network this key manager is associated with
2019-12-26 19:12:08 -06:00
2020-03-10 12:49:22 -05:00
This controls how the root key is defined. The combination of `purpose` and `network` determine how the root `ExtKey` is serialized. For more information on how this works please see [hd-keys ](../core/hd-keys.md )
2019-12-26 19:12:08 -06:00
Now we can construct a native segwit key manager for the regtest network!
2020-03-10 12:49:22 -05:00
```scala mdoc:invisible
2020-04-29 09:49:41 -05:00
import java.time.Instant
2020-11-06 07:00:18 -06:00
import org.bitcoins.crypto._
2019-12-26 19:12:08 -06:00
import org.bitcoins.core.crypto._
import org.bitcoins.core.config._
import org.bitcoins.core.hd._
import org.bitcoins.keymanager._
2019-12-27 10:09:04 -06:00
import org.bitcoins.keymanager.bip39._
2020-08-21 14:37:12 -05:00
import org.bitcoins.core.wallet.keymanagement._
2019-12-26 19:12:08 -06:00
import java.nio.file._
2020-03-10 12:49:22 -05:00
```
```scala mdoc:to-string
2019-12-26 19:12:08 -06:00
//this will create a temp directory with the prefix 'key-manager-example` that will
//have a file in it called "encrypted-bitcoin-s-seed.json"
val seedPath = Files.createTempDirectory("key-manager-example").resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME)
//let's create a native segwit key manager
val purpose = HDPurposes.SegWit
//let's choose regtest as our network
val network = RegTest
val kmParams = KeyManagerParams(seedPath, purpose, network)
2020-11-06 07:00:18 -06:00
val aesPasswordOpt = Some(AesPassword.fromString("password"))
val km = BIP39KeyManager.initializeWithMnemonic(aesPasswordOpt, mnemonic, None, kmParams)
2019-12-26 19:12:08 -06:00
val rootXPub = km.right.get.getRootXPub
println(rootXPub)
```
Which should print something that looks like this
`vpub5SLqN2bLY4WeXxMqwJHJFBEwxSscGB2uDUnsTS3edVjZEwTrQDFDNqoR2xLqARQPabGaXsHSTenTRcqm2EnB9MpuC4vSk3LqSgNmGGZtuq7`
which is a native segwit `ExtPubKey` for the regtest network!
You can always change the `network` or `purpose` to support different things. You do _not_ need to initialize the key manager
again after initializing it once. You can use the same `mnemonic` for different networks, which you control `KeyManagerParams` .
2020-03-10 12:49:22 -05:00
```scala mdoc:to-string
2019-12-26 19:12:08 -06:00
//let's create a nested segwit key manager for mainnet
val mainnetKmParams = KeyManagerParams(seedPath, HDPurposes.SegWit, MainNet)
//we do not need to all `initializeWithMnemonic()` again as we have saved the seed to dis
2020-12-17 13:25:04 -06:00
val mainnetKeyManager = BIP39KeyManager.fromMnemonic(mnemonic, mainnetKmParams, None, Instant.now)
2019-12-26 19:12:08 -06:00
val mainnetXpub = mainnetKeyManager.getRootXPub
println(mainnetXpub)
```
Which gives us something that looks like this
`zpub6jftahH18ngZw98KGjRo5XcxeKTQ2eztsvskb1dC9XF5TLimQquTs6Ry7nBBA425D9joXmfgJJCexmJ1u2SELJZJfRi95gcnXadLpZzYb5c`
which is a p2sh wrapped segwit `ExtPubKey` for the bitcoin main network!
#### Creating a key manager from existing mnemonic
To create a `KeyManager` from existing mnemonic you need to specify the `seedPath` and then construct the `KeyManagerParams` that you would like.
Finally you call `KeyManager.fromParams()` that reads the mnemonic from disk and create's the key manager