Skip to content

Commit 365dab5

Browse files
authored
Use secure RNG to generate passwords (hestiacp#2726)
* use secure rng to generate passwords quoting MDN: >Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead My rng is kinda shitty, i know there is some fast way to cut down higher digits to get a digit in range without introducing bias, but i also know that other people have introduced bias by trying to do that on an initially secure rng and getting it wrong (iirc it's discussed here? https://www.youtube.com/watch?v=LDPMpc-ENqY - been years since i saw the talk, but i know Lavavej discussed it in one of his presentations, i think it was that one) , but anyway this is fast enough, and secure. * shorter name * randomString2 / centralize js string generation * missed 2
1 parent 41518aa commit 365dab5

File tree

10 files changed

+89
-139
lines changed

10 files changed

+89
-139
lines changed

web/js/init.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,64 @@ $(document).ready(function(){
615615
});
616616
});
617617

618+
/**
619+
* generates a random string
620+
* using a cryptographically secure rng,
621+
* and ensuring it contains at least 1 lowercase, 1 uppercase, and 1 number.
622+
*
623+
* @param int length
624+
* @throws Error if length is too small to create a "sufficiently secure" string
625+
* @returns string
626+
*/
627+
function randomString2(length = 16) {
628+
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
629+
var secure_rng = function (min, max) {
630+
if (min < 0 || min > 0xffff) {
631+
throw new Error(
632+
"minimum supported number is 0, this generator can only make numbers between 0-65535 inclusive."
633+
);
634+
}
635+
if (max > 0xffff || max < 0) {
636+
throw new Error(
637+
"max supported number is 65535, this generator can only make numbers between 0-65535 inclusive."
638+
);
639+
}
640+
if (min > max) {
641+
throw new Error("dude min>max wtf");
642+
}
643+
// micro-optimization
644+
let randArr = max > 255 ? new Uint16Array(1) : new Uint8Array(1);
645+
let ret;
646+
let attempts = 0;
647+
for (;;) {
648+
crypto.getRandomValues(randArr);
649+
ret = randArr[0];
650+
if (ret >= min && ret <= max) {
651+
return ret;
652+
}
653+
++attempts;
654+
if (attempts > 1000000) {
655+
// should basically never happen with max 0xFFFF/Uint16Array.
656+
throw new Error("tried a million times, something is wrong");
657+
}
658+
}
659+
};
660+
let attempts = 0;
661+
let minimumStrengthRegex = new RegExp(
662+
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/
663+
);
664+
let randmax = chars.length - 1;
665+
for (;;) {
666+
let ret = "";
667+
for (let i = 0; i < length; ++i) {
668+
ret += chars[secure_rng(0, randmax)];
669+
}
670+
if (minimumStrengthRegex.test(ret)) {
671+
return ret;
672+
}
673+
++attempts;
674+
if (attempts > 1000000) {
675+
throw new Error("tried a million times, something is wrong");
676+
}
677+
}
678+
};

web/js/pages/add_db.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,7 @@ App.Listeners.DB.keypress_v_password();
8888
App.Listeners.DB.keypress_db_username();
8989
App.Listeners.DB.keypress_db_databasename();
9090

91-
randomString = function(min_length = 16) {
92-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
93-
var string_length = min_length;
94-
var randomstring = '';
95-
for (var i = 0; i < string_length; i++) {
96-
var rnum = Math.floor(Math.random() * chars.length);
97-
randomstring += chars.substr(rnum, 1);
98-
}
99-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
100-
if(!regex.test(randomstring)){
101-
randomString();
102-
}else{
103-
$('input[name=v_password]').val(randomstring);
91+
randomString = function(min_length = 16) {
92+
$('input[name=v_password]').val(randomString2(min_length));
10493
App.Actions.DB.update_v_password();
105-
}
10694
}

web/js/pages/add_mail_acc.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,26 +115,14 @@ App.Listeners.MAIL_ACC.keypress_v_password();
115115

116116

117117
randomString = function(min_length = 16) {
118-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
119-
var string_length = min_length;
120-
var randomstring = '';
121-
for (var i = 0; i < string_length; i++) {
122-
var rnum = Math.floor(Math.random() * chars.length);
123-
randomstring += chars.substr(rnum, 1);
124-
}
125-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
126-
if(!regex.test(randomstring)){
127-
randomString();
128-
}else{
118+
var randomstring = randomString2(min_length);
129119
$('input[name=v_password]').val(randomstring);
130120
if($('input[name=v_password]').attr('type') == 'text')
131121
$('#v_password').text(randomstring);
132122
else
133-
$('#v_password').text(Array(randomstring.length+1).join('*'));
134-
123+
$('#v_password').text(Array(randomstring.length+1).join('*'));s
135124
App.Actions.MAIL_ACC.update_v_password();
136125
generate_mail_credentials();
137-
}
138126
}
139127

140128
generate_mail_credentials = function() {

web/js/pages/add_user.js

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,10 @@ $(function() {
1414
});
1515

1616

17-
randomString = function(min_length = 16) {
18-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
19-
var string_length = min_length;
20-
var randomstring = '';
21-
for (var i = 0; i < string_length; i++) {
22-
var rnum = Math.floor(Math.random() * chars.length);
23-
randomstring += chars.substr(rnum, 1);
24-
}
25-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
26-
if(!regex.test(randomstring)){
27-
randomString();
28-
}else{
29-
$('input[name=v_password]').val(randomstring);
30-
App.Actions.WEB.update_v_password();
31-
}
32-
}
17+
randomString = function (min_length = 16) {
18+
$("input[name=v_password]").val(randomString2(min_length));
19+
App.Actions.WEB.update_v_password();
20+
};
3321

3422
App.Actions.WEB.update_v_password = function (){
3523
var password = $('input[name="v_password"]').val();

web/js/pages/add_web.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -237,24 +237,11 @@ $(function() {
237237

238238

239239
function WEBrandom() {
240-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
241-
var string_length = 16;
242-
var webrandom = '';
243-
for (var i = 0; i < string_length; i++) {
244-
var rnum = Math.floor(Math.random() * chars.length);
245-
webrandom += chars.substr(rnum, 1);
246-
}
247-
document.v_add_web.v_stats_password.value = webrandom;
240+
document.v_add_web.v_stats_password.value = randomString2(16);
248241
}
249242

250243
function FTPrandom(elm) {
251-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
252-
var string_length = 16;
253-
var ftprandomstring = '';
254-
for (var i = 0; i < string_length; i++) {
255-
var rnum = Math.floor(Math.random() * chars.length);
256-
ftprandomstring += chars.substr(rnum, 1);
257-
}
244+
var ftprandomstring = randomString2(16);
258245
$(elm).parents('.ftptable').find('.v-ftp-user-psw').val(ftprandomstring);
259246
}
260247

web/js/pages/edit_db.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,8 @@ App.Listeners.DB.keypress_db_databasename();
9494

9595

9696
randomString = function(min_length = 16) {
97-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
98-
var string_length = min_length;
99-
var randomstring = '';
100-
for (var i = 0; i < string_length; i++) {
101-
var rnum = Math.floor(Math.random() * chars.length);
102-
randomstring += chars.substr(rnum, 1);
103-
}
104-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
105-
if(!regex.test(randomstring)){
106-
randomString();
107-
}else{
108-
$('input[name=v_password]').val(randomstring);
109-
App.Actions.DB.update_v_password();
110-
}
97+
$('input[name=v_password]').val(randomString2(min_length));
98+
App.Actions.DB.update_v_password();
11199
}
112100

113101

web/js/pages/edit_mail_acc.js

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,28 +93,17 @@ $('#v_blackhole').on('click', function(evt){
9393
App.Listeners.MAIL_ACC.keypress_v_password();
9494

9595

96-
randomString = function(min_length = 16) {
97-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
98-
var string_length = min_length;
99-
var randomstring = '';
100-
for (var i = 0; i < string_length; i++) {
101-
var rnum = Math.floor(Math.random() * chars.length);
102-
randomstring += chars.substr(rnum, 1);
103-
}
104-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
105-
if(!regex.test(randomstring)){
106-
randomString();
107-
}else{
108-
$('input[name=v_password]').val(randomstring);
109-
if($('input[name=v_password]').attr('type') == 'text')
110-
$('#v_password').text(randomstring);
111-
else
112-
$('#v_password').text(Array(randomstring.length+1).join('*'));
113-
114-
App.Actions.MAIL_ACC.update_v_password();
115-
generate_mail_credentials();
116-
}
117-
}
96+
randomString = function (min_length = 16) {
97+
var randomstring = randomString2(min_length);
98+
$("input[name=v_password]").val(randomstring);
99+
if ($("input[name=v_password]").attr("type") == "text")
100+
$("#v_password").text(randomstring);
101+
else
102+
$("#v_password").text(Array(randomstring.length + 1).join("*"));
103+
App.Actions.MAIL_ACC.update_v_password();
104+
generate_mail_credentials();
105+
};
106+
118107
generate_mail_credentials = function() {
119108
var div = $('.mail-infoblock').clone();
120109
div.find('#mail_configuration').remove();

web/js/pages/edit_user.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
11
randomString = function(min_length = 16) {
2-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
3-
var string_length = min_length;
4-
var randomstring = '';
5-
for (var i = 0; i < string_length; i++) {
6-
var rnum = Math.floor(Math.random() * chars.length);
7-
randomstring += chars.substr(rnum, 1);
8-
}
9-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
10-
if(!regex.test(randomstring)){
11-
randomString();
12-
}else{
13-
$('input[name=v_password]').val(randomstring);
2+
$('input[name=v_password]').val(randomString2(min_length));
143
App.Actions.WEB.update_v_password();
15-
}
164
}
175

186
App.Actions.WEB.update_v_password = function (){

web/js/pages/edit_web.js

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -276,26 +276,11 @@ $(function() {
276276
});
277277

278278
function WEBrandom() {
279-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
280-
var string_length = 16;
281-
var webrandom = '';
282-
for (var i = 0; i < string_length; i++) {
283-
var rnum = Math.floor(Math.random() * chars.length);
284-
webrandom += chars.substr(rnum, 1);
285-
}
286-
document.v_edit_web.v_stats_password.value = webrandom;
279+
document.v_edit_web.v_stats_password.value = randomString2(16);
287280
}
288281

289282
function FTPrandom(elm) {
290-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
291-
var string_length = 16;
292-
var ftprandomstring = '';
293-
for (var i = 0; i < string_length; i++) {
294-
var rnum = Math.floor(Math.random() * chars.length);
295-
ftprandomstring += chars.substr(rnum, 1);
296-
}
297-
298-
$(elm).parents('.ftptable').find('.v-ftp-user-psw').val(ftprandomstring);
283+
$(elm).parents('.ftptable').find('.v-ftp-user-psw').val(randomString2(16));
299284
App.Actions.WEB.randomPasswordGenerated && App.Actions.WEB.randomPasswordGenerated(elm);
300285
}
301286

web/js/pages/setup_webapp.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,4 @@
11
randomString = function(target, min_length = 16) {
2-
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
3-
var string_length = min_length;
4-
var randomstring = '';
5-
for (var i = 0; i < string_length; i++) {
6-
var rnum = Math.floor(Math.random() * chars.length);
7-
randomstring += chars.substr(rnum, 1);
8-
}
9-
var regex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\d)[a-zA-Z\d]{8,}$/);
10-
if(!regex.test(randomstring)){
11-
randomString();
12-
}else{
13-
elm = document.getElementById(target);
14-
$(elm).val(randomstring);
15-
}
2+
elm = document.getElementById(target);
3+
$(elm).val(randomString2(min_length));
164
}

0 commit comments

Comments
 (0)