OSDN Git Service

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