1 | <?php␊ |
2 | /*␊ |
3 | Copyright (C) 2013 Grégory Soutadé␊ |
4 | ␊ |
5 | This file is part of gPass.␊ |
6 | ␊ |
7 | gPass is free software: you can redistribute it and/or modify␊ |
8 | it under the terms of the GNU General Public License as published by␊ |
9 | the Free Software Foundation, either version 3 of the License, or␊ |
10 | (at your option) any later version.␊ |
11 | ␊ |
12 | gPass is distributed in the hope that it will be useful,␊ |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of␊ |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the␊ |
15 | GNU General Public License for more details.␊ |
16 | ␊ |
17 | You should have received a copy of the GNU General Public License␊ |
18 | along with gPass. If not, see <http://www.gnu.org/licenses/>.␊ |
19 | */␊ |
20 | ␊ |
21 | /*␊ |
22 | login is stored as :␊ |
23 | @@url;login␊ |
24 | ␊ |
25 | Password is salted (3 random characters) and encrypted␊ |
26 | ␊ |
27 | All is encrypted with AES256 and key : PKDBF2(hmac_sha256, master key, url, 1000)␊ |
28 | */␊ |
29 | $MAX_ENTRY_LEN = 512;␊ |
30 | $USERS_PATH = "./users/";␊ |
31 | ␊ |
32 | function open_crypto($mkey)␊ |
33 | {␊ |
34 | if (!isset($_SESSION['td']))␊ |
35 | {␊ |
36 | $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');␊ |
37 | ␊ |
38 | if ($td == false)␊ |
39 | die("Unable to open mcrypt");␊ |
40 | ␊ |
41 | $ret = mcrypt_generic_init($td, hex2bin($mkey), '0000000000000000');␊ |
42 | ␊ |
43 | if ($ret < 0)␊ |
44 | {␊ |
45 | echo "<div class=\"error\">Unable to set key $ret</div>";␊ |
46 | return null;␊ |
47 | }␊ |
48 | ␊ |
49 | $_SESSION['td'] = $td;␊ |
50 | }␊ |
51 | else␊ |
52 | $td = $_SESSION['td'];␊ |
53 | ␊ |
54 | return $td;␊ |
55 | }␊ |
56 | ␊ |
57 | function decrypt($mkey, $val, $salted)␊ |
58 | {␊ |
59 | $td = open_crypto($mkey);␊ |
60 | ␊ |
61 | if ($td == null) return;␊ |
62 | ␊ |
63 | $val = mdecrypt_generic($td, hex2bin($val));␊ |
64 | ␊ |
65 | // Remove 0 added by encrypt␊ |
66 | $val = str_replace("\0", '', $val);␊ |
67 | ␊ |
68 | // Remove salt␊ |
69 | if ($salted)␊ |
70 | $val = substr($val, 0, strlen($val)-3);␊ |
71 | ␊ |
72 | return $val;␊ |
73 | }␊ |
74 | ␊ |
75 | function encrypt($mkey, $val, $salted)␊ |
76 | {␊ |
77 | global $MAX_ENTRY_LEN;␊ |
78 | ␊ |
79 | $td = open_crypto($mkey);␊ |
80 | ␊ |
81 | if ($td == null) return;␊ |
82 | ␊ |
83 | if ($salted)␊ |
84 | {␊ |
85 | $val .= dechex(rand(256,4095)); //between 0x100 and 0xfff␊ |
86 | }␊ |
87 | ␊ |
88 | $val = mcrypt_generic($td, $val);␊ |
89 | ␊ |
90 | if (strlen($val) > $MAX_ENTRY_LEN)␊ |
91 | {␊ |
92 | echo "<div class=\"error\">Value to encrypt is too long</div>";␊ |
93 | return null;␊ |
94 | }␊ |
95 | ␊ |
96 | return bin2hex($val);␊ |
97 | }␊ |
98 | ␊ |
99 | // From http://php.net/manual/en/function.copy.php␊ |
100 | function recurse_copy($src,$dst) {␊ |
101 | $dir = opendir($src);␊ |
102 | if ($dir == FALSE) return FALSE;␊ |
103 | if (!@mkdir($dst)) return FALSE;␊ |
104 | while(false !== ( $file = readdir($dir)) ) {␊ |
105 | if (( $file != '.' ) && ( $file != '..' )) {␊ |
106 | if ( is_dir($src . '/' . $file) ) {␊ |
107 | return recurse_copy($src . '/' . $file,$dst . '/' . $file);␊ |
108 | }␊ |
109 | else {␊ |
110 | copy($src . '/' . $file,$dst . '/' . $file);␊ |
111 | }␊ |
112 | }␊ |
113 | }␊ |
114 | closedir($dir);␊ |
115 | return TRUE;␊ |
116 | } ␊ |
117 | ␊ |
118 | function create_user($user)␊ |
119 | {␊ |
120 | global $USERS_PATH;␊ |
121 | ␊ |
122 | if (strpos($user, "..") || strpos($user, "/") || $user[0] == "." || $user[0] == "_")␊ |
123 | {␊ |
124 | echo "<div class=\"error\">Invalid user</div>";␊ |
125 | }␊ |
126 | else␊ |
127 | {␊ |
128 | $user = $USERS_PATH . $user;␊ |
129 | ␊ |
130 | if (file_exists($user))␊ |
131 | {␊ |
132 | echo "<div class=\"error\">User already exists</div>";␊ |
133 | }␊ |
134 | else␊ |
135 | {␊ |
136 | if (!recurse_copy("./ref", $user))␊ |
137 | {␊ |
138 | echo "<div class=\"error\">Cannot create user $user</div>";␊ |
139 | }␊ |
140 | else␊ |
141 | {␊ |
142 | return true;␊ |
143 | }␊ |
144 | }␊ |
145 | }␊ |
146 | ␊ |
147 | return false;␊ |
148 | }␊ |
149 | ␊ |
150 | function load_database($user)␊ |
151 | {␊ |
152 | global $USERS_PATH;␊ |
153 | ␊ |
154 | try {␊ |
155 | $db = new SQLite3($USERS_PATH . "$user/gpass.bdd", SQLITE3_OPEN_READWRITE);␊ |
156 | }␊ |
157 | catch(Exception $e)␊ |
158 | {␊ |
159 | echo "<div class=\"error\">Unable to load database for user $user !</div>";␊ |
160 | return null;␊ |
161 | }␊ |
162 | ␊ |
163 | // New access need to reset crypto␊ |
164 | unset($_SESSION['td']);␊ |
165 | ␊ |
166 | return $db;␊ |
167 | }␊ |
168 | ␊ |
169 | function add_entry($user, $login, $password)␊ |
170 | {␊ |
171 | $db = load_database($user);␊ |
172 | ␊ |
173 | if ($db == null)␊ |
174 | {␊ |
175 | echo "Unknown user";␊ |
176 | return false;␊ |
177 | }␊ |
178 | ␊ |
179 | $count = $db->querySingle("SELECT COUNT(*) FROM gpass WHERE login='" . $login . "'");␊ |
180 | ␊ |
181 | if ($count != 0)␊ |
182 | {␊ |
183 | echo "Entry already exists";␊ |
184 | return false;␊ |
185 | }␊ |
186 | ␊ |
187 | $result = $db->query("INSERT INTO gpass ('login', 'password') VALUES ('" . $login . "', '" . $password . "')");␊ |
188 | ␊ |
189 | $db->close();␊ |
190 | ␊ |
191 | echo "OK";␊ |
192 | ␊ |
193 | return true;␊ |
194 | }␊ |
195 | ␊ |
196 | function delete_entry($user, $login)␊ |
197 | {␊ |
198 | $db = load_database($user);␊ |
199 | ␊ |
200 | if ($db == null)␊ |
201 | {␊ |
202 | echo "Unknown user";␊ |
203 | return false;␊ |
204 | }␊ |
205 | ␊ |
206 | $db->query("DELETE FROM gpass WHERE login='" . $login . "'");␊ |
207 | ␊ |
208 | $db->close();␊ |
209 | ␊ |
210 | echo "OK";␊ |
211 | ␊ |
212 | return true;␊ |
213 | }␊ |
214 | ␊ |
215 | function update_entry($user, $mkey, $old_login, $url, $login, $password)␊ |
216 | {␊ |
217 | if (delete_entry($user, $old_login))␊ |
218 | return add_entry($user, $mkey, $url, $login, $password);␊ |
219 | ␊ |
220 | return false;␊ |
221 | }␊ |
222 | ␊ |
223 | function list_entries($user)␊ |
224 | {␊ |
225 | $db = load_database($user);␊ |
226 | ␊ |
227 | if ($db == null) return;␊ |
228 | ␊ |
229 | $result = $db->query("SELECT * FROM gpass");␊ |
230 | ␊ |
231 | echo "entries\n";␊ |
232 | ␊ |
233 | while (($row = $result->fetchArray()))␊ |
234 | {␊ |
235 | echo $row['login'] . ";" . $row['password'] . "\n";␊ |
236 | }␊ |
237 | }␊ |
238 | ␊ |
239 | ?> |