GO语言-区块链离线钱包开发之如何存储私钥

# 如何存储私钥
在确保私钥安全的情况下,为了更好的体验,我们需要让钱包把私钥存储起来。给用户更好的体验感。Geth是将私钥通过加密技术转换为json格式的文件,这个文件虽然是明文的,但是解析它的时候需要密码,否则将无法解密。

在Geth中,使用`personal.newAccount("password")`,password就是密码。在keystore的文件中,我们可以看到一些关键元素。
- Address:账户地址信息
- Crypto:加密算法部分
  ```
  1、Cipher:对称加密
  2、Kdf:密钥生成函数
  3、Mac:验证密码的代码
  ```
- ID:uuid,系统内的唯一标识
- Version:版本号

## 定义hdkeystore包和结构
自定义一个HDkeystore结构体
```go
//HDkeystore使用的并非是私钥,它也是一个结构体,内部包含私钥
type HDkeyStore struct {
    keysDirPath string       //文件所在路径
    scryptN     int          //生成加密文件的参数N
    scryptP     int          //生成加密文件的参数P
    Key         keystore.Key //keystore对应的key
}
type Key struct{
 Id uuid.UUID
 Address common.Address
 PrivateKey *ecdsa.PrivateKey
}
```
## 生成UUID
借助rand加密包,生成uuid
```go
type UUID []byte

//全局加密随机阅读器
var rander = rand.Reader

//生成UUID
func NewRandom() UUID {
    uuid := make([]byte, 16)
    io.ReadFull(rand.Reader, uuid)
    //版本4规范处理与变形
    uuid[6] = (uuid[6] & 0x0f) | 0x40
    uuid[8] = (uuid[8] & 0x3f) | 0x80
    return uuid
}
```
## 编写HDkeystore构造函数
面向对象编程的通用思想
```go
//给出一个生成HDkeyStore对象的方法,通过privatekey生成
func NewHDkeyStore(path string, privateKey *ecdsa.PrivateKey) *HDkeyStore {
    //获得UUID
    uuid := []byte(NewRandom())
    key := keystore.Key{
        Id:         uuid,
        Address:    crypto.PubkeyToAddress(privateKey.PublicKey), //地址信息
        PrivateKey: privateKey,                                   //私钥信息
    }
    return &HDkeyStore{
        keysDirPath: path,
        scryptN:     keystore.LightScryptN, //固定参数
        scryptP:     keystore.LightScryptP, //固定参数
        Key:         key,
    }
}
```
## 写入文件实现
Keystore实际上是以太坊的一个接口,内部定义的三个方法都需要实现

### 实现StoreKey方法
存储key值
```go
//存储key为keystore文件
//StoreKey
func (ks HDkeyStore) StoreKey(filename string, key *keystore.Key, auth string) error {

    //编码key为json

    keyjson, err := keystore.EncryptKey(key, auth, ks.scryptN, ks.scryptP)

    if err != nil {
        return err
    }

    //写入文件

    return WriteKeyFile(filename, keyjson)

}
```
### 实现JoinPath方法
用于路径和文件拼接
```go
func (ks HDkeyStore) JoinPath(filename string) string {
    //如果filename是绝对路径,则直接返回
    if filepath.IsAbs(filename) {
        return filename
    }
    //将路径与文件拼接
    return filepath.Join(ks.keysDirPath, filename)
}
```
### 实现GetKey方法
keystore文件解析,形成私钥信息
```go

//解析key
func (ks *HDkeyStore) GetKey(addr common.Address, filename, auth string) (*keystore.Key, error) {
    //读取文件内容

    keyjson, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    //利用以太坊DecryptKey解码json文件
    key, err := keystore.DecryptKey(keyjson, auth)
    if err != nil {
        return nil, err
    }
    // 如果地址不同代表解析失败
    if key.Address != addr {
        return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
    }
    ks.Key = *key
    return key, nil
}
```

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>