以太坊钱包开发系列2 - 账号Keystore文件导入导出

以太坊去中心化网页钱包开发系列,将从零开始开发出一个可以实际使用的钱包,本系列文章是理论与实战相结合,一共有四篇:创建钱包账号账号Keystore文件导入导出展示钱包信息及发起签名交易发送Token(代币),这是第二篇,主要介绍钱包账号导出与导入,将对Keystore文件的生成的原理进行介绍。

如何导入Geth创建的账号?

上一篇文章,介绍了如何使用私钥及助记词来创建账号,如果是使用已有的私钥及助记词,这其实也是账号导入的过程。

有一些同学会问,我的账号是Geth生成的,如何导入到钱包呢?使用Geth的同学,应该知道Geth在创建账号时会生成一个对应keystore JSON文件,Keystore文件存储加密后的私钥信息,因此我们需要做的就是导入这个Keystore文件,这个文件通常在同步区块数据的目录下的keystore文件夹(如: ~/.ethereum/keystore)里。

尽管在ethers.js 中,简单的使用一个函数就可以完成keystore文件的导入,不过理解Keystore 文件的作用及原理还是非常有必要的,当然如果你是在没有兴趣,可以直接跳到本文最后一节:使用ethers.js 实现账号导出导入。

详细解读 Keystore 文件

为什么需要 Keystore 文件

通过这篇文章理解开发HD 钱包涉及的 BIP32、BIP44、BIP39,私钥其实就代表了一个账号,最简单的保管账号的方式就是直接把私钥保存起来,如果私钥文件被人盗取,我们的数字资产将洗劫一空。

Keystore 文件就是一种以加密的方式存储密钥的文件,这样的发起交易的时候,先从Keystore 文件是使用密码解密出私钥,然后进行签名交易。这样做之后就会安全的多,因为只有***同时盗取 keystore 文件和密码才能盗取我们的数字资产。

Keystore 文件如何生成的

以太坊是使用对称加密算法来加密私钥生成Keystore文件,因此对称加密秘钥(注意它其实也是发起交易时需要的解密秘钥)的选择就非常关键,这个秘钥是使用KDF算法推导派生而出。因此在完整介绍Keystore 文件如何生成前,有必要先介绍一下KDF。

使用 KDF 生成秘钥

密码学KDF(key derivation functions),其作用是通过一个密码派生出一个或多个秘钥,即从 password 生成加密用的 key。

其实在理解开发HD 钱包涉及的 BIP32、BIP44、BIP39中介绍助记词推导出种子的PBKDF2算法就是一种KDF函数,其原理是加盐以及增加哈希迭代次数。

而在Keystore中,是用的是Scrypt算法,用一个公式来表示的话,派生的Key生成方程为:

DK = Scrypt(salt, dk_len, n, r, p)

其中的 salt 是一段随机的盐,dk_len 是输出的哈希值的长度。n 是 CPU/Memory 开销值,越高的开销值,计算就越困难。r 表示块大小,p 表示并行度。

Litecoin 就使用 scrypt 作为它的 POW 算法

实际使用中,还会加上一个密码进行计算,用一张图来表示这个过程就是:

对私钥进行对称加密

上面已经用KDF算法生成了一个秘钥,这个秘钥就是接着进行对称加密的秘钥,这里使用的对称加密算法是 aes-128-ctr,aes-128-ctr 加密算法还需要用到一个参数初始化向量 iv。

Keystore文件

好了,我们现在结合具体 Keystore文件的内容,就很容易理解了Keystore 文件怎么产生的了。

{
   "address":"856e604698f79cef417aab...",
   "crypto":{
      "cipher":"aes-128-ctr",
      "ciphertext":"13a3ad2135bef1ff228e399dfc8d7757eb4bb1a81d1b31....",
      "cipherparams":{
         "iv":"92e7468e8625653f85322fb3c..."
      },
      "kdf":"scrypt",
      "kdfparams":{
         "dklen":32,
         "n":262144,
         "p":1,
         "r":8,
         "salt":"3ca198ce53513ce01bd651aee54b16b6a...."
      },
      "mac":"10423d837830594c18a91097d09b7f2316..."
   },
   "id":"5346bac5-0a6f-4ac6-baba-e2f3ad464f3f",
   "version":3
}

来解读一下各个字段:

  • address: 账号地址
  • version: Keystore文件的版本,目前为第3版,也称为V3 KeyStore。
  • id : uuid
  • crypto: 加密推倒的相关配置.
    • cipher 是用于加密以太坊私钥的对称加密算法。用的是 aes-128-ctr 。
    • cipherparams 是 aes-128-ctr 加密算法需要的参数。在这里,用到的唯一的参数 iv。
    • ciphertext 是加密算法输出的密文,也是将来解密时的需要的输入。
    • kdf: 指定使用哪一个算法,这里使用的是 scrypt。
    • kdfparams: scrypt函数需要的参数
    • mac: 用来校验密码的正确性, mac= sha3(DK[16:32], ciphertext) 下面一个小节单独分析。

我们来完整梳理一下 Keystore 文件的产生:

  1. 使用scrypt函数 (根据密码 和 相应的参数) 生成秘钥
  2. 使用上一步生成的秘钥 + 账号私钥 + 参数 进行对称加密。
  3. 把相关的参数 和 输出的密文 保存为以上格式的 JSON 文件

如何确保密码是对的?

当我们在使用Keystore文件来还原私钥时,依然是使用kdf生成一个秘钥,然后用秘钥对ciphertext进行解密,其过程如下:

此时细心的同学会发现,无论使用说明密码,来进行这个操作,都会生成一个私钥,但是最终计算的以太坊私钥到底是不是正确的,却不得而知。

这就是 keystore 文件中 mac 值的作用。mac 值是 kdf输出 和 ciphertext 密文进行SHA3-256运算的结果,显然密码不同,计算的mac 值也不同,因此可以用来检验密码的正确性。检验过程用图表示如下:

现在我们以解密的角度完整的梳理下流程,就可以得到以下图:

用ethers.js 实现账号导出导入

ethers.js 直接提供了加载keystore JSON来创建钱包对象以及加密生成keystore文件的方法,方法如下:

// 导入keystore Json
    ethers.Wallet.fromEncryptedJson(json, password, [progressCallback]).then(function(wallet) {
       // wallet
    });

    // 使用钱包对象 导出keystore Json
    wallet.encrypt(pwd, [progressCallback].then(function(json) {
        // 保存json
    });

现在结合界面来完整的实现账号导出及导入,先看看导出,UI图如下:

HTML 代码如下:

    <h3>KeyStore 导出:</h3>
    <table>
        <tr>
            <th>密码:</th>
            <td><input type="text" placeholder="(password)" id="save-keystore-file-pwd" /></td>
        </tr>

        <tr>
            <td> </td>
            <td>
                <div id="save-keystore" class="submit">导出</div>
            </td>
        </tr>
    </table>

上面主要定义了一个密码输入框和一个导出按钮,点击“导出”后,处理逻辑代码如下:

// "导出" 按钮,执行exportKeystore函数
  $(‘#save-keystore‘).click(exportKeystore);

  exportKeystore: function() {
    // 获取密码
    var pwd = $(‘#save-keystore-file-pwd‘);

    // wallet 是上一篇文章中生成的钱包对象
    wallet.encrypt(pwd.val()).then(function(json) {
      var blob = new Blob([json], {type: "text/plain;charset=utf-8"});

      // 使用了FileSaver.js 进行文件保存
      saveAs(blob, "keystore.json");

    });
  }

FileSaver.js 是可以用来在页面保存文件的一个库。

再来看看导入keystore 文件, UI图如下:

 <h2>加载账号Keystore文件</h2>
<table>
    <tr>
        <th>Keystore:</th>
        <td><div class="file" id="select-wallet-drop">把Json文件拖动到这里</div><input type="file" id="select-wallet-file" /></td>
    </tr>
    <tr>
        <th>密码:</th>
        <td><input type="password" placeholder="(password)" id="select-wallet-password" /></td>
    </tr>
    <tr>
        <td> </td>
        <td>
            <div id="select-submit-wallet" class="submit disable">解密</div>
        </td>
    </tr>
</table>

上面主要定义了一个文件输入框、一个密码输入框及一个“解密“按钮,因此处理逻辑包含两部分,一是读取文件,二是解析加载账号,关键代码如下:

 // 使用FileReader读取文件,

var fileReader = new FileReader();
  fileReader.onload = function(e) {
    var json = e.target.result;

    // 从加载
    ethers.Wallet.fromEncryptedJson(json, password).then(function(wallet) {

    }, function(error) {

    });

  };
fileReader.readAsText(inputFile.files[0]);

哈哈哈,有到了推广时间了,完整源码请订阅深入浅出区块链技术小专栏查看,赶紧订阅吧,走过路过,不容错过。

参考文档

what-is-an-ethereum-keystore-file

深入浅出区块链 - 系统学习区块链,打造最好的区块链技术博客。

深入浅出区块链知识星球最专业技术问答社区,加入社区还可以在微信群里和300多位区块链技术爱好者一起交流。

原文地址:http://blog.51cto.com/13457438/2314306

时间: 2024-07-31 12:52:21

以太坊钱包开发系列2 - 账号Keystore文件导入导出的相关文章

(转)以太坊 钱包 创建 导入 Keystore

最近闲来无事 研究了下以太坊钱包 下边分享下 准备工作 : 需要用到的加密:BIP32 BIP39 BIP44 SCRYPT 加密算法 githab地址 https://github.com/NovaCrypto/BIP32 https://github.com/NovaCrypto/BIP39 https://github.com/NovaCrypto/BIP44 https://github.com/wg/scrypt/ 官方依赖 https://github.com/web3j/web3j

c#实战开发:用.net core开发一个简单的Web以太坊钱包 (六)

今天就来开发一个C# 版的简易钱包 先回顾以前的内容 c#实战开发:以太坊Geth 命令发布智能合约 (五) c#实战开发:以太坊Geth 常用命令 (四) c#实战开发:以太坊钱包快速同步区块和钱包卡死解决方案 (三) c#实战开发:以太坊钱包对接私链 (二) c#实战开发:以太坊私链搭建(一) 先看一下可视化钱包有哪些功能呢? 那这个钱包得有什么功能呢? 1.查看用户 2.查看交易记录 3.转账 4.发布智能合约 5.代币转账 6.代币查询 7.实时同步区块对比 8.智能填写手续费 首先新建

Android开发以太坊钱包生成应用程序

Android应用程序以太坊钱包生成,要做的工作不少,不过如果我们一步一步来应该也比较清楚: 1.在app/build.gradle中集成以下依赖项: compile ('org.web3j:core-android:2.2.1') web3j核心是用于从服务器下载以太坊区块链数据的核心类库.它通常用于以太坊开发. 2.我们将设计一个Android UI示例,屏幕上将有文本编辑和按钮.在EditText中,将要求用户输入钱包的密码.然后在按钮的单击事件上,我们将开始发送密码的过程.以下是layo

登链钱包(一款功能强大的以太坊钱包)完全开源

你是否和我前段时间一样,苦苦的寻找一款好用的开源以太坊钱包,你会发现可用都很少,因为很多钱包说开源,仅仅是开源部分代码,现在不需要再找了, 登链钱包完全开源,登链钱包完全开源,登链钱包完全开源,重要的事情说三遍. 再也不用傻乎乎找人开发以太坊钱包了, 直接拿去用吧:再也不用担心私钥会被上传到别人的服务器上. <!-- more --> 写在前面 区块链是开放的,很难想象一个封闭的项目如何产生信任,开源一直是区块链社区所倡导的行为准则. 我们也希望开源能够降低行业的开发门槛,吸引更多的开发者和公

牛奶ddw如何通过以太坊钱包实现互相打赏

很多朋友不清楚如何转账ddw,但是万能的网友是无敌的先就自己摸索的一点经验总结下今天的转账经验. 1. 提取到自己的账户 这个大家都知道如何操作,使用官方的钱包 在“日日盈app”中点击"我的设备”,点击提取收益,如果顺利币会瞬间提取到你的主账户钱包中 如果失了(查看账户余额不为0则失败),稍后使用4G或者其他网络再次尝试,多次尝试后即可 2. 如何互相转账 2.1 请下载网友提供的以太坊万能钱包:http://ox0ubbr6d.bkt.clouddn.com/Ethereum-Wallet-

Windows下以太坊集成开发环境(Remix-IDE)搭建与智能合约的简单应用

前面我们介绍了在以太坊平台下开发区块链私有链的过程,以及在私有链下进行挖矿的操作,而随着区块链技术的发展,区块链技术已不仅限于比特币的应用,未来将重在着眼于向其他领域的扩展推广,以此开启区块链2.0以智能合约为代表的时代.本文选用remix作为开发应用平台,配合geth客户端实现与以太坊网络的交互,下一篇文章则改用truffle和ganache搭建开发框架(这是后话). 本文分为remix-ide搭建和智能合约部署应用两部分. 一.remix-ide搭建 [准备工作] 1.安装Node.js.N

以太坊 DApp 开发入门实战! 用Node.js和truffle框架搭建——区块链投票系统!

第一节 概述 面向初学者,内容涵盖以太坊开发相关的基本概念,并将手把手地教大家如何构建一个 基于以太坊的完整去中心化应用 -- 区块链投票系统. 通过学习,你将掌握: 以太坊区块链的基本知识 开发和部署以太坊合约所需的软件环境 使用高级语言(solidity)编写以太坊合约 使用NodeJS编译.部署合约并与之交互 使用Truffle框架开发分布式应用 使用控制台或网页与合约进行交互 前序知识要求 为了顺利完成,最好对以下技术已经有一些基本了解: 一种面向对象的开发语言,例如:Python,Ru

区块链学习(3)--以太坊Dapp开发

DApp是Decentralized Application的缩写,译为:分散式的应用程序.App我们都知道,我们在智能手机上安装的应用程序也就是App.而DApp比App多了一个'D','D'的意思是分散式的.意思是 分散式的应用程序/去中心化的应用程序.与传统的App最大的区别是:DApp运行在去中心化的网络上,也就是区块链网络中.这里的DApp开发用以太坊智能合约为例,智能合约是记录在链上的一段能够控制链行为事件的一段协议,如:合约下关联账户转币.查账.投票.购买等等,合约里涉及的变量.常

以太坊钱包搭建与使用

前言 本文使用系统:centos7. 以太坊客户端:geth 安装 下载geth: 官方下载地址:https://geth.ethereum.org/downloads 直接下载: wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.9.6-bd059680.tar.gz 解压 tar zxvf geth-linux-amd64-1.9.6-bd059680.tar.gz cd geth-linux-amd