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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
const asmcrypto = require('asmcrypto.js')
const Unibabel = require('browserify-unibabel')
/**
* A Microsoft Edge-specific encryption class that exposes
* the interface expected by eth-keykeyring-controller
*/
class EdgeEncryptor {
/**
* Encrypts an arbitrary JavaScript object to cypher text
*
* @param {string} password Password used to unlock a cryptographic key
* @param {Object} dataObject Data to encrypt
* @returns {Object} Object containing cypher text, generation vectors, and salt
*/
encrypt (password, dataObject) {
var salt = this._generateSalt()
return this._keyFromPassword(password, salt)
.then(function (key) {
var data = JSON.stringify(dataObject)
var dataBuffer = Unibabel.utf8ToBuffer(data)
var vector = global.crypto.getRandomValues(new Uint8Array(16))
var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
var buffer = new Uint8Array(resultbuffer)
var vectorStr = Unibabel.bufferToBase64(vector)
var vaultStr = Unibabel.bufferToBase64(buffer)
return JSON.stringify({
data: vaultStr,
iv: vectorStr,
salt: salt,
})
})
}
/**
* Decrypts an arbitrary JavaScript object from cypher text
*
* @param {string} password Password used to unlock a cryptographic key
* @param {string} text Cypher text of an encrypted JavaScript object
* @returns {Promise<Object>} Promise resolving to copy of decrypted JavaScript object
*/
decrypt (password, text) {
const payload = JSON.parse(text)
const salt = payload.salt
return this._keyFromPassword(password, salt)
.then(function (key) {
const encryptedData = Unibabel.base64ToBuffer(payload.data)
const vector = Unibabel.base64ToBuffer(payload.iv)
return new Promise((resolve, reject) => {
var result
try {
result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
} catch (err) {
return reject(new Error('Incorrect password'))
}
const decryptedData = new Uint8Array(result)
const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
const decryptedObj = JSON.parse(decryptedStr)
resolve(decryptedObj)
})
})
}
/**
* Retrieves a cryptographic key using a password
*
* @private
* @param {string} password Password used to unlock a cryptographic key
* @param {string} salt Random base-64 data
* @returns {Promise<Object>} Promise resolving to a derived key
*/
_keyFromPassword (password, salt) {
var passBuffer = Unibabel.utf8ToBuffer(password)
var saltBuffer = Unibabel.base64ToBuffer(salt)
return new Promise((resolve) => {
var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
resolve(key)
})
}
/**
* Generates random base-64 encoded data
*
* @private
* @returns {string} Randomized base-64 encoded data
*/
_generateSalt (byteCount = 32) {
var view = new Uint8Array(byteCount)
global.crypto.getRandomValues(view)
var b64encoded = btoa(String.fromCharCode.apply(null, view))
return b64encoded
}
}
module.exports = EdgeEncryptor
|