由TrustWallet理解以太坊钱包管

白癜风诚信为民 https://jbk.39.net/yiyuanfengcai/tsyl_bjzkbdfyy/5077/

钱包管理

钱包管理就要提到一个类EtherKeystore,应用的核心业务的处理类,有钱包管理(创建、删除、导入、导出)、助记词转化、签名工作、私钥管理等功能。

EtherKeystore中使用了由Trust开源的了两个库:TrustKeystore:用于管理钱包的通用以太坊密钥库。TrustCore:区块链核心的数据结构和算法。还有CryptoSwift,一个标准的安全加密算法集合的库。

钱包创建

在EtherKeystore类中,封装了钱包的创建,主要使用了TrustKeystore库、TrustCore库中关于公私钥和地址的API、以及密码学的库CryptoSwift。我下面所说的整个流程也包括这些库中的源码逻辑,先创建密钥对(或者助记词),再利用本地生成的随机密码对密钥进行加密保存,然后生成钱包,将钱包、获取私钥的密码以及KeystoreKey保存到本地。

Trust默认的方式是生成助记词,这种方式其实是私钥的一种管理方式,助记词是由私钥通过某种算法派生出来的,TrustCore中的Crypto就是这个功能。而且当你用到私钥的时候,你还可以把你的助记词通过对应的算法在转译成私钥。所以它只是一种私钥的存储方式,下面文章中以私钥为例来讲述整个流程。

创建公钥私钥

创建钱包就相当于生成一对密钥,公钥(PublicKey)和私钥(PrivateKey)。公钥其实就相当于你账户在区块链中的地址(Address);私钥就相当于你钱包的账号密码,它是证明你是钱包主人的唯一证明,一旦丢失就不可找回。当然,公钥并不完全等于地址,地址是由公钥经过一系列的算法生成的,需要经过SHA3-(Keccak)哈希然后转化为符合EIP55规则的字符串。

(sk,pk)=generateKeys(keysize)

上面这段伪代码中,generateKeys方法把keysize作为输入,来产生一对公钥和私钥。私钥sk被安全保存,并用来签名一段消息;公钥pk是人人都可以找到的,拿到它,就可以用来验证你的签名。下图是TrustCore中对以太坊私钥和地址的keysize定义,私钥是32字节,公钥地址是20字节,所以十六进制的私钥长度为64位,而公钥地址长度为40位。

具体来说,创建公钥和私钥的功能是由TrustCore中的PrivateKey来完成的。而且是通过苹果官方的Security库来创建的公钥和私钥,经过整理密钥对生成和获取过程如下:

funcgetPrivatePublicKey()-(String,String){

letprivateAttributes:[String:Any]=[

kSecAttrIsExtractableasString:true,

]

letparameters:[String:Any]=[

kSecAttrKeyTypeasString:kSecAttrKeyTypeEC,

kSecAttrKeySizeInBitsasString:,

kSecPrivateKeyAttrsasString:privateAttributes,

]

//PrivateKeyToString

guardletprivateKey=SecKeyCreateRandomKey(parametersasCFDictionary,nil)else{

fatalError("Failedtogeneratekeypair")

}

guardvarpriRepresentation=SecKeyCopyExternalRepresentation(privateKey,nil)asData?else{

fatalError("Failedtoextractnewprivatekey")

}

defer{

priRepresentation.replaceSubrange(0..priRepresentation.count,with:repeatElement(0,count:priRepresentation.count))

}

letpriData=Data(priRepresentation.suffix(32))

varpriString=""

forbyteinpriData{

priString.append(String(format:"%02x",byte))

}

//PublicKeyToString

guardletpublicKey=SecKeyCopyPublicKey(privateKey)else{

fatalError("Failedtogetpublickey")

}

guardvarpubRepresentation=SecKeyCopyExternalRepresentation(publicKey,nil)asData?else{

fatalError("Failedtoextractnewpublickey")

}

defer{

pubRepresentation.replaceSubrange(0..pubRepresentation.count,with:repeatElement(0,count:pubRepresentation.count))

}

letpubData=Data(pubRepresentation.suffix(32))

varpubString=""

forbyteinpubData{

pubString.append(String(format:"%02x",byte))

}

return(priString,pubString)

}

1

2

使用随机密码对私钥加密

在生成了私钥之后,将在KeystoreKeyHeader类中,这里使用了CryptoSwift(安全加密算法集合的库)对私钥进行加密。使用AES-算法进行对称加密后,将这些数据以KeystoreKeyHeader类型保存在KeystoreKey中。

创建Wallet

在前两个步骤的基础之上,就可以创建一个Wallet了,并将Wallet加入到当前的账户中。也会计算或者获取一些参数存储在Wallet中,如公钥地址Address,Account、KeystoreKey等。

保存到本地

KeyStore会将当前钱包账户的KeystoreKey数据存储在本地文件中。文件以"UTC+时间戳+钱包唯一标识"为名称存储在本地,其中存储的是上面KeystoreKey的数据。这些数据用户每次启动时,将会由这些数据再次生成所有的Wallet数据。

当然,私钥当然也是需要保存的,前一篇文章中说过了,这样的敏感信息保存在keychain中。但keychain并不是直接存储这私钥,而是将获取私钥的密码保存在其中了。以钱包的id为key值,将获取私钥的密码保存子keychain之中,拿出密码后,再使用KeystoreKey进行AES-对称解密,获取私钥,便可以使用了。所以,KeystoreKey这个类的主要功能是对私钥和助记词的管理以及对私钥的加解密。

另外,这样拥有PrivateKey的钱包账户是不需要存储在Realm数据库中的。只有一种需要保存到本地的Realm数据库中,那就是导入地址钱包,下面将会说明。

钱包的导入

钱包导入相对于钱包的创建来说,只是不需要自己去生成公钥和私钥对了,剩下的流程还是一样的。当然导入时会有三种方式,除了之前提到的私钥和助记词的方式,还有地址的方式。

钱包地址是公开的,当然你也可以导入,也可以查看这个钱包的任何数据,但因为你不具备它的私钥,所以你不可以进行签名或者说任何写入区块链的操作。所以这种方式,就不需要KeyStore进行操作了,只需要EtherKeystore进行本地操作,将其放入本地的Realm数据库中,那就是导入地址钱包。当启动应用时,将会以两者组成的数据为本地钱包列表。

钱包导出、删除等

钱包导出,当然也会分三种方式,私钥和助记词的方式,还有地址的方式。在keychain中将密码取出,然后通过KeystoreKey解密到私钥或者助记词,导出。地址的方式,就是直接导出地址。

如果你把上面的钱包创建条理理清楚了,你就可以想到删除只是钱包创建的逆过程,但没有那么复杂。只需要验证你的私钥是正确的就可以将你本地KeystoreKey删除了。




转载请注明:http://www.aierlanlan.com/grrz/2522.html