Introduce shadow logins

This commit is contained in:
Gregory Soutade
2015-02-09 18:57:49 +01:00
parent 636d403396
commit e9c6208b54
8 changed files with 316 additions and 133 deletions

View File

@@ -99,7 +99,7 @@ body {
}
#scorebar {
background-image: url(/ressources/bg_strength_gradient.jpg);
background-image: url(/resources/bg_strength_gradient.jpg);
background-repeat: no-repeat;
background-position: 0 0;
position:absolute;

View File

@@ -50,20 +50,21 @@ Element.prototype.removeAllChilds = function() {
this.removeChild(this.childNodes[0]);
};
function generate_password()
function generate_random(size, only_ascii)
{
// symbols 32 - 47 / 58 - 64 / 91 - 96 / 123 - 126
// numbers 48 - 57
// upper 65 - 90
// lower 97 - 122
// Give priority to letters (65 - 122 duplicated in front and end of array)
var symbols = new Array(65, 90, 97, 122, 40, 47, 48, 57, 65, 90, 97, 122, 123, 126, 65, 90, 97, 122);
field = document.getElementById("new_password");
var symbols;
if (only_ascii)
symbols = new Array(65, 90, 97, 122, 40, 47, 48, 57, 65, 90, 97, 122, 123, 126, 65, 90, 97, 122);
else
symbols = new Array(1, 255);
var res = "";
while (res.length < 16)
while (res.length < size)
{
a = Math.round(Math.random() * (symbols.length/2) * 2);
diff = symbols[a+1] - symbols[a];
@@ -73,7 +74,12 @@ function generate_password()
res += String.fromCharCode(r + symbols[a]);
}
field.value = res;
return res;
}
function generate_password()
{
document.getElementById("new_password").value = generate_random(16, true);
}
function url_domain(data) {
@@ -111,7 +117,7 @@ var passwords;
var current_user = "";
var current_mkey = "";
function PasswordEntry (ciphered_login, ciphered_password) {
function PasswordEntry (ciphered_login, ciphered_password, salt="", shadow_login="") {
this.ciphered_login = ciphered_login;
this.ciphered_password = ciphered_password;
this.unciphered = false;
@@ -119,6 +125,9 @@ function PasswordEntry (ciphered_login, ciphered_password) {
this.clear_login = "";
this.clear_password = "";
this.masterkey = "";
this.salt = salt;
this.shadow_login = shadow_login;
this.access_token = "";
this.decrypt = function(masterkey)
{
@@ -163,25 +172,43 @@ function PasswordEntry (ciphered_login, ciphered_password) {
{
return !(this.isUnciphered(masterkey));
}
this.shadow_login_to_access_token = function(masterkey)
{
var aes = new AES();
var key = pkdbf2(hex2a(masterkey), hex2a(this.salt), pkdbf2_level, 256/8);
var a_key = aes.init(hex2a(key));
this.access_token = aes.encryptLongString(hex2a(this.shadow_login), a_key);
this.access_token = a2hex(this.access_token);
aes.finish();
}
this.generate_access_token = function(masterkey)
{
this.salt = a2hex(generate_random(16, false));
this.shadow_login = a2hex(generate_random(16, false));
return this.shadow_login_to_access_token(masterkey);
}
}
function list_all_entries(user)
{
passwords = new Array();
req = new XMLHttpRequest();
req.addEventListener("load", function(evt) {
entries = this.responseText.split("\n");
if (entries[0] == "entries")
j = JSON.parse(this.responseText);
for(i=0; i<j.entries.length; i++)
{
for(i=1; i<entries.length; i++)
{
if (entries[i] == "") continue;
entry = entries[i].split(";");
passwords.push(new PasswordEntry(entry[0], entry[1]));
}
if (j.entries[i].hasOwnProperty('login'))
p = new PasswordEntry(j.entries[i].login, j.entries[i].password, "", "");
else
p = new PasswordEntry("", "", j.entries[i].salt, j.entries[i].shadow_login);
passwords.push(p);
}
}, false);
}
, false);
req.open("POST", document.documentURI, false);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
req.send("get_passwords=1&user=" + user);
@@ -219,16 +246,77 @@ function update_stats()
div.appendChild(document.createElement("br"));
}
// Remove all password without credentials
function put_ciphered_credentials(passwords, masterkey)
{
for(var i=0; i<passwords.length; i++)
{
passwords[i].generate_access_token(masterkey);
remove_password_server(current_user, passwords[i].ciphered_login, '');
add_password_server(current_user, passwords[i]);
}
}
function get_ciphered_credentials(masterkey)
{
access_tokens = '';
old_passwords = new Array();
for(var i=0; i<passwords.length; i++)
{
// Already got
if (passwords[i].ciphered_login.length)
{
if (!passwords[i].access_token.length)
old_passwords.push(passwords[i]);
continue;
}
passwords[i].shadow_login_to_access_token(masterkey);
if (access_tokens.length) access_tokens += ",";
access_tokens += passwords[i].access_token;
}
if (old_passwords.length)
put_ciphered_credentials(old_passwords, masterkey);
if (!access_tokens.length)
return;
req = new XMLHttpRequest();
req.addEventListener("load", function(evt) {
j = JSON.parse(this.responseText);
for(i=0; i<j.entries.length; i++)
{
for (k=0; k<passwords.length; k++)
{
if (passwords[k].access_token == j.entries[i].access_token)
{
passwords[k].ciphered_login = j.entries[i].login;
passwords[k].ciphered_password = j.entries[i].password;
break;
}
}
}
}, false);
req.open("POST", document.documentURI, false);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
req.send("get_secure_passwords=1&user=" + user + "&access_tokens=" + access_tokens);
}
function change_master_key(warning_unciphered)
{
var nb_unciphered = 0;
if (current_mkey.length && use_shadow_logins)
get_ciphered_credentials(current_mkey);
for(i=0; i<passwords.length; i++)
{
if (passwords[i].decrypt(current_mkey))
nb_unciphered++;
}
if (!nb_unciphered && warning_unciphered)
alert("No password unciphered with this master key !");
@@ -305,7 +393,6 @@ function change_master_key(warning_unciphered)
ciph_login = document.createElement("input");
ciph_login.setAttribute("name", "ciphered_login");
ciph_login.setAttribute("type", "hidden");
ciph_login.setAttribute("login", passwords[i].ciphered_login);
div.appendChild(ciph_login);
div.appendChild(document.createTextNode("URL"));
@@ -313,7 +400,6 @@ function change_master_key(warning_unciphered)
url.setAttribute("class", "hash");
url.setAttribute("type", "text");
url.setAttribute("name", "URL");
url.setAttribute("value", passwords[i].ciphered_login);
div.appendChild(url);
div.appendChild(document.createTextNode("password"));
@@ -321,7 +407,6 @@ function change_master_key(warning_unciphered)
password.setAttribute("class", "hash");
password.setAttribute("type", "text");
password.setAttribute("name", "password");
password.setAttribute("value", passwords[i].ciphered_password);
div.appendChild(password);
delete_button = document.createElement("input");
@@ -331,6 +416,19 @@ function change_master_key(warning_unciphered)
div.appendChild(delete_button);
password_div.appendChild(div);
if (passwords[i].ciphered_login.length)
{
ciph_login.setAttribute("login", passwords[i].ciphered_login);
url.setAttribute("value", passwords[i].ciphered_login);
password.setAttribute("value", passwords[i].ciphered_password);
}
else
{
ciph_login.setAttribute("login", passwords[i].shadow_login);
url.setAttribute("value", passwords[i].shadow_login);
// password empty
}
}
}
@@ -393,7 +491,7 @@ function add_password_server(user, pentry)
}, false);
req.open("POST", document.documentURI, false);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
req.send("add_entry=1&user=" + user + "&login=" + pentry.ciphered_login + "&password=" + pentry.ciphered_password);
req.send("add_entry=1&user=" + user + "&login=" + pentry.ciphered_login + "&password=" + pentry.ciphered_password + "&shadow_login=" + pentry.shadow_login + "&salt=" + pentry.salt + "&access_token=" + pentry.access_token);
return ok;
}
@@ -445,12 +543,7 @@ function construct_pentry(user, url, password, login, mkey, derive_masterkey)
ciphered_login = "@@" + url + ";" + login;
// Add salt
for(i=0; i<3; i++)
{
password += String.fromCharCode((Math.random() * 128)+1);
}
ciphered_password = password;
ciphered_password = password + generate_random(3, false);
aes = new AES();
a_masterkey = aes.init(hex2a(mkey));
@@ -461,13 +554,15 @@ function construct_pentry(user, url, password, login, mkey, derive_masterkey)
pentry.unciphered = true;
pentry.clear_url = url;
pentry.clear_login = login;
pentry.clear_password = password.substr(0, password.length-3);
pentry.clear_password = password;
pentry.masterkey = mkey;
if (use_shadow_logins)
pentry.generate_access_token(mkey);
return pentry;
}
function remove_password_server(user, login)
function remove_password_server(user, login, access_token)
{
var ok = false;
@@ -481,7 +576,7 @@ function remove_password_server(user, login)
}, false);
req.open("POST", document.documentURI, false);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
req.send("delete_entry=1&user=" + user + "&login=" + login);
req.send("delete_entry=1&user=" + user + "&login=" + login + "&access_token=" + access_token);
return ok;
}
@@ -579,7 +674,7 @@ function delete_entry(entry_number)
if(!confirm("Are you sure want to delete this entry ?"))
return;
ok = remove_password_server(current_user, ciphered_login.getAttribute("login"));
ok = remove_password_server(current_user, ciphered_login.getAttribute("login"), passwords[i].access_token);
if (!ok) return;
@@ -644,7 +739,7 @@ function update_entry(entry_number)
if (pentry == null) return;
ok = remove_password_server(current_user, passwords[found].ciphered_login);
ok = remove_password_server(current_user, passwords[found].ciphered_login, passwords[found].access_token);
if (!ok) return;
ok = add_password_server(current_user, pentry);