Peel the comparison to the original see Code 10: How to create a key by/create-key interface

Source: Internet
Author: User
Tags ed25519

Author: freewind

Compared to the original project warehouse:

GitHub Address: Https://github.com/Bytom/bytom

Gitee Address: Https://gitee.com/BytomBlockc ...

In the previous article, we explored how the key, account alias, and password were uploaded from the front end to the backend when registering from the browser's dashboard. In this article, we'll look at how it will be created when the request to create the key is received in the background than the original.

As this article is more specific, so there is no need to subdivide, we start directly from the code.

Remember in the previous article, what is the configuration of the function point for the Web API that created the key?

In the API.buildHandler method:

api/api.go#l164-l244

func (a *API) buildHandler() {    // ...    if a.wallet != nil {        // ...        m.Handle("/create-key", jsonHandler(a.pseudohsmCreateKey))        // ...

Visible, its path is /create-key , and the corresponding handler is a.pseudohsmCreateKey (outside the cover jsonHandler has been discussed before, here does not mention):

Api/hsm.go#l23-l32

func (a *API) pseudohsmCreateKey(ctx context.Context, in struct {    Alias string `json:"alias"`    Password string `json:"password"`}) Response {    xpub, err := a.wallet.Hsm.XCreate(in.Alias, in.Password)    if err != nil {        return NewErrorResponse(err)    }    return NewSuccessResponse(xpub)}

It's mostly called a.wallet.Hsm.XCreate , let's go in:

Blockchain/pseudohsm/pseudohsm.go#l50-l66

// XCreate produces a new random xprv and stores it in the db.func (h *HSM) XCreate(alias string, auth string) (*XPub, error) {    // ...    // 1.    normalizedAlias := strings.ToLower(strings.TrimSpace(alias))    // 2.    if ok := h.cache.hasAlias(normalizedAlias); ok {        return nil, ErrDuplicateKeyAlias    }    // 3.    xpub, _, err := h.createChainKDKey(auth, normalizedAlias, false)    if err != nil {        return nil, err    }    // 4.    h.cache.add(*xpub)    return xpub, err}

The word appears, HSM it means Hardware-Security-Module that the original is also reserved for hardware-related modules (not discussed).

The above code is divided into 4 parts, namely:

    1. First, standardize the incoming alias parameters, that is, go blank on both sides, and convert to lowercase
    2. Check that cache there is no, some words will be directly returned and reported a corresponding error, will not be repeated generation, because the private key and alias is one by one corresponding. The front end can be used to alert users to check or change a new alias based on this error.
    3. Called createChainKDKey to generate the corresponding key and get the returned public keyxpub
    4. Put the public key into the cache. It seems that the public key and the alias are not the same thing, so why is it possible to query alias before?

So let's go h.cache.hasAlias look at:

Blockchain/pseudohsm/keycache.go#l76-l84

func (kc *keyCache) hasAlias(alias string) bool {    xpubs := kc.keys()    for _, xpub := range xpubs {        if xpub.Alias == alias {            return true        }    }    return false}

xpub.Aliasas we can see, the original alias is bound to the public key and can be thought of as alias a property of the public key (and, of course, the corresponding private key). So the public key is placed in the cache before the alias can be queried.

So how does the 3rd step generate the key? createChainKDKey

Blockchain/pseudohsm/pseudohsm.go#l68-l86

func (h *HSM) createChainKDKey(auth string, alias string, get bool) (*XPub, bool, error) {    // 1.    xprv, xpub, err := chainkd.NewXKeys(nil)    if err != nil {        return nil, false, err    }    // 2.    id := uuid.NewRandom()    key := &XKey{        ID: id,        KeyType: "bytom_kd",        XPub: xpub,        XPrv: xprv,        Alias: alias,    }    // 3.    file := h.keyStore.JoinPath(keyFileName(key.ID.String()))    if err := h.keyStore.StoreKey(file, key, auth); err != nil {        return nil, false, errors.Wrap(err, "storing keys")    }    // 4.    return &XPub{XPub: xpub, Alias: alias, File: file}, true, nil}

This code is quite clear, we can divide it into 4 steps, namely:

    1. Invokes the chainkd.NewXKeys generate key. It chainkd corresponds to another package in the original code base, "crypto/ed25519/chainkd" and from the name, the algorithm is used ed25519 . If you have an impression that the previous article "How to connect to a previous node", you will remember that the algorithm generates a pair of keys that are used to encrypt the communication when the connection is connected. However, it is important to note that although both are ed25519 algorithms, the last code used was from a third-party library "github.com/tendermint/go-crypto" . It is different from the details of this algorithm, it is not clear, left to the appropriate opportunity to study. Then there is the incoming chainkd.NewXKeys(nil) parameter, which corresponds to the nil "random number generator". If nil so, NewXKeys random numbers are generated internally using the default random number generator and the key is generated. The relevant content of the key algorithm is not discussed in this paper.
    2. Generates a unique ID for the current key, which is later used to generate the file name, saved on the hard disk. The ID uses the UUID, which generates a 62bc9340-f6a7-4d16-86f0-4be61920a06e globally unique random number that is shaped like this.
    3. Save the key as a file on your hard disk. This piece of content is more, detailed below.
    4. The public key-related information is combined for use by the caller.

Let's talk about the 3rd step in detail and save the key as a file. The first is to generate the file name, keyFileName the corresponding code of the function is as follows:

Blockchain/pseudohsm/key.go#l96-l101

// keyFileName implements the naming convention for keyfiles:// UTC--<created_at UTC ISO8601>-<address hex>func keyFileName(keyAlias string) string {    ts := time.Now().UTC()    return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), keyAlias)}

Note that the parameters here should actually be the UUID that was keyAlias keyID generated earlier. Written alias somewhat misleading, has been submitted to pr#922. The last generated file name, such as:UTC--2018-05-07T06-20-46.270917000Z--62bc9340-f6a7-4d16-86f0-4be61920a06e

After the file name is generated, h.keyStore.JoinPath it is placed in the appropriate directory. Generally speaking, this directory is the native data directory keystore , if you are the OSX system, it should be in your ~/Library/Bytom/keystore , if anything else, you can use the following code to determine Defaultdatadir ()

About the above to save the key file directory, exactly how to determine, in the code is actually a bit around. But if you are interested in this, I believe you should be able to find it yourself, this is not listed here. If you can't find it, try the following keywords:,, pseudohsm.New(config.KeysDir()) , os.ExpandEnv(config.DefaultDataDir()) DefaultDataDir()DefaultBaseConfig()

At the end of the 3rd step, the method is called to keyStore.StoreKey save it as a file. The method code is as follows:

blockchain/pseudohsm/keystore_passphrase.go#l67-l73

func (ks keyStorePassphrase) StoreKey(filename string, key *XKey, auth string) error {    keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)    if err != nil {        return err    }    return writeKeyFile(filename, keyjson)}

EncryptKeyHas done a lot of things, using incoming keys and other information to generate JSON-formatted information, and then writeKeyFile save it on the hard disk. So in your keystore directory, you will see the key file that belongs to you. They are important, so don't delete them by mistake.

a.wallet.Hsm.XCreateAfter reading, let's go back to a.pseudohsmCreateKey the last part of the method. As you can see, when a key is successfully generated, it returns one NewSuccessResponse(xpub) that returns the information associated with the public key to the front end. It will be jsonHandler automatically converted into JSON format and returned to the past via HTTP.

In this case, we focused on /create-key what was done internally, and where the key file was placed, after the request was received via the Web API interface. The algorithm that involves the key (for example ed25519 ) will be discussed in detail in a later article.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.