OSDN Git Service

update and test the key logic
[bytom/Bytom-JS-SDK.git] / src / utils / key / keystore.js
1 let cryp = require('crypto-browserify');
2 let scrypt = require('scrypt-js');
3 import {XPrv} from './chainkd';
4 let sha3_256 = require('js-sha3').sha3_256;
5 import _ from 'lodash';
6
7 const scryptDKLen = 32;
8 const scryptR     = 8;
9
10 function encryptKey(key , auth, scryptN, scryptP){
11     let authArray = new Buffer(auth);
12     let salt = cryp.randomBytes(32);
13
14     let derivedKey = scrypt.syncScrypt(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen);
15
16     let encryptKey = derivedKey.slice(0, 16);
17     let keyBytes = key.xPrv;
18     let iv = cryp.randomBytes(16);
19
20
21     let cipherText = aesCTRXOR(encryptKey, keyBytes, iv);
22
23     let kdfparams = {
24         n:scryptN,
25         r:scryptR,
26         p:scryptP,
27         dklen:scryptDKLen,
28         salt:salt.toString('hex')
29     };
30
31     let mac = sha3_256(Buffer.concat([Buffer(derivedKey.slice(16, 32)), cipherText]));
32
33
34     return {
35         version: 1,
36         xpub:key.xPub.toString('hex'),
37         alias:key.alias,
38         type: key.keyType,
39         crypto: {
40             ciphertext: cipherText.toString('hex'),
41             cipherparams: {
42                 iv: iv.toString('hex')
43             },
44             cipher:  'aes-128-ctr',
45             kdf:  'scrypt',
46             kdfparams: kdfparams,
47             mac: mac.toString('hex')
48         }
49     };
50 }
51
52
53 function aesCTRXOR(key, inText, iv) {
54     let cipher = cryp.createCipheriv('aes-128-ctr', key, iv);
55
56     var ciphertext = Buffer.from([
57         ...cipher.update(Buffer.from(inText, 'hex')),
58         ...cipher.final()]
59     );
60
61
62     return ciphertext;
63 }
64
65 function decryptKey(v3Keystore, password){
66     if (!_.isString(password)) {
67         throw new Error('No password given.');
68     }
69
70     let   k = (_.isObject(v3Keystore)) ? v3Keystore : JSON.parse(v3Keystore);
71     const xprv = decrypt(k, password);
72     const _xprv = new XPrv(xprv)
73     const xpub = _xprv.XPub()
74
75     return {
76         xPrv:    xprv,
77         xPub:    xpub,
78         keyType: k.type,
79         alias:   k.alias,
80     };
81 }
82
83 function decrypt(json, password) {
84     var derivedKey;
85     var kdfparams;
86     if (json.crypto.kdf === 'scrypt') {
87         kdfparams = json.crypto.kdfparams;
88
89         // FIXME: support progress reporting callback
90         derivedKey = scrypt.syncScrypt(Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen);
91     } else if (json.crypto.kdf === 'pbkdf2') {
92         kdfparams = json.crypto.kdfparams;
93
94         if (kdfparams.prf !== 'hmac-sha256') {
95             throw new Error('Unsupported parameters to PBKDF2');
96         }
97
98         derivedKey = cryp.pbkdf2Sync(Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.c, kdfparams.dklen, 'sha3256');
99     } else {
100         throw new Error('Unsupported key derivation scheme');
101     }
102
103     var ciphertext = Buffer.from(json.crypto.ciphertext, 'hex');
104
105     var mac = sha3_256(Buffer.concat([Buffer(derivedKey.slice(16, 32)), ciphertext]));
106     if (mac !== json.crypto.mac) {
107         throw new Error('Key derivation failed - possibly wrong password');
108     }
109
110     var decipher = cryp.createDecipheriv(json.crypto.cipher, derivedKey.slice(0, 16), Buffer.from(json.crypto.cipherparams.iv, 'hex'));
111     var privateKey = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
112
113     return privateKey;
114 }
115
116
117 export{
118     encryptKey,
119     decryptKey
120 };