-
Notifications
You must be signed in to change notification settings - Fork 10
/
encryption.js
152 lines (124 loc) · 3.48 KB
/
encryption.js
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import CryptoJS from "crypto-js";
import uuidv4 from "uuid/v4";
import { sha3_256 } from "js-sha3";
import forge from "node-forge";
// can't import iota from services/iota because the iota.lib.js tries to run
// curl.init() during the unit tests
import iotaUtils from "iota.lib.js/lib/utils/asciiToTrytes";
import _ from "lodash";
// an eth private seed key is 64 characters, the treasure prefix is 20 characters,
// and our tags are 32 characters
const PAYLOAD_LENGTH = 64;
const NONCE_LENGTH = 24;
const TAG_LENGTH = 32;
const TREASURE_PREFIX = _.split("Treasure: ", "")
.map(char => {
return char.charCodeAt(char).toString(16);
})
.join("");
const parseEightCharsOfFilename = fileName => {
fileName = fileName + "________";
fileName = fileName.substr(0, 8);
return fileName;
};
const getSalt = numChars => {
let array = new Uint32Array(1);
window.crypto.getRandomValues(array);
let salt = array[0];
return salt.toString(36).substr(2, numChars);
};
const getPrimordialHash = () => {
const entropy = uuidv4();
return CryptoJS.SHA256(entropy).toString();
};
const obfuscate = hash => CryptoJS.SHA384(hash).toString();
// Returns [obfuscatedHash, nextHash]
const hashChain = hash => {
const obfuscatedHash = CryptoJS.SHA384(hash).toString();
const nextHash = CryptoJS.SHA256(hash).toString();
return [obfuscatedHash, nextHash];
};
// Genesis hash is not yet obfuscated.
const genesisHash = handle => {
const [_obfuscatedHash, genHash] = hashChain(handle);
return genHash;
};
const sideChain = address => sha3_256(address).toString();
const decryptTest = (text, secretKey) => {
//TODO temporary for debugging
try {
return CryptoJS.AES.decrypt(text, secretKey).toString();
} catch (e) {
return "";
}
};
const encrypt = (key, secret, nonce) => {
let nonceInBytes = forge.util.hexToBytes(nonce.substring(0, NONCE_LENGTH));
const cipher = forge.cipher.createCipher(
"AES-GCM",
forge.util.hexToBytes(key)
);
cipher.start({
iv: nonceInBytes,
output: null
});
cipher.update(forge.util.createBuffer(forge.util.hexToBytes(secret)));
cipher.finish();
const encrypted = cipher.output;
const tag = cipher.mode.tag;
return encrypted.toHex() + tag.toHex();
};
const decryptTreasure = (
sideChainHash,
signatureMessageFragment,
sha256Hash
) => {
const hexMessage = forge.util.bytesToHex(
iotaUtils.fromTrytes(
signatureMessageFragment.substring(
0,
PAYLOAD_LENGTH + TAG_LENGTH + TREASURE_PREFIX.length
)
)
);
const decryptedValue = decrypt(sideChainHash, hexMessage, sha256Hash);
return _.startsWith(decryptedValue, TREASURE_PREFIX)
? _.replace(decryptedValue, TREASURE_PREFIX, "")
: false;
};
const decrypt = (key, secret, nonce) => {
let nonceInBytes = forge.util.hexToBytes(nonce.substring(0, NONCE_LENGTH));
const decipher = forge.cipher.createDecipher(
"AES-GCM",
forge.util.hexToBytes(key)
);
decipher.start({
iv: nonceInBytes,
output: null,
tag: forge.util.hexToBytes(
secret.substring(secret.length - TAG_LENGTH, secret.length)
)
});
decipher.update(
forge.util.createBuffer(
forge.util.hexToBytes(secret.substring(0, secret.length - TAG_LENGTH))
)
);
if (!decipher.finish()) {
return false;
}
return decipher.output.toHex();
};
export default {
decrypt,
decryptTest, //TODO
encrypt,
genesisHash,
getPrimordialHash,
getSalt,
hashChain,
obfuscate,
parseEightCharsOfFilename,
sideChain,
decryptTreasure
};