借助网上的一段描述:

若以银行账户为类比,这 5 个词分别对应内容如下:

地址=银行卡号
密码=银行卡密码
私钥=银行卡号+银行卡密码
助记词=银行卡号+银行卡密码
Keystore+密码=银行卡号+银行卡密码
Keystore ≠ 银行卡号

1
2
implementation 'org.web3j:core:3.3.1-android'
implementation 'io.github.novacrypto:BIP39:0.1.9'

org.web3j:core 这个库是Java的,org.web3j:core:x-android 是兼容Android平台,所有接口和工具类都是为Java应用设计的,所以在Android上使用的时候要注意变通一下。

创建数字身份

创建钱包身份可以通过 WalletUtils 类来实现,它可以创建两种钱包:标准和 BIP39。

可以通过 generateWalletFile 函数创建,直接保存为json文件,以下其他三个函数都是它的封装。

在Android上不建议使用 WalletUtils 的这几个函数创建数字身份。

1
2
3
4
WalletUtils.generateFullNewWalletFile();
WalletUtils.generateLightNewWalletFile();
WalletUtils.generateNewWalletFile();
WalletUtils.generateWalletFile();

generateFullNewWalletFile 使用N_STANDARD加密强度,在Android上会发送OOM,Android的处理速度也跟不上。

generateLightNewWalletFile 相对来说比较轻量级,但是在我手机(红米4)上也花了21秒才创建完成,而加载为 Credentials 花了40秒。而在一台三星手机跑比较快,7秒左右。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public void (View view)  {

	try {
String password = "123456";
String path = Environment.getExternalStorageDirectory().getPath() + "/MyWallet";
File fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
//生成钱包身份保存到目录下
String fileName = null; Log.e(TAG, "startClickCreateDefault: "+fileDir.getPath() );
fileName = WalletUtils.generateLightNewWalletFile("123456",fileDir); Log.e(TAG, "wallet fileName: " + fileName ); //加载钱包身份
Credentials credentials = WalletUtils.loadCredentials(password,path + "/" +fileName);
Log.e(TAG, "getAddress: "+credentials.getAddress());
Log.e(TAG, "getPrivateKey: "+credentials.getEcKeyPair().getPrivateKey());
Log.e(TAG, "getPublicKey: "+credentials.getEcKeyPair().getPublicKey());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (CipherException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

创建BIP39身份

可以导出助记词,创建花了43秒,用助记词导入很快,只花了几秒。

1
WalletUtils.generateBip39Wallet();

WalletUtils提供的这个方法在Android上闪退,只有自己写一个了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public void startClickCreateBip39(View view){

	String password = "123456";
String path = Environment.getExternalStorageDirectory().getPath() + "/MyWallet";
File fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
Log.e(TAG, "wallet start");
//闪退
//Bip39Wallet wallet = WalletUtils.generateBip39Wallet(password,fileDir);
//String mnemonic = wallet.getMnemonic();
//Log.e(TAG, "助记词wallet.getMnemonic(): " + mnemonic);
//String fileName = wallet.getFilename();
//Log.e(TAG, "fileName: " + fileName);
try { StringBuilder sb = new StringBuilder();
byte[] entropy = new byte[Words.TWELVE.byteLength()];
new SecureRandom().nextBytes(entropy);
new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
String mnemonic = sb.toString();
//String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy);
byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
ECKeyPair privateKey = ECKeyPair.create(sha256(seed)); String fileName = WalletUtils.generateWalletFile(password, privateKey, fileDir, false);
Log.e(TAG, "fileName: " + fileName);
Log.e(TAG, "助记词wallet.getMnemonic(): " + mnemonic);
//加载钱包身份
Credentials credentials = WalletUtils.loadBip39Credentials(password,mnemonic);
Log.e(TAG, "getAddress: "+credentials.getAddress());
Log.e(TAG, "getPrivateKey: "+credentials.getEcKeyPair().getPrivateKey());
Log.e(TAG, "getPublicKey: "+credentials.getEcKeyPair().getPublicKey()); } catch (CipherException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
} }

Android创建钱包

上面这些感觉比较适合Java程序,我们跳进去看看就知道了,其实生成数字身份的代码是:

1
2
3
4
public static WalletFile createLight(String password, ECKeyPair ecKeyPair)
throws CipherException {
return create(password, ecKeyPair, N_LIGHT, P_LIGHT);
}

针对Android,我们需要将生成的数字身份 WalletFile 转为 JSON (Keystore)保存到 SharedPreferences ,所以整理一个工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
大专栏  14、创建/恢复ETH钱包身份s="line">80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import android.support.annotation.Nullable;
import android.util.Log; import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.crypto.MnemonicUtils;
import org.web3j.crypto.Wallet;
import org.web3j.crypto.WalletFile; import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom; import io.github.novacrypto.bip39.MnemonicGenerator;
import io.github.novacrypto.bip39.Words;
import io.github.novacrypto.bip39.wordlists.English; import static org.web3j.crypto.Hash.sha256; public class MyWalletTool { private final String TAG = getClass().getName(); /**
* 创建一个轻量级钱包,没有助记词
* @param password
* @return
*/
public WalletFile createLightWallet(String password){ WalletFile walletFile = null;
try {
walletFile = Wallet.createLight(password, Keys.createEcKeyPair());
} catch (CipherException | NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return walletFile;
} /**
* 创建一个助记词
* @return
*/
public String createMnemonic(){ StringBuilder sb = new StringBuilder();
byte[] entropy = new byte[Words.TWELVE.byteLength()];
new SecureRandom().nextBytes(entropy);
new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);
return sb.toString();
} /**
* 创建一个带有助记词的轻量级钱包
* @param password
* @param mnemonic
* @return
*/ public WalletFile createBip39Wallet(String password,String mnemonic){ WalletFile walletFile = null;
try {
byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
Log.d(TAG, "createLight start...");
walletFile = Wallet.createLight(password, ECKeyPair.create(sha256(seed)));
Log.d(TAG, "createLight end.");
} catch (Exception e){
e.printStackTrace();
}
return walletFile;
} /**
* 生成凭证
* @param password
* @param walletFile
* @return
* @throws CipherException
*/
public Credentials createCredentials(String password,String mnemonic){ byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
return Credentials.create(ECKeyPair.create(sha256(seed)));
} public Credentials createCredentials(String password,WalletFile walletFile) throws CipherException { return Credentials.create(Wallet.decrypt(password, walletFile));
} public Credentials createCredentials(String privateKey) { return Credentials.create(privateKey);
}

交易凭证Credentials

web3j 中每一个交易都需要一个参数:CredentialsCredentials 实例化有三种方法,其中私钥权限最高,所以绝不能泄露自己的私钥和助记词,常用的是密码 + Keystore

MyWalletTool调用的函数来看,交易凭证的实例化只需要以下之一:

  1. 私钥
  2. 助记词
  3. 密码 + Keystore

私钥

一个钱包只有一个私钥且不能修改

为什么 私钥 单独可以实现实例化 Credentials

Credentials 的构造函数参数是 ECKeyPairaddress

1
2
3
4
private Credentials(ECKeyPair ecKeyPair, String address) {
this.ecKeyPair = ecKeyPair;
this.address = address;
}

address 可以通过 ECKeyPair 推导出来,而 ECKeyPair 的构造函数参数就是公钥和私钥

1
2
3
4
public ECKeyPair(BigInteger privateKey, BigInteger publicKey) {
this.privateKey = privateKey;
this.publicKey = publicKey;
}

公钥可以通过私钥推导出来,所以可以直接实例化 Credentials

1
Sign.publicKeyFromPrivate(privateKey)

助记词

助记词是明文私钥的另一种表现形式,其目的是为了帮助用户记忆复杂的私钥

Canache生成的一个助记词

1
2
3
助记词:jump dolphin leave reward allow farm gate hospital region diary seminar loan
地址:0x7E728c371D66813434F340E6D473B212F506bA54
私钥:6229413033912ab1f26e36f0aad7e1ea2b957de73cfedf788b9fff811192aa89

imToken 可以成功导入钱包,但是用下面的 BIP39 标准的代码却不行(passphrase是加盐,这里为空)。

1
2
3
4
byte[] seed = MnemonicUtils.generateSeed(mnemonic, passphrase);//passphrase=null
ECKeyPair ecKeyPair = ECKeyPair.create(sha256(seed));
System.out.println("private=" + ecKeyPair.getPrivateKey().toString());
System.out.println("private=" + ecKeyPair.getPrivateKey().toString(16));

结果是:

1
2
private=27538423023524426157929608133615570842335693203949154557762660148101331275721
private=3ce231f097447fe5d623b3a1f9a37e8c554ee014959903c4e2ebadf69ac7cfc9

网上查资料说 imToken 用的是 BIP44 标准。后面再看看怎么搞,imToken核心码开源地址

BIP44助记词创建和导入

Keystore

将私钥以加密的方式保存为一份 JSON 文件,这份 JSON 文件就是 Keystore,所以它就是加密后的私钥,它必须配合钱包密码才能使用该账号。

1
ECKeyPair ecKeyPair = Wallet.decrypt(password, walletFile);

钱包开源项目

  1. A ethereum wallet like imToken for Android
  2. A beautiful, secure and native Ethereum Wallet for Android
  3. Lightweight JS Wallet for Node and the browser
  4. A plugin that turns Vault into an Ethereum wallet. Golang

14、创建/恢复ETH钱包身份的更多相关文章

  1. [币严BIZZAN区块链]Java生成ETH钱包助记词、私钥、地址

    本文主要介绍在Java工程中如何生成ETH钱包的助记词.私钥.地址. 一.在之前创建的spring boot 项目中的 pom.xml文件中加入需要的依赖 <dependency> < ...

  2. EOS智能合约开发(二):EOS创建和管理钱包

    上节介绍了EOS智能合约开发之EOS环境搭建及启动节点 那么,节点启动后我们要做的第一件事儿是什么呢?就是我们首先要有账号,但是有账号的前提是什么呢?倒不是先创建账号,而是先要有自己的一组私钥,有了私 ...

  3. 配置ASM以及创建恢复目录

    本次配置ASM沿用了搭建RAC的环境配置,系统选用CENTOS6.8 首先本地配置YUM,安装GRID集群件所需要的RPM包 [root@rac01 Packages]# cd /etc/yum.re ...

  4. nodejs 使用 ethers创建以太坊钱包

    创建钱包创建钱包流程: 生成随机助记词 => 通过助记词创建钱包=>钱包信息和加密明文(私钥和密码加密) 导入钱包通过插件提供方法,根据助记词|keyStore|私钥,找到钱包信息(地址和 ...

  5. VMware Workstation 14创建mac-10.12虚拟机详细步骤

     一.VMware和unlocker的下载和安装 链接:https://pan.baidu.com/s/15Z4DqRENt6JdyfJef_VWSw 密码:40vw 1.安装VMware Works ...

  6. [Swift通天遁地]九、拔剑吧-(14)创建更美观的景深视差滚动效果

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  7. ABBYY FineReader 14创建PDF文档功能解析

    使用ABBYY FineReader,您可以轻松查看和编辑任何类型的 PDF,真的是一款实至名归的PDF编辑转换器,您知道的,它能够保护.签署和编辑PDF文档,甚至还可以创建PDF文档,本文和小编一起 ...

  8. oracle创建恢复编录(recovery catalog)

    1.在要作为恢复编录的数据库创建用户 create user rman identified by oracle default tablespace system temporary TABLESP ...

  9. 【转载】如何用IntelliJ IDEA 14 创建Web项目

    首先要理解一个概念:在IntelliJ IDEA中"new Project"相当于eclipse中的工作空间(Workspace),而"new Module"相 ...

随机推荐

  1. Matlab高级教程_第二篇:Matlab相见恨晚的模块_01_定时器

    MATLAB的定时器功能(timer函数): 1 从MATLAB6.5版本开始,MATLAB开始支持定时器.相对于传统的pause函数来说,定时器要强大的多,不仅可以等效实现pause的功能,还可以显 ...

  2. HDU-1875 畅通工程再续(最小生成树+判断是否存在)

    http://acm.hdu.edu.cn/showproblem.php?pid=1875 Problem Description 相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛 ...

  3. 蓝桥杯练习Day 2

    问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n ...

  4. Opencv笔记(一):图像的基本操作

    1.图像的读.显示和保存操作 import cv2 img = cv2.imread('filename',0); cv2.imshow('name',img); k=cv2.waitKey(0); ...

  5. Monkey通过安装包获取包名

    在monkey命令中,包名常作为一个参数.但我们经常知道apk文件,却不知道包名. 如何获取包名呢? 方法一:AAPT 在SDK的build-tools目录下,aapt工具可以查看,创建,更新zip格 ...

  6. 【lca+输入】Attack on Alpha-Zet

    Attack on Alpha-Zet 题目描述 Space pirate Captain Krys has recently acquired a map of the artificial and ...

  7. pytorch函数之nn.Linear

    class torch.nn.Linear(in_features,out_features,bias = True )[来源] 对传入数据应用线性变换:y = A x+ b 参数: in_featu ...

  8. android打飞机游戏、MVP句子迷App、悬浮窗、RxJava+Retrofit、加载动画、定制计划App等源码

    Android精选源码 微信打飞机 android进度设置加载效果源码 Android新手引导库EasyGuide MVP-好看又好用的句子迷客户端 XFloatView 一个简易的悬浮窗实现方案 a ...

  9. [LC] 1170. Compare Strings by Frequency of the Smallest Character

    Let's define a function f(s) over a non-empty string s, which calculates the frequency of the smalle ...

  10. EXAM-2018-8-9

    EXAM-2018-8-9 B 水题 注意理解题意 有坑 G 博弈 观察发现 总是会进行到最后两个,或者先手取完全部,再特判一下只有一张牌的情况 H 九连环 通过找规律 我们可以得出递推式: F[n] ...