建立數字錢包(一)賬號生成
橢圓曲線數字簽名演算法生成私鑰
Secp256k1
通過橢圓曲線數字簽名演算法生成私鑰和公鑰,其中SEC(Standards for Efficient Cryptography)是專門利用ECDSA或者其可選項Schnorr演算法來產生高效的加密方法。
特點是生成金鑰很快。
Scep256k1 基本特性
- secp256k1 ECDSA signing/verification and key generation.
- Adding/multiplying private/public keys.
- Serialization/parsing of private keys, public keys, signatures.
- Constant time, constant memory access signing and pubkey generation.
- Derandomized DSA (via RFC6979 or with a caller provided function.)
- Very efficient implementation.
講解程式碼
步驟
- 生成私鑰
- 加密私鑰
- 生成 keyObject 物件
- 從keyObject物件中恢復私鑰
生成私鑰
下面利用 keythereum[1] 產生符合以太坊的金鑰,併產生keyObject檔案
const params = { keyBytes: 32, ivBytes: 16 };
let {privateKey, salt, iv} = keythereum.create(params);
keythereum可以產生私鑰,以及後面加密私鑰所用的PBKDF2演算法需要的salt,和加密aes-128-ctr私鑰的iv值。
得到私鑰之後,我們可以通過私鑰生成公鑰。
let privateKeyBuffer = Buffer.from(privateKey, "hex") // or "base64"
let publicKey = secp256k1.publicKeyCreate(privateKeyBuffer, false).slice(1);
let address = "0x" + keccak256(publicKey).slice(-20).toString("hex");
加密私鑰
利用KDF演算法基於password派生出金鑰,然後利用這個金鑰加密我們的私鑰。
const password = "Hello,Ethereum"
const options = {
kdf: "pbkdf2",
cipher: "aes-128-ctr",
kdfparams: {
c: 262144,
dklen: 32,
prf: "hmac-sha256"
}
};
const keyObject = keythereum.dump(password, privateKey, salt, iv, options);
這就是產生keyObject基本思路。我們在看看dump函式到底做了什麼
this.marshal(this.deriveKey(password, salt, options), privateKey, salt, iv, options);
deriveKey(...) 的原始碼如下:
this.crypto.pbkdf2Sync(
password,
salt,
options.kdfparams.c || this.constants.pbkdf2.c,
options.kdfparams.dklen || this.constants.pbkdf2.dklen,
prf //hmac-sha256
);
這裡基於password生成的derivedKey,這個金鑰並不是我們要用的私鑰,而是用來加密先前生成的privateKey的,加密的過程在marshal函式中呼叫的encrypt函式裡。
let ciphertext = this.encrypt(privateKey, derivedKey.slice(0, 16), iv, algo).toString("hex");
encrypt函式,如下:
var cipher, ciphertext;
algo = algo || this.constants.cipher;
if (!this.isCipherAvailable(algo)) throw new Error(algo + " is not available");
//加密過程
cipher = this.crypto.createCipheriv(algo, this.str2buf(key), this.str2buf(iv));
ciphertext = cipher.update(this.str2buf(plaintext));
return Buffer.concat([ciphertext, cipher.final()]);
此處的ciphertext代表的是privateKey,而key則是derivedKey
生成 keyObject 物件
得到了加密後的ciphertext之後,開始組裝keyObject物件並返回。
keyObject = {
address: this.privateKeyToAddress(privateKey).slice(2),
crypto: {
cipher: options.cipher || this.constants.cipher,
ciphertext: ciphertext,
cipherparams: { iv: iv.toString("hex") },
mac: this.getMAC(derivedKey, ciphertext)
},
id: uuid.v4(), // random 128-bit UUID
version: 3
};
keyObject.crypto.kdf = "pbkdf2";
keyObject.crypto.kdfparams = {
c: options.kdfparams.c || this.constants.pbkdf2.c,
dklen: options.kdfparams.dklen || this.constants.pbkdf2.dklen,
prf: options.kdfparams.prf || this.constants.pbkdf2.prf,
salt: salt.toString("hex")
};
privateKeyToAddress(...)方法裡首先通過privateKey產生publicKey,然後使用keccak256雜湊publicKey得到地址。
具體實現如下:
let privateKeyBuffer = Buffer.from(privateKey);
let publicKey = secp256k1.publicKeyCreate(privateKeyBuffer, false).slice(1);
let address = "0x" + keccak256(publicKey).slice(-20).toString("hex");
keccak256(publicKey) 產生了32bytes,擷取尾部20bytes轉換成十六進位制之後就是40字元,加上前導0x之後,就是42個字元的以太坊地址,比如:0x0f645438395206b408e52be4fcf4bc21c330bfa2
從keyObject物件中恢復私鑰
有了keyObject和密碼就可以恢復原來的私鑰
let privateKey = keythereum.recover(password, keyObject)
可以想到,recover方法中,首先會利用password和keyObject中的salt派生出當初的金鑰derivedKey,然後把加密過的私鑰ciphertext和derivedKey, iv作為原來加密演算法aes-128-ctr的輸入引數,成功解密後返回明文的私鑰。
具體程式碼如下:
verifyAndDecrypt(this.deriveKey(password, salt, keyObjectCrypto), salt, iv, ciphertext, algo)
這裡首先得到了derivedKey,然後驗證並解密kyeObject中的ciphertext,如下:
function verifyAndDecrypt(derivedKey, salt, iv, ciphertext, algo) {
var key;
if (self.getMAC(derivedKey, ciphertext) !== keyObjectCrypto.mac) {
throw new Error("message authentication code mismatch");
}
if (keyObject.version === "1") {
key = keccak256(derivedKey.slice(0, 16)).slice(0, 16);
} else {
key = derivedKey.slice(0, 16);
}
return self.decrypt(ciphertext, key, iv, algo);
}
注意這裡的mac值比較,確保了ciphertext沒有被人篡改才有解密的必要。
參考實現
相關文章
- 以太坊錢包開發系列1 - 建立錢包賬號
- 如何開發一款以太坊(安卓)錢包系列2 - 匯入賬號及賬號管理安卓
- 如何開發一款以太坊(安卓)錢包系列1 - 通過助記詞建立賬號安卓
- 多幣種數字錢包開發及區塊鏈數字錢包系統區塊鏈
- 區塊鏈錢包之ETH錢包生成區塊鏈
- [譯] 數字貨幣錢包詳解
- 區塊鏈錢包之BTC錢包地址生成區塊鏈
- 可以像微信錢包一樣?2020年數字錢包技術重要的進化方向(上)
- 什麼是NFT數字錢包開發?
- 區塊鏈錢包開發,數字貨幣錢包開發的型別區塊鏈型別
- 告別App,數字人民幣錢包來了APP
- 6 個開源的數字貨幣錢包
- 數字貨幣TP錢包/ImToken錢包/MetaMask小狐狸錢包系統開發(開發流程)丨原始碼分析原始碼
- 以太坊錢包開發系列2 - 賬號Keystore檔案匯入匯出
- 使用者錢包(賬戶)設計
- 數字資產多幣種跨鏈錢包開發錢包交易系統開發
- 鏈塔智庫:2019數字錢包研究報告
- 區塊鏈數字錢包系統開發方案區塊鏈
- 區塊鏈數字錢包系統開發方案,去中化多幣種錢包搭建區塊鏈
- Steam修改遊戲啟用規則 啟用碼必須與賬號錢包區域一致遊戲
- 如何開發元宇宙虛擬數字錢包系統?元宇宙
- 如何識別真假區塊鏈數字錢包資產?區塊鏈
- 區塊鏈數字錢包開發詳細介紹區塊鏈
- 區塊鏈錢包系統開發,數字貨幣高頻搬磚錢包app開發區塊鏈APP
- Python 比特幣教程第三課: 建立比特幣錢包,讀餘額,極速免費轉賬,標準轉賬Python比特幣
- copay錢包(3.轉賬功能報文分析)
- 數字資產多幣種錢包交易所開發
- 使用 PHP 生成以太坊錢包和金鑰對PHP
- 如何在Java中生成比特幣錢包地址Java比特幣
- 區塊鏈100講:EOS環境搭建入門(私鏈節點-錢包-金鑰-賬號)區塊鏈
- GITHUB賬號註冊、提交、下載、建立分支Github
- EOS開發完全解析(三):EOS賬號建立
- mongo 監控備份業務賬號建立Go
- 為了弄清起點小說如何算字扣錢,我特意註冊了作家賬號
- 蘋果企業開發者賬號賣多少錢蘋果
- Plustoken智慧合約數字錢包系統技術開發原理
- 區塊鏈技術數字貨幣錢包開發哪家好區塊鏈
- 數字貨幣錢包系統開發平臺技術搭建