-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathv2.js
89 lines (76 loc) · 2.42 KB
/
v2.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
const secrets = require('secrets.js-grempe')
const sodium = require('sodium-native')
const isString = require('./isString')
const MAC_LENGTH = 32
module.exports = {
pack: function packV2 (secret, label) {
return JSON.stringify([secret, label])
},
unpack: function unpackV2 (secret) {
let arr
try {
arr = JSON.parse(secret)
if ((arr.length !== 2) || (!arr.every(isString))) return false
} catch (err) {
return false
}
return { secret: arr[0], label: arr[1] }
},
share: function shareV2 (secret, numOfShards, quorum) {
const shardsHex = secrets.share(secret2Hex(secret), numOfShards, quorum)
return shardsHex.map(compress)
},
combine: function combineV2 (shards) {
// this could probably be improved by checking the hash before converting to hex
const hex = secrets.combine(shards.map(decompress))
return hex2Secret(hex)
},
verify: function verifyV2 (shards) {
const hex = secrets.combine(shards.map(decompress))
const secret = secrets.hex2str(hex.slice(MAC_LENGTH))
if (Mac(secret) !== mac(hex)) return false
else return true
},
validateShard: function validateShardV2 (shard) {
try {
secrets.extractShareComponents(decompress(shard))
} catch (err) {
return false
}
return true
}
}
// helpers which prepare a secret ready for sharding, and also manage the MAC
// TODO - could be better names
// secret-specific mac
function mac (hex) {
return hex.slice(0, MAC_LENGTH)
}
function secret2Hex (string) {
return Mac(string) + secrets.str2hex(string)
}
function hex2Secret (hex) {
const mac = hex.slice(0, MAC_LENGTH)
const secret = secrets.hex2str(hex.slice(MAC_LENGTH))
if (Mac(secret) !== mac) throw new Error('This secret appears to be corrupt - invalid MAC')
else return secret
}
// supposedly 'original' mac
function Mac (secret) {
var hash = Buffer.alloc(sodium.crypto_hash_sha256_BYTES)
sodium.crypto_hash_sha256(hash, Buffer.from(secret))
return hash
.toString('hex')
.slice(-1 * MAC_LENGTH)
}
// compress shards by using denser encoding
function compress (shard) {
const shardData = shard.slice(3)
const shardDataBase64 = Buffer.from(shardData, 'hex').toString('base64')
return shard.slice(0, 3) + shardDataBase64
}
function decompress (shard) {
const shardData = shard.slice(3)
const shardDataHex = Buffer.from(shardData, 'base64').toString('hex')
return shard.slice(0, 3) + shardDataHex
}