-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPassManager.java
594 lines (524 loc) · 22.3 KB
/
PassManager.java
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Scanner;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import org.bouncycastle.util.Arrays;
/**
*
* @author Kyle Den Hartog, Nicholas Kao, and Doug Ives
*/
public class PassManager {
private static SecretKey encKey;
private static SecretKey macKey;
private static byte[] macSalt;
private static byte[] encSalt;
private static void checkIntegrity() throws
IOException,
FileNotFoundException,
NoSuchProviderException,
NoSuchAlgorithmException,
InvalidKeyException,
InvalidKeySpecException {
//Get data from passwd_file
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
Path path = Paths.get(passwd_file_path);
byte[] data = Files.readAllBytes(path);
byte[] lastHmac = Arrays.copyOfRange(data, 256, 320);
byte[] encrypted = Arrays.copyOfRange(data, 320, data.length);
byte[] currentHmac = SecurityFunction.hmac(encrypted, macKey);
if (Arrays.areEqual(lastHmac, currentHmac)) {
System.out.print("PASSED!\n");
} else {
System.out.println("FAILED!\n");
}
}
private static void registerAccount() throws
NoSuchAlgorithmException,
NoSuchPaddingException,
NoSuchProviderException,
FileNotFoundException,
IOException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
InvalidAlgorithmParameterException,
InvalidKeySpecException {
Scanner sc = new Scanner(System.in);
//Get Domain Name
System.out.print("\nPlease enter the domain name: ");
String domain = sc.next();
//Get Username
System.out.print("Please enter your username: ");
String username = sc.next();
//Get password
System.out.print("Please enter your password: ");
String password = sc.next();
//get data from passwd_file
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
Path path = Paths.get(passwd_file_path);
byte[] data = Files.readAllBytes(path);
//strip hmac and salt
byte[] encrypted_data = Arrays.copyOfRange(data, 320, data.length);
byte[] decrypted = SecurityFunction.decrypt(encrypted_data, encKey);
//Lookup account to see if it already exists if not write it to file
if (accountLookup(domain, username, decrypted) == null) {
//create account using " " for acc attribute seperation and "!" used for acc seperation
String account = domain + " " + username + " " + password + "!";
byte[] dataBytes = account.getBytes("UTF-8");
//append account to end of stored accounts data
byte[] newData = Arrays.concatenate(decrypted, dataBytes);
//reencrypt data
byte[] encrypted = SecurityFunction.encrypt(newData, encKey);
//generate hmac
byte[] hmac = SecurityFunction.hmac(encrypted, macKey);
byte[] salt_hmac_and_encrypted = Arrays.concatenate(macSalt, hmac, encrypted);
//write to file
try (FileOutputStream output = new FileOutputStream("passwd_file")) {
output.write(salt_hmac_and_encrypted);
output.close();
System.out.println("USER ACCOUNT REGISTERED!\n");
}
} else {
System.out.println("USER ACCOUNT ALREADY EXISTS!\n");
}
}
private static void deleteAccount() throws
IOException,
NoSuchAlgorithmException,
NoSuchProviderException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
FileNotFoundException,
InvalidAlgorithmParameterException,
InvalidKeySpecException {
Scanner sc = new Scanner(System.in);
//Get Domain Name
System.out.print("\nPlease enter the domain name: ");
String domain = sc.next();
//Get Username
System.out.print("Please enter your username: ");
String username = sc.next();
//Get password
System.out.print("Please enter your password: ");
String password = sc.next();
//get data from passwd_file
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
Path path = Paths.get(passwd_file_path);
byte[] data = Files.readAllBytes(path);
//strip hmac and salt
byte[] encrypted_data = Arrays.copyOfRange(data, 320, data.length);
byte[] decrypted = SecurityFunction.decrypt(encrypted_data, encKey);
//check if account exists
if (accountLookup(domain, username, decrypted) != null) {
String dataString = new String(decrypted, "UTF-8");
String[] accounts = dataString.split("!");
String account = domain + " " + username;
//search through accounts and delete account
for (int i = 0; i < accounts.length; i++) {
if (accounts[i].contains(account)) {
accounts[i] = null;
break;
}
}
//rebuild list of accounts by filling the removed
String newAccList = "";
for (int i = 0; i < accounts.length; i++) {
if (accounts[i] != null) {
newAccList += accounts[i] + "!";
}
}
//turn accounts list back into bytes
byte[] bytesData = newAccList.getBytes("UTF-8");
//encrypt data
byte[] encrypted = SecurityFunction.encrypt(bytesData, encKey);
//generate salt, hmac, and append data
byte[] hmac = SecurityFunction.hmac(encrypted, macKey);
byte[] salt_hmac_and_encrypted = Arrays.concatenate(macSalt, hmac, encrypted);
//write to file
try (FileOutputStream output = new FileOutputStream("passwd_file")) {
output.write(salt_hmac_and_encrypted);
output.close();
System.out.println("USER ACCOUNT REMOVED!\n");
}
} else {//account not found
System.out.println("USER ACCOUNT DOES NOT EXIST!\n");
}
}
/* This is a function to change an accounts password given a domain name,
* a username, the old password, and the new password.
*/
private static void changeAccount() throws
IOException,
NoSuchAlgorithmException,
NoSuchProviderException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
FileNotFoundException,
InvalidAlgorithmParameterException,
InvalidKeySpecException {
Scanner sc = new Scanner(System.in);
//Get Domain Name
System.out.print("\nPlease enter the domain name: ");
String domain = sc.next();
//Get Username
System.out.print("Please enter your username: ");
String username = sc.next();
//Get old password
System.out.print("Please enter your old password: ");
String oldpass = sc.next();
//Get new password
System.out.print("Please enter your new password: ");
String newpass = sc.next();
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
Path path = Paths.get(passwd_file_path);
byte[] data = Files.readAllBytes(path);
//strip hmac
byte[] encrypted_data = Arrays.copyOfRange(data, 320, data.length);
byte[] decrypted = SecurityFunction.decrypt(encrypted_data, encKey);
//perform account change
if (accountLookup(domain, username, decrypted) != null) {
String dataString = new String(decrypted, "UTF-8");
String[] accounts = dataString.split("!");
String account = domain + " " + username;
String updated = domain + " " + username + " " + newpass;
//search through accounts and delete account
for (int i = 0; i < accounts.length; i++) {
if (accounts[i].contains(account)) {
accounts[i] = updated;
break;
}
}
//rebuild list of accounts and change to byte[]
String newAccList = "";
for (String acc : accounts) {
newAccList += acc + "!";
}
byte[] bytesData = newAccList.getBytes("UTF-8");
//encrypt new data
byte[] encrypted = SecurityFunction.encrypt(bytesData, encKey);
//generate new hmac and append
byte[] hmac = SecurityFunction.hmac(encrypted, macKey);
byte[] salt_hmac_and_encrypted = Arrays.concatenate(macSalt, hmac, encrypted);
//write to file
try (FileOutputStream output = new FileOutputStream("passwd_file")) {
output.write(salt_hmac_and_encrypted);
output.close();
System.out.println("USER ACCOUNT UPDATED!\n");
}
} else {//account not found
System.out.println("USER ACCOUNT DOES NOT EXIST!\n");
}
}
/* This is a feature required by the assignment where it reads in a domain
* from the user and returns all usernames and passwords matching that domain.
*/
private static void getPassword() throws
IOException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException,
NoSuchProviderException,
FileNotFoundException,
InvalidKeySpecException {
Scanner sc = new Scanner(System.in);
System.out.print("\nPlease enter a domain: ");
String domain = sc.next();
//reads in all data from /passwd_file
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
Path path = Paths.get(passwd_file_path);
byte[] data = Files.readAllBytes(path);
//strip hmac
byte[] encrypted_data = Arrays.copyOfRange(data, 320, data.length);
byte[] decrypted = SecurityFunction.decrypt(encrypted_data, encKey);
//search data for account and print all found based on domain
String dataString = new String(decrypted, "UTF-8");
String[] accounts = dataString.split("!");
String id = domain;
for (String account : accounts) {
if (account.contains(id)) {
String[] accArr = account.split(" ");
System.out.print("username " + accArr[1] + " password " + accArr[2] + "\n");
}
}
}
//This is used upon startup for the first time or if a file is missing to
private static void setup() throws
NoSuchAlgorithmException,
NoSuchProviderException,
FileNotFoundException,
IOException,
InvalidKeyException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
InvalidAlgorithmParameterException {
Scanner sc = new Scanner(System.in);
//create passwd_file path
String passwd_file_string = System.getProperty("user.dir");
passwd_file_string += "/passwd_file";
//Used for master_passwd path
String master_passwd_string = System.getProperty("user.dir");
master_passwd_string += "/master_passwd";
//initialize file paths
Path passwd_file_path = Paths.get(passwd_file_string);
Path master_passwd_path = Paths.get(master_passwd_string);
//initialize files
File master_passwd_file = new File(master_passwd_string);
File passwd_file = new File(passwd_file_string);
//delete old files if they exists
Files.deleteIfExists(passwd_file_path);
Files.deleteIfExists(master_passwd_path);
//create files
passwd_file.createNewFile();
master_passwd_file.createNewFile();
//get master password
System.out.print("\nPlease provide a master password: ");
String master_passwd = sc.next();
byte[] password = master_passwd.getBytes();
//get salts and combine with master password
encSalt = SecurityFunction.randomNumberGenerator(256);
macSalt = SecurityFunction.randomNumberGenerator(256);
byte[] salted_password = Arrays.concatenate(encSalt, password);
//setup master_passwd file
byte[] hash = SecurityFunction.hash(salted_password);
byte[] salt_and_hash = Arrays.concatenate(encSalt, hash);
//write data to master_passwd file
try (FileOutputStream output = new FileOutputStream("master_passwd")) {
output.write(salt_and_hash);
output.close();
}
//generate key kept in memory during the use of the program
encKey = SecurityFunction.generateKey(master_passwd, encSalt);
macKey = SecurityFunction.generateKey(master_passwd, macSalt);
//get hash for passwd_file and append to file
byte[] passwd_file_data = Files.readAllBytes(passwd_file_path);
byte[] encrypted = SecurityFunction.encrypt(passwd_file_data, encKey);
byte[] hmac = SecurityFunction.hmac(encrypted, macKey);
byte[] salt_hmac_and_encrypted = Arrays.concatenate(macSalt, hmac, encrypted);
//write data to passwd_file
try (FileOutputStream output = new FileOutputStream("passwd_file")) {
output.write(salt_hmac_and_encrypted);
output.close();
}
}
//this method is used to authenticate the user and verify the integrity of passwd_file on startup
private static boolean startup() throws
IOException,
NoSuchAlgorithmException,
FileNotFoundException,
NoSuchProviderException,
InvalidKeyException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
InvalidAlgorithmParameterException {
String master_passwd;
Scanner sc = new Scanner(System.in);
System.out.println("\nWelcome to your password manager");
if (!fileCheck()) {
setup();
return true;
} else {
System.out.print("\nPlease enter your master password: ");
master_passwd = sc.next();
//verifies password are correct or exits after 5 attempts
int counter = 0;
while (!passwordCheck(master_passwd)) {
System.out.println("WRONG MASTER PASSWORD\n");
System.out.print("Please re-enter your master password: ");
master_passwd = sc.next();
counter++;
if (counter == 5) {
System.out.println("Password attempts exceeded. Exiting...");
return false;
}
}
//get file data
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
Path pPath = Paths.get(passwd_file_path);
byte[] passwd_file_data = Files.readAllBytes(pPath);
String master_passwd_path = System.getProperty("user.dir");
master_passwd_path += "/master_passwd";
Path mPath = Paths.get(master_passwd_path);
byte[] master_passwd_data = Files.readAllBytes(mPath);
//get salts for both Keys
macSalt = Arrays.copyOf(passwd_file_data, 256);
encSalt = Arrays.copyOf(master_passwd_data, 256);
//generate key kept in memory during the use of the program
encKey = SecurityFunction.generateKey(master_passwd, encSalt);
macKey = SecurityFunction.generateKey(master_passwd, macSalt);
//integrity check
byte[] lastHmac = Arrays.copyOfRange(passwd_file_data, 256, 320);
byte[] encrypted = Arrays.copyOfRange(passwd_file_data, 320, passwd_file_data.length);
byte[] currentHmac = SecurityFunction.hmac(encrypted, macKey);
if (Arrays.areEqual(lastHmac, currentHmac)) {
} else {
System.out.println("INTEGRITY CHECK OF PASSWORD FILE FAILED\n");
}
return true;
}
}
//This is a helper function to help do a password check during startup
private static boolean passwordCheck(String entry) throws
FileNotFoundException,
IOException,
NoSuchAlgorithmException,
NoSuchProviderException {
//get contents
String master_passwd_path = System.getProperty("user.dir");
master_passwd_path += "/master_passwd";
Path path = Paths.get(master_passwd_path);
byte[] contents = Files.readAllBytes(path);
//get salt and password as bytes for comparison
byte[] salt = Arrays.copyOf(contents, 256);
byte[] password = entry.getBytes();
//concatenate the salt and the password then hash it
byte[] salted_password = Arrays.concatenate(salt, password);
byte[] hashed = SecurityFunction.hash(salted_password);
return (Arrays.areEqual(contents, Arrays.concatenate(salt, hashed)));
}
//This will be used for checking if accounts exist
private static String accountLookup(String domain, String user, byte[] data) throws UnsupportedEncodingException {
String dataString = new String(data, "UTF-8");
String[] accounts = dataString.split("!");
String id = domain + " " + user;
//search through accounts
for (String account : accounts) {
if (account.contains(id)) {
return account;
}
}
return null;
}
//This is a helper function to verify that both files exist
private static boolean fileCheck() {
//Used for passwd_file path
String passwd_file_path = System.getProperty("user.dir");
passwd_file_path += "/passwd_file";
//Used for master_passwd path
String master_passwd_path = System.getProperty("user.dir");
master_passwd_path += "/master_passwd";
File passwd_file = new File(passwd_file_path);
File master_passwd = new File(master_passwd_path);
return (passwd_file.exists() && master_passwd.exists());
}
private static void mainMenu() throws
NoSuchAlgorithmException,
NoSuchProviderException,
IOException,
NoSuchPaddingException,
FileNotFoundException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
InvalidAlgorithmParameterException,
InvalidKeySpecException {
Scanner sc = new Scanner(System.in);
System.out.println("\n1 - Check Integrity");
System.out.println("2 - Register Account");
System.out.println("3 - Delete Account");
System.out.println("4 - Change Account");
System.out.println("5 - Get Password");
System.out.println("6 - Exit");
int option = 0;
//option input sanitization
do {
System.out.print("Please enter an integer between 1 and 6 corresponding with the option you would like to select: ");
while (!sc.hasNextInt()) {
System.out.println("Invalid input.");
sc.next();
}
option = sc.nextInt();
} while (!(option >= 1 && option <= 6));
//run option logic
switch (option) {
case 1:
checkIntegrity();
break;
case 2:
registerAccount();
break;
case 3:
deleteAccount();
break;
case 4:
changeAccount();
break;
case 5:
getPassword();
break;
case 6:
System.exit(0);
}
}
/**
*
* @param args
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws IOException
* @throws NoSuchPaddingException
* @throws java.io.FileNotFoundException
* @throws java.security.InvalidKeyException
* @throws javax.crypto.IllegalBlockSizeException
* @throws javax.crypto.BadPaddingException
* @throws java.security.spec.InvalidParameterSpecException
* @throws java.security.InvalidAlgorithmParameterException
* @throws java.security.spec.InvalidKeySpecException
*/
public static void main(String[] args) throws
NoSuchAlgorithmException,
NoSuchProviderException,
IOException,
NoSuchPaddingException,
FileNotFoundException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException,
InvalidParameterSpecException,
InvalidAlgorithmParameterException,
InvalidKeySpecException {
if(startup()){
while (true) {
mainMenu();
}
}
}
}