Introduce shadow logins
This commit is contained in:
		| @@ -47,7 +47,7 @@ if ($PKDBF2_LEVEL != 1000) | ||||
|  | ||||
| for ($i=0; isset($_POST["k$i"]); $i++) | ||||
| { | ||||
|     $statement->bindValue(":login", $_POST["k$i"]); | ||||
|     $statement->bindValue(":login", addslashes($_POST["k$i"])); | ||||
|     $result = $statement->execute(); | ||||
|     $row = $result->fetchArray(SQLITE3_ASSOC); | ||||
|     $result->finalize(); | ||||
|   | ||||
| @@ -38,4 +38,26 @@ $ADMIN_MODE=true; | ||||
|   this value with existings masterkeys, they will unusable ! | ||||
|  */ | ||||
| $PKDBF2_LEVEL=1000; | ||||
|  | ||||
| /* | ||||
|   This is a security feature : It protects from database dump | ||||
|   and database purge without authentication. | ||||
|   When get all entries, instead of returning logins/passwords, | ||||
|   it returns "shadow logins". These are random values. | ||||
|   Shadow logins must be encrypted using masterkey and salt | ||||
|   (to generate a unique PKDBF2 derivation) that result in an access tokens. | ||||
|   With this access token, user has the right to get | ||||
|   encrypted login/password values and remove them. | ||||
|   It's a kind of challenge. | ||||
|  | ||||
|   This option is backward compatible with old version < 0.6, but | ||||
|   once activated it cannot be reverted as access tokens will be | ||||
|   generated for all values. So, if you want to test it, make | ||||
|   a copy of your databases before ! | ||||
|  | ||||
|   For now it's deactivated because it requires high cpu bandwidth | ||||
|   (one derivation + two decryption for each password !). When | ||||
|   standard crypto API will be stable it will be enabled by default. | ||||
| */ | ||||
| $USE_SHADOW_LOGINS=0; | ||||
| ?> | ||||
| @@ -28,72 +28,11 @@ | ||||
|  */ | ||||
| $MAX_ENTRY_LEN = 512; | ||||
| $USERS_PATH = "./users/"; | ||||
| $TARGET_DB_VERSION = 1; | ||||
|  | ||||
| function open_crypto($mkey) | ||||
| function sanitize($val) | ||||
| { | ||||
|     if (!isset($_SESSION['td'])) | ||||
|     { | ||||
|         $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); | ||||
|  | ||||
|         if ($td == false) | ||||
|             die("Unable to open mcrypt"); | ||||
|  | ||||
|         $ret = mcrypt_generic_init($td, hex2bin($mkey), '0000000000000000'); | ||||
|  | ||||
|         if ($ret < 0) | ||||
|         { | ||||
|             echo "<div class=\"error\">Unable to set key $ret</div>"; | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         $_SESSION['td'] = $td; | ||||
|     } | ||||
|     else | ||||
|         $td = $_SESSION['td']; | ||||
|  | ||||
|     return $td; | ||||
| } | ||||
|  | ||||
| function decrypt($mkey, $val, $salted) | ||||
| { | ||||
|     $td = open_crypto($mkey); | ||||
|  | ||||
|     if ($td == null) return; | ||||
|  | ||||
|     $val = mdecrypt_generic($td, hex2bin($val)); | ||||
|  | ||||
|     // Remove 0 added by encrypt | ||||
|     $val = str_replace("\0", '', $val); | ||||
|  | ||||
|     // Remove salt | ||||
|     if ($salted) | ||||
|         $val = substr($val, 0, strlen($val)-3); | ||||
|      | ||||
|     return $val; | ||||
| } | ||||
|  | ||||
| function encrypt($mkey, $val, $salted) | ||||
| { | ||||
|     global $MAX_ENTRY_LEN; | ||||
|  | ||||
|     $td = open_crypto($mkey); | ||||
|  | ||||
|     if ($td == null) return; | ||||
|  | ||||
|     if ($salted) | ||||
|     { | ||||
|         $val .= dechex(rand(256,4095)); //between 0x100 and 0xfff | ||||
|     } | ||||
|  | ||||
|     $val = mcrypt_generic($td, $val); | ||||
|  | ||||
|     if (strlen($val) > $MAX_ENTRY_LEN) | ||||
|     { | ||||
|         echo "<div class=\"error\">Value to encrypt is too long</div>"; | ||||
|         return null; | ||||
|     } | ||||
|      | ||||
|     return bin2hex($val); | ||||
|     return (isset($_POST[$val])) ? addslashes($_POST[$val]) : ""; | ||||
| } | ||||
|  | ||||
| // From http://php.net/manual/en/function.copy.php | ||||
| @@ -147,6 +86,45 @@ function create_user($user) | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| function _migrate_0($user, $db) | ||||
| { | ||||
|     try { | ||||
|         $db->query("ALTER TABLE gpass ADD access_token VARCHAR(32)"); | ||||
|         $db->query("ALTER TABLE gpass ADD shadow_login VARCHAR(32)"); | ||||
|         $db->query("ALTER TABLE gpass ADD salt VARCHAR(32)"); | ||||
|  | ||||
|         $db->query("CREATE TABLE db_version(version INTEGER)"); | ||||
|         $db->query("INSERT INTO db_version (version) VALUES (1)"); | ||||
|     } | ||||
|     catch(Exception $e) | ||||
|     { | ||||
|         $db->close(); | ||||
|         echo "<div class=\"error\">Unable to load database for user $user ! : $e</div>"; | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| function migrate_database($user, $db) | ||||
| { | ||||
|     global $TARGET_DB_VERSION; | ||||
|  | ||||
|     $migration_functions = ['_migrate_0']; | ||||
|  | ||||
|     $version = $db->querySingle("SELECT version FROM db_version"); | ||||
|     if ($version == false) | ||||
|         $version = 0; | ||||
|  | ||||
|     for($i=$version; $i<$TARGET_DB_VERSION; $i++) | ||||
|     { | ||||
|         if ($migration_functions[$i]($user, $db)) | ||||
|             return -1; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| function load_database($user) | ||||
| { | ||||
|     global $USERS_PATH; | ||||
| @@ -160,13 +138,17 @@ function load_database($user) | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     if (migrate_database($user, $db)) | ||||
|         return null; | ||||
|  | ||||
|     // New access need to reset crypto | ||||
|     unset($_SESSION['td']); | ||||
|  | ||||
|     return $db; | ||||
| } | ||||
|  | ||||
| function add_entry($user, $login, $password) | ||||
| function add_entry($user, $login, $password, | ||||
|                    $shadow_login, $salt, $access_token) | ||||
| { | ||||
|     $db = load_database($user); | ||||
|  | ||||
| @@ -184,8 +166,11 @@ function add_entry($user, $login, $password) | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     $result = $db->query("INSERT INTO gpass ('login', 'password') VALUES ('" . $login . "', '" . $password . "')"); | ||||
|     $result = $db->query("INSERT INTO gpass ('login', 'password', 'shadow_login', 'salt', 'access_token') VALUES | ||||
|  ('" . $login . "', '" . $password . "', '" . $shadow_login . "', '" . $salt . "', '" . $access_token . "')"); | ||||
|  | ||||
|     error_log("INSERT INTO gpass ('login', 'password', 'shadow_login', 'salt', 'access_token') VALUES | ||||
|  ('" . $login . "', '" . $password . "', '" . $shadow_login . "', '" . $salt . "', '" . $access_token . "')"); | ||||
|     $db->close(); | ||||
|  | ||||
|     echo "OK"; | ||||
| @@ -193,7 +178,7 @@ function add_entry($user, $login, $password) | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| function delete_entry($user, $login) | ||||
| function delete_entry($user, $login, $access_token) | ||||
| { | ||||
|     $db = load_database($user); | ||||
|  | ||||
| @@ -203,19 +188,26 @@ function delete_entry($user, $login) | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     $db->query("DELETE FROM gpass WHERE login='" . $login . "'"); | ||||
|  | ||||
|     $db->close(); | ||||
|  | ||||
|     echo "OK"; | ||||
|  | ||||
|     return true; | ||||
|     $db_ac = $db->querySingle("SELECT access_token FROM gpass WHERE login='" . $login . "'"); | ||||
|     if (strlen($db_ac) != 0 && strcmp($db_ac, $access_token)) | ||||
|     { | ||||
|         $db->close(); | ||||
|         echo "Bad access token"; | ||||
|         return false; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         $db->query("DELETE FROM gpass WHERE login='" . $login . "'"); | ||||
|         $db->close(); | ||||
|         echo "OK"; | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
|  | ||||
| function update_entry($user, $mkey, $old_login, $url, $login, $password) | ||||
| function update_entry($user, $mkey, $old_login, $url, $login, $password, $shadow_login, $salt, $old_access_token, $new_access_token) | ||||
| { | ||||
|     if (delete_entry($user, $old_login)) | ||||
|         return add_entry($user, $mkey, $url, $login, $password); | ||||
|     if (delete_entry($user, $old_login, $old_access_token)) | ||||
|         return add_entry($user, $mkey, $url, $login, $password, $shadow_login, $salt, $new_access_token); | ||||
|  | ||||
|     return false; | ||||
| } | ||||
| @@ -228,12 +220,60 @@ function list_entries($user) | ||||
|  | ||||
|     $result = $db->query("SELECT * FROM gpass"); | ||||
|  | ||||
|     echo "entries\n"; | ||||
|     $first = false; | ||||
|     header('Content-Type: application/json'); | ||||
|     echo "{ \"entries\" : [\n"; | ||||
|  | ||||
|     while (($row = $result->fetchArray())) | ||||
|     { | ||||
|         echo $row['login'] . ";" . $row['password'] . "\n"; | ||||
|         if ($first) echo ","; | ||||
|         else $first = true; | ||||
|         if (!strlen($row['shadow_login'])) | ||||
|             echo "{\"login\" : \"" . $row['login'] . "\", \"password\" : \"" . $row['password'] . "\" }\n"; | ||||
|         else | ||||
|             echo "{\"shadow_login\" : \"" . $row['shadow_login'] . "\", \"salt\" : \"" . $row['salt'] . "\" }\n"; | ||||
|     } | ||||
|  | ||||
|     echo "]}"; | ||||
|  | ||||
|     $db->close(); | ||||
| } | ||||
|  | ||||
| function get_secure_entries($user, $access_tokens) | ||||
| { | ||||
|     $db = load_database($user); | ||||
|  | ||||
|     if ($db == null) return; | ||||
|  | ||||
|     $query = "SELECT access_token, login, password FROM gpass WHERE access_token IN ("; | ||||
|     $first = false; | ||||
|  | ||||
|     foreach (preg_split("/,/", $access_tokens) as $ac) | ||||
|     { | ||||
|         /* error_log($ac); */ | ||||
|         if ($first) $query .= ", "; | ||||
|         else $first = true; | ||||
|         $query .= "'$ac'"; | ||||
|     } | ||||
|     $query .= ")"; | ||||
|  | ||||
|     error_log($query); | ||||
|     $result = $db->query($query); | ||||
|  | ||||
|     header('Content-Type: application/json'); | ||||
|     $first = false; | ||||
|     echo "{ \"entries\" : [\n"; | ||||
|  | ||||
|     while (($row = $result->fetchArray())) | ||||
|     { | ||||
|         if ($first) echo ","; | ||||
|         else $first = true; | ||||
|         echo "{\"access_token\" : \"" . $row['access_token'] . "\", \"login\" : \"" . $row['login'] . "\", \"password\" : \"" . $row['password'] . "\" }\n"; | ||||
|     } | ||||
|  | ||||
|     echo "]}"; | ||||
|  | ||||
|     $db->close(); | ||||
| } | ||||
|  | ||||
| ?> | ||||
| @@ -24,25 +24,49 @@ include('conf.php'); | ||||
|  | ||||
| session_start(); | ||||
|  | ||||
| $user = ""; | ||||
| $user = ''; | ||||
|  | ||||
| if ($ADMIN_MODE && isset($_POST['create_user'])) | ||||
| { | ||||
|     if (create_user($_POST['user'])) | ||||
|     $user = addslashes($_POST['user']); | ||||
|     if (create_user($user)) | ||||
|         $user = $_POST['user']; | ||||
|     else | ||||
|         $user = ''; | ||||
| } | ||||
| else | ||||
| { | ||||
|     $user          = sanitize('user'); | ||||
|     $login         = sanitize('login'); | ||||
|     $shadow_login  = sanitize('shadow_login'); | ||||
|     $password      = sanitize('password'); | ||||
|     $access_token  = sanitize('access_token'); | ||||
|     $access_tokens = sanitize('access_tokens'); | ||||
|     $salt          = sanitize('salt'); | ||||
|  | ||||
|     if (isset($_POST['get_secure_passwords']) && isset($_POST['user']) && | ||||
|         isset($_POST['access_tokens'])) | ||||
|         return get_secure_entries($user, $access_tokens); | ||||
|  | ||||
|     if (isset($_POST['get_passwords']) && isset($_POST['user'])) | ||||
|         return list_entries($_POST['user']); | ||||
|         return list_entries($user); | ||||
|  | ||||
|     if (isset($_POST['add_entry']) && isset($_POST['user']) &&  | ||||
|         isset($_POST['login']) && isset($_POST['password'])) | ||||
|         return add_entry($_POST['user'], $_POST['login'], $_POST['password']); | ||||
|         isset($_POST['login']) && isset($_POST['password']) && | ||||
|         isset($_POST['shadow_login']) && isset($_POST['salt']) && | ||||
|         isset($_POST['access_token']) ) | ||||
|         return add_entry($user, | ||||
|                          $login, | ||||
|                          $password, | ||||
|                          $shadow_login, | ||||
|                          $salt, | ||||
|                          $access_token); | ||||
|  | ||||
|     if (isset($_POST['delete_entry']) && isset($_POST['user']) &&  | ||||
|         isset($_POST['login'])) | ||||
|         return delete_entry($_POST['user'], $_POST['login']); | ||||
|         isset($_POST['login']) && isset($_POST['access_token'])) | ||||
|         return delete_entry($user, | ||||
|                             $login, | ||||
|                             $access_token); | ||||
| } | ||||
|  | ||||
| ?> | ||||
| @@ -50,24 +74,24 @@ else | ||||
| <html> | ||||
|   <head> | ||||
|     <meta http-equiv="Content-Type" content="text/html;charset=utf-8" > | ||||
|     <link rel="icon"       type="image/png" href="ressources/favicon.png" /> | ||||
|     <link rel="stylesheet" type="text/css"  href="ressources/gpass.css" /> | ||||
|     <link rel="icon"       type="image/png" href="resources/favicon.png" /> | ||||
|     <link rel="stylesheet" type="text/css"  href="resources/gpass.css" /> | ||||
|     <script language="javascript"> | ||||
|     <?php | ||||
|     echo "pkdbf2_level=$PKDBF2_LEVEL;\n"; | ||||
|     echo "pkdbf2_level=$PKDBF2_LEVEL; use_shadow_logins=$USE_SHADOW_LOGINS;\n"; | ||||
|     ?> | ||||
|     </script> | ||||
|     <script src="ressources/jsaes.js"></script> | ||||
|     <script src="ressources/jssha256.js"></script> | ||||
|     <script src="ressources/hmac.js"></script> | ||||
|     <script src="ressources/pkdbf2.js"></script> | ||||
|     <script src="ressources/gpass.js"></script> | ||||
|     <script src="ressources/pwdmeter.js"></script> | ||||
|     <script src="resources/jsaes.js"></script> | ||||
|     <script src="resources/jssha256.js"></script> | ||||
|     <script src="resources/hmac.js"></script> | ||||
|     <script src="resources/pkdbf2.js"></script> | ||||
|     <script src="resources/gpass.js"></script> | ||||
|     <script src="resources/pwdmeter.js"></script> | ||||
|     <title>gPass : global Password</title> | ||||
|   </head> | ||||
|   <body onload="start();"> | ||||
|     <div id="logo"> | ||||
|       <a href="http://indefero.soutade.fr/p/gpass"><img src="ressources/gpass.png" alt="logo"/></a> | ||||
|       <a href="http://indefero.soutade.fr/p/gpass"><img src="resources/gpass.png" alt="logo"/></a> | ||||
|     </div> | ||||
|  | ||||
|     <div id="admin" <?php if (!$ADMIN_MODE) echo "style=\"display:none\"";?> > | ||||
|   | ||||
| @@ -1 +1,3 @@ | ||||
| CREATE TABLE gpass(login VARCHAR(512) PRIMARY KEY, password VARCHAR(512)); | ||||
| CREATE TABLE gpass(login VARCHAR(512) PRIMARY KEY, password VARCHAR(512), shadow_login VARCHAR(32), salt VARCHAR(32), access_token VARCHAR(32)); | ||||
| CREATE TABLE db_version(version INTEGER); | ||||
| INSERT INTO db_version VALUES (1); | ||||
							
								
								
									
										
											BIN
										
									
								
								server/ref/gpass.bdd
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								server/ref/gpass.bdd
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user