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
|
import sodium from 'libsodium-wrappers';
export default class PWDv1Challenge {
constructor(data) {
this._salts = null;
if(data.hasOwnProperty('salts')) {
this._salts = data.salts;
}
this._password = null;
}
/**
*
* @returns {null}
*/
getPassword() {
return this._password;
}
/**
*
* @param value
* @returns {PWDv1Challenge}
*/
setPassword(value) {
this._password = value;
return this;
}
/**
* Generate a challenge solution with the user provided password
* and the server provided salts
*
* @returns {string}
*/
solve() {
if(this._password.length < 12) throw new Error('Password is too short');
if(this._password.length > 128) throw new Error('Password is too long');
let salts = this._salts;
let passwordSalt = sodium.from_hex(salts[0]),
genericHashKey = sodium.from_hex(salts[1]),
passwordHashSalt = sodium.from_hex(salts[2]),
genericHash = sodium.crypto_generichash(
sodium.crypto_generichash_BYTES_MAX,
new Uint8Array([...sodium.from_string(this._password), ...passwordSalt]),
genericHashKey
);
let passwordHash = sodium.crypto_pwhash(
sodium.crypto_box_SEEDBYTES,
genericHash,
passwordHashSalt,
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
sodium.crypto_pwhash_ALG_DEFAULT
);
return sodium.to_hex(passwordHash);
}
/**
* Create the salts and the secret for the server
* using the user provided password
*
* @returns {{salts: *[], secret: *}}
*/
create() {
if(this._password.length < 12) throw new Error('Password is too short');
if(this._password.length > 128) throw new Error('Password is too long');
let passwordSalt = sodium.randombytes_buf(256),
genericHashKey = sodium.randombytes_buf(sodium.crypto_generichash_KEYBYTES_MAX),
genericHash = sodium.crypto_generichash(
sodium.crypto_generichash_BYTES_MAX,
new Uint8Array([...sodium.from_string(this._password), ...passwordSalt]),
genericHashKey
);
let passwordHashSalt = sodium.sodium(sodium.crypto_pwhash_SALTBYTES),
passwordHash = sodium.crypto_pwhash(
sodium.crypto_box_SEEDBYTES,
genericHash,
passwordHashSalt,
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
sodium.crypto_pwhash_ALG_DEFAULT
);
return {
salts : [
sodium.to_hex(passwordSalt),
sodium.to_hex(genericHashKey),
sodium.to_hex(passwordHashSalt)
],
secret: sodium.to_hex(passwordHash)
}
}
}
|