lnd.xprv/aezeed/errors.go

37 lines
1.2 KiB
Go
Raw Normal View History

aezeed: add new package implementing the aezeed cipher seed scheme In this commit, we add a new package implementing the aezeed cipher seed scheme. This is a new scheme developed that aims to overcome the two major short comings of BIP39: a lack of a version, and a lack of a wallet birthday. A lack a version means that wallets may not necessarily know *how* to re-derive addresses during the recovery process. A lack of a birthday means that wallets don’t know how far back to look in the chain to ensure that they derive *all* the proper user addresses. The aezeed scheme addresses these two drawbacks and adds a number of desirable features. First, we start with the following plaintext seed: {1 byte internal version || 2 byte timestamp || 16 bytes of entropy}. The version field is for wallets to be able to know *how* to re-derive the keys of the wallet. The 2 byte timestamp is expressed in Bitcoin Days Genesis, meaning that the number of days since the timestamp in Bitcoin’s genesis block. This allow us to save space, and also avoid using a wasteful level of granularity. With the currently, this can express time up until 2188. Finally, the entropy is raw entropy that should be used to derive wallet’s HD root. Next, we’ll take the plaintext seed described above and encipher it to procure a final cipher text. We’ll then take this cipher text (the CipherSeed) and encode that using a 24-word mnemonic. The enciphering process takes a user defined passphrase. If no passphrase is provided, then the string “aezeed” will be used. To encipher a plaintext seed (19 bytes) to arrive at an enciphered cipher seed (33 bytes), we apply the following operations: * First we take the external version an append it to our buffer. The external version describes *how* we encipher. For the first version (version 0), we’ll use scrypt(n=32768, r=8, p=1) and aezeed. * Next, we’ll use scrypt (with the version 9 params) to generate a strong key for encryption. We’ll generate a 32-byte key using 5 bytes as a salt. The usage of the salt is meant to make the creation of rainbow tables infeasible. * Next, the enciphering process. We use aezeed, modern AEAD with nonce-misuse resistance properties. The important trait we exploit is that it’s an *arbitrary input length block cipher*. Additionally, it has what’s essentially a configurable MAC size. In our scheme we’ll use a value of 4, which acts as a 32-bit checksum. We’ll encrypt with our generated seed, and use an AD of (version || salt). We'll them compute a checksum over all the data, using crc-32, appending the result to the end. * Finally, we’ll encode this 33-byte cipher text using the default world list of BIP 39 to produce 24 english words. The `aezeed` cipher seed scheme has a few cool properties, notably: * The mnemonic itself is a cipher text, meaning leaving it in plaintext is advisable if the user also set a passphrase. This is in contrast to BIP 39 where the mnemonic alone (without a passphrase) may be sufficient to steal funds. * A cipherseed can be modified to *change* the passphrase. This means that if the users wants a stronger passphrase, they can decipher (with the old passphrase), then encipher (with a new passphrase). Compared to BIP 39, where if the users used a passphrase, since the mapping is one way, they can’t change the passphrase of their existing HD key chain. * A cipher seed can be *upgraded*. Since we have an external version, offline tools can be provided to decipher using the old params, and encipher using the new params. In the future if we change ciphers, change scrypt, or just the parameters of scrypt, then users can easily upgrade their seed with an offline tool. * We're able to verify that a user has input the incorrect passphrase, and that the user has input the incorrect mnemonic independently.
2018-02-23 04:12:41 +03:00
package aezeed
import "fmt"
var (
// ErrIncorrectVersion is returned if a seed bares a mismatched
// external version to that of the package executing the aezeed scheme.
ErrIncorrectVersion = fmt.Errorf("wrong seed version")
// ErrInvalidPass is returned if the user enters an invalid passphrase
// for a particular enciphered mnemonic.
ErrInvalidPass = fmt.Errorf("invalid passphrase")
// ErrIncorrectMnemonic is returned if we detect that the checksum of
// the specified mnemonic doesn't match. This indicates the user input
// the wrong mnemonic.
ErrIncorrectMnemonic = fmt.Errorf("mnemonic phrase checksum doesn't " +
aezeed: add new package implementing the aezeed cipher seed scheme In this commit, we add a new package implementing the aezeed cipher seed scheme. This is a new scheme developed that aims to overcome the two major short comings of BIP39: a lack of a version, and a lack of a wallet birthday. A lack a version means that wallets may not necessarily know *how* to re-derive addresses during the recovery process. A lack of a birthday means that wallets don’t know how far back to look in the chain to ensure that they derive *all* the proper user addresses. The aezeed scheme addresses these two drawbacks and adds a number of desirable features. First, we start with the following plaintext seed: {1 byte internal version || 2 byte timestamp || 16 bytes of entropy}. The version field is for wallets to be able to know *how* to re-derive the keys of the wallet. The 2 byte timestamp is expressed in Bitcoin Days Genesis, meaning that the number of days since the timestamp in Bitcoin’s genesis block. This allow us to save space, and also avoid using a wasteful level of granularity. With the currently, this can express time up until 2188. Finally, the entropy is raw entropy that should be used to derive wallet’s HD root. Next, we’ll take the plaintext seed described above and encipher it to procure a final cipher text. We’ll then take this cipher text (the CipherSeed) and encode that using a 24-word mnemonic. The enciphering process takes a user defined passphrase. If no passphrase is provided, then the string “aezeed” will be used. To encipher a plaintext seed (19 bytes) to arrive at an enciphered cipher seed (33 bytes), we apply the following operations: * First we take the external version an append it to our buffer. The external version describes *how* we encipher. For the first version (version 0), we’ll use scrypt(n=32768, r=8, p=1) and aezeed. * Next, we’ll use scrypt (with the version 9 params) to generate a strong key for encryption. We’ll generate a 32-byte key using 5 bytes as a salt. The usage of the salt is meant to make the creation of rainbow tables infeasible. * Next, the enciphering process. We use aezeed, modern AEAD with nonce-misuse resistance properties. The important trait we exploit is that it’s an *arbitrary input length block cipher*. Additionally, it has what’s essentially a configurable MAC size. In our scheme we’ll use a value of 4, which acts as a 32-bit checksum. We’ll encrypt with our generated seed, and use an AD of (version || salt). We'll them compute a checksum over all the data, using crc-32, appending the result to the end. * Finally, we’ll encode this 33-byte cipher text using the default world list of BIP 39 to produce 24 english words. The `aezeed` cipher seed scheme has a few cool properties, notably: * The mnemonic itself is a cipher text, meaning leaving it in plaintext is advisable if the user also set a passphrase. This is in contrast to BIP 39 where the mnemonic alone (without a passphrase) may be sufficient to steal funds. * A cipherseed can be modified to *change* the passphrase. This means that if the users wants a stronger passphrase, they can decipher (with the old passphrase), then encipher (with a new passphrase). Compared to BIP 39, where if the users used a passphrase, since the mapping is one way, they can’t change the passphrase of their existing HD key chain. * A cipher seed can be *upgraded*. Since we have an external version, offline tools can be provided to decipher using the old params, and encipher using the new params. In the future if we change ciphers, change scrypt, or just the parameters of scrypt, then users can easily upgrade their seed with an offline tool. * We're able to verify that a user has input the incorrect passphrase, and that the user has input the incorrect mnemonic independently.
2018-02-23 04:12:41 +03:00
"match")
)
// ErrUnknownMnenomicWord is returned when attempting to decipher and
// enciphered mnemonic, but a word encountered isn't a member of our word list.
type ErrUnknownMnenomicWord struct {
// Word is the unknown word in the mnemonic phrase.
Word string
// Index is the index (starting from zero) within the slice of strings
// that makes up the mnemonic that points to the incorrect word.
Index uint8
aezeed: add new package implementing the aezeed cipher seed scheme In this commit, we add a new package implementing the aezeed cipher seed scheme. This is a new scheme developed that aims to overcome the two major short comings of BIP39: a lack of a version, and a lack of a wallet birthday. A lack a version means that wallets may not necessarily know *how* to re-derive addresses during the recovery process. A lack of a birthday means that wallets don’t know how far back to look in the chain to ensure that they derive *all* the proper user addresses. The aezeed scheme addresses these two drawbacks and adds a number of desirable features. First, we start with the following plaintext seed: {1 byte internal version || 2 byte timestamp || 16 bytes of entropy}. The version field is for wallets to be able to know *how* to re-derive the keys of the wallet. The 2 byte timestamp is expressed in Bitcoin Days Genesis, meaning that the number of days since the timestamp in Bitcoin’s genesis block. This allow us to save space, and also avoid using a wasteful level of granularity. With the currently, this can express time up until 2188. Finally, the entropy is raw entropy that should be used to derive wallet’s HD root. Next, we’ll take the plaintext seed described above and encipher it to procure a final cipher text. We’ll then take this cipher text (the CipherSeed) and encode that using a 24-word mnemonic. The enciphering process takes a user defined passphrase. If no passphrase is provided, then the string “aezeed” will be used. To encipher a plaintext seed (19 bytes) to arrive at an enciphered cipher seed (33 bytes), we apply the following operations: * First we take the external version an append it to our buffer. The external version describes *how* we encipher. For the first version (version 0), we’ll use scrypt(n=32768, r=8, p=1) and aezeed. * Next, we’ll use scrypt (with the version 9 params) to generate a strong key for encryption. We’ll generate a 32-byte key using 5 bytes as a salt. The usage of the salt is meant to make the creation of rainbow tables infeasible. * Next, the enciphering process. We use aezeed, modern AEAD with nonce-misuse resistance properties. The important trait we exploit is that it’s an *arbitrary input length block cipher*. Additionally, it has what’s essentially a configurable MAC size. In our scheme we’ll use a value of 4, which acts as a 32-bit checksum. We’ll encrypt with our generated seed, and use an AD of (version || salt). We'll them compute a checksum over all the data, using crc-32, appending the result to the end. * Finally, we’ll encode this 33-byte cipher text using the default world list of BIP 39 to produce 24 english words. The `aezeed` cipher seed scheme has a few cool properties, notably: * The mnemonic itself is a cipher text, meaning leaving it in plaintext is advisable if the user also set a passphrase. This is in contrast to BIP 39 where the mnemonic alone (without a passphrase) may be sufficient to steal funds. * A cipherseed can be modified to *change* the passphrase. This means that if the users wants a stronger passphrase, they can decipher (with the old passphrase), then encipher (with a new passphrase). Compared to BIP 39, where if the users used a passphrase, since the mapping is one way, they can’t change the passphrase of their existing HD key chain. * A cipher seed can be *upgraded*. Since we have an external version, offline tools can be provided to decipher using the old params, and encipher using the new params. In the future if we change ciphers, change scrypt, or just the parameters of scrypt, then users can easily upgrade their seed with an offline tool. * We're able to verify that a user has input the incorrect passphrase, and that the user has input the incorrect mnemonic independently.
2018-02-23 04:12:41 +03:00
}
// Error returns a human readable string describing the error.
func (e ErrUnknownMnenomicWord) Error() string {
return fmt.Sprintf("word %v isn't a part of default word list "+
"(index=%v)", e.Word, e.Index)
aezeed: add new package implementing the aezeed cipher seed scheme In this commit, we add a new package implementing the aezeed cipher seed scheme. This is a new scheme developed that aims to overcome the two major short comings of BIP39: a lack of a version, and a lack of a wallet birthday. A lack a version means that wallets may not necessarily know *how* to re-derive addresses during the recovery process. A lack of a birthday means that wallets don’t know how far back to look in the chain to ensure that they derive *all* the proper user addresses. The aezeed scheme addresses these two drawbacks and adds a number of desirable features. First, we start with the following plaintext seed: {1 byte internal version || 2 byte timestamp || 16 bytes of entropy}. The version field is for wallets to be able to know *how* to re-derive the keys of the wallet. The 2 byte timestamp is expressed in Bitcoin Days Genesis, meaning that the number of days since the timestamp in Bitcoin’s genesis block. This allow us to save space, and also avoid using a wasteful level of granularity. With the currently, this can express time up until 2188. Finally, the entropy is raw entropy that should be used to derive wallet’s HD root. Next, we’ll take the plaintext seed described above and encipher it to procure a final cipher text. We’ll then take this cipher text (the CipherSeed) and encode that using a 24-word mnemonic. The enciphering process takes a user defined passphrase. If no passphrase is provided, then the string “aezeed” will be used. To encipher a plaintext seed (19 bytes) to arrive at an enciphered cipher seed (33 bytes), we apply the following operations: * First we take the external version an append it to our buffer. The external version describes *how* we encipher. For the first version (version 0), we’ll use scrypt(n=32768, r=8, p=1) and aezeed. * Next, we’ll use scrypt (with the version 9 params) to generate a strong key for encryption. We’ll generate a 32-byte key using 5 bytes as a salt. The usage of the salt is meant to make the creation of rainbow tables infeasible. * Next, the enciphering process. We use aezeed, modern AEAD with nonce-misuse resistance properties. The important trait we exploit is that it’s an *arbitrary input length block cipher*. Additionally, it has what’s essentially a configurable MAC size. In our scheme we’ll use a value of 4, which acts as a 32-bit checksum. We’ll encrypt with our generated seed, and use an AD of (version || salt). We'll them compute a checksum over all the data, using crc-32, appending the result to the end. * Finally, we’ll encode this 33-byte cipher text using the default world list of BIP 39 to produce 24 english words. The `aezeed` cipher seed scheme has a few cool properties, notably: * The mnemonic itself is a cipher text, meaning leaving it in plaintext is advisable if the user also set a passphrase. This is in contrast to BIP 39 where the mnemonic alone (without a passphrase) may be sufficient to steal funds. * A cipherseed can be modified to *change* the passphrase. This means that if the users wants a stronger passphrase, they can decipher (with the old passphrase), then encipher (with a new passphrase). Compared to BIP 39, where if the users used a passphrase, since the mapping is one way, they can’t change the passphrase of their existing HD key chain. * A cipher seed can be *upgraded*. Since we have an external version, offline tools can be provided to decipher using the old params, and encipher using the new params. In the future if we change ciphers, change scrypt, or just the parameters of scrypt, then users can easily upgrade their seed with an offline tool. * We're able to verify that a user has input the incorrect passphrase, and that the user has input the incorrect mnemonic independently.
2018-02-23 04:12:41 +03:00
}