Overview
Comment: | fix missing return that was breaking build under clang, add ability to delete records |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
178e52ca5577a2a6f7e7fed5b68b4b88 |
User & Date: | lexi on 2019-08-15 23:49:54 |
Other Links: | manifest | tags |
Context
2019-08-16
| ||
01:56 | fix so it compiles in non-clipboard mode check-in: 6f480eda3f user: lexi tags: trunk | |
2019-08-15
| ||
23:49 | fix missing return that was breaking build under clang, add ability to delete records check-in: 178e52ca55 user: lexi tags: trunk | |
12:31 | my monster liiiiives check-in: 5089ec59d3 user: lexi tags: trunk | |
Changes
Modified kpw.d/errtab from [763d2287dd] to [ce1ef8cc06].
9 9 copy could not copy password 10 10 pipe could not create pipe 11 11 insane your environment is not sane 12 12 index no such entry in database 13 13 db_create database could not be created 14 14 db_load database could not be read 15 15 db_corrupt database corrupt 16 +db_empty no records in database notice 16 17 cancel user canceled operation notice 17 18 pw invalid password 18 19 pw_match passwords do not match 19 20 usage usage displayed to user debug 64 20 21 lib unspecified library error fatal 128 21 22 lib_sodium_init could not initialize libsodium
Modified kpw.d/kpw.c from [7a6fbd2214] to [9c1b0583ee].
80 80 typedef enum { 81 81 tbl_ok = ok, tbl_error = fail 82 82 } tbl_error_type; 83 83 typedef unsigned char tbl_word_type; 84 84 #include "clib/tbl.c" 85 85 86 86 #include "opt.inc" 87 + 88 +typedef uint8_t key_priv [db_privkey_len]; 89 +typedef uint8_t key_pub [db_pubkey_len]; 90 +typedef uint8_t db_sz; 91 +typedef uint8_t byte; 87 92 88 93 #define str_ucase "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 89 94 #define str_lcase "abcdefghijklmnopqrstuvwxyz" 90 95 #define str_num "0123456789" 91 96 const char* reftbl = str_num str_ucase str_lcase; 92 97 const char* reftbl_lcase = str_num str_lcase; 93 98 ................................................................................ 224 229 } 225 230 226 231 buf[len] = '\n'; 227 232 228 233 return ok; 229 234 } 230 235 231 -struct entry { 232 - pstr account; 233 - pstr pw; 234 -}; 236 +void 237 +bytedump(byte* bytes, size_t sz) { 238 + for (size_t i = 0; i < sz; ++i) { 239 + char tpl[] ="\x1b[35m \x1b[m"; 240 + char* c = tpl + 5; 241 + *c = bytes[i]; 242 + if (*c < ' ' || *c > '~') *c='.', write(2, tpl, sz(tpl)); 243 + else write(2, c, 1); 244 + } 245 +} 246 + 247 +void 248 +hexdump(byte* bytes, size_t sz) { 249 + if(!_g_debug_msgs) return; 250 + alert(a_debug, "printing hex dump"); 251 + byte* st = bytes; 252 + write(2, _str("\t\x1b[94m")); 253 + for (size_t i = 0; i < sz; ++i) { 254 + char hex[5] = " "; 255 + kitoa(16, bytes[i], hex, hex + 2, NULL, true); 256 + write(2, hex, 4); 257 + if(!((i+1)%8)) { 258 + write(2, _str("\x1b[;1m│\x1b[m ")); 259 + bytedump(st, 8); 260 + write(2, "\n\t\x1b[94m", (i == sz - 1 ? 1 : 7)); 261 + st += 8; 262 + } else if (i == sz - 1) { 263 + write(2, _str("\x1b[;1m│\x1b[m ")); 264 + bytedump(st, (bytes + sz) - st); 265 + write(2, _str("\n\x1b[m")); 266 + } 267 + } 268 +} 269 + 270 +struct dbrecord { pstr acct; pstr pw; }; 271 + 272 +enum bad 273 +dbtell(int db, db_sz* ciphlen, db_sz* plainlen){ 274 + if (read(db, ciphlen, 1) != 1) 275 + return fail; 276 + *plainlen = *ciphlen - crypto_box_SEALBYTES; 277 + return ok; 278 +} 279 + 280 +enum bad 281 +dbnext(int db, struct dbrecord* rec, db_sz acctlen, 282 + byte* pub, byte* priv, 283 + byte ciphertext[static acctlen], 284 + byte plaintext[static acctlen - crypto_box_SEALBYTES]) { 285 + db_sz plaintext_sz = acctlen - crypto_box_SEALBYTES; 286 + 287 + if (read(db, ciphertext, acctlen) != acctlen) 288 + return bad_db_corrupt; 289 + alert(a_debug, "scanned record"); 290 + hexdump(ciphertext, acctlen); 291 + 292 + if(crypto_box_seal_open(plaintext, ciphertext, acctlen, pub, priv) != 0) 293 + return bad_db_corrupt; 294 + 295 + alert(a_debug, "record deciphered"); 296 + hexdump(plaintext, plaintext_sz); 297 + 298 + db_sz record_name_len = plaintext[0], 299 + record_pw_len = plaintext[record_name_len + 1]; 300 + 301 + rec -> acct.len = record_name_len; 302 + rec -> acct.ptr = plaintext + 1; 303 + rec -> pw.len = record_pw_len; 304 + rec -> pw.ptr = plaintext + record_name_len + 2; 305 + 306 + return ok; 307 +} 308 + 309 +enum bad 310 +dbappend(struct dbrecord rec) { 311 + return ok; 312 +} 235 313 236 314 enum term_clear {term_clear_line, 237 315 term_clear_screen}; 238 316 239 317 void term_clear(int tty, enum term_clear behavior) { 240 318 switch(behavior) { 241 319 case term_clear_line: write(tty,"\r\x1b[2K",5); break; 242 320 case term_clear_screen: write(tty,"\r\x1b[3J",5); break; 243 321 } 244 322 } 245 323 void term_bell(int tty) { 246 324 write(tty,"\a",1); 247 325 } 248 - 326 +#include<stdio.h> 249 327 typedef char password[kpw_db_pw_max + 1]; 250 328 bad pwread(bool obscure, char* dest, size_t* out_len, const char* prompt, const size_t plen) { 251 329 if (isatty(0)) { 252 330 int tty = 1; 253 331 if (!isatty(tty)) tty = open("/dev/tty", O_WRONLY); 254 332 if (tty == -1) return bad_insane; 255 333 ................................................................................ 309 387 310 388 if (tty != 1) close(tty); 311 389 } else { 312 390 alert(a_warn, "reading pw from standard input"); 313 391 ssize_t ct = read(0, dest, kpw_db_pw_max); 314 392 dest[ct] = 0; 315 393 } 394 + return ok; 316 395 } 317 396 318 397 int 319 398 dbopen(int flags) { 320 399 const char* dbpath = getenv("kpw_db"); 321 400 int db; 322 401 if (dbpath == NULL) { ................................................................................ 344 423 } else { 345 424 db = open(dbpath, flags, 0600); 346 425 } 347 426 348 427 return db; 349 428 } 350 429 351 -void bytedump(uint8_t* bytes, size_t sz) { 352 - for (size_t i = 0; i < sz; ++i) { 353 - char tpl[] ="\x1b[35m \x1b[m"; 354 - char* c = tpl + 5; 355 - *c = bytes[i]; 356 - if (*c < ' ' || *c > '~') *c='.', write(2, tpl, sz(tpl)); 357 - else write(2, c, 1); 358 - } 359 -} 360 - 361 -void hexdump(uint8_t* bytes, size_t sz) { 362 - if(!_g_debug_msgs) return; 363 - alert(a_debug, "printing hex dump"); 364 - uint8_t* st = bytes; 365 - for (size_t i = 0; i < sz; ++i) { 366 - char hex[5] = " "; 367 - kitoa(16, bytes[i], hex, hex + 2, NULL, true); 368 - write(2, hex, 4); 369 - if(!((i+1)%8)) { 370 - write(2, _str("│ ")); 371 - bytedump(st, 8); 372 - write(2, "\n", 1); 373 - st += 8; 374 - } else if (i == sz - 1) { 375 - write(2, _str("│ ")); 376 - bytedump(st, (bytes + sz) - st); 377 - write(2, "\n", 1); 378 - } 379 - } 430 +enum bad 431 +dbheader_load (int db, byte* salt, byte* salt_enc, byte* pub, byte* priv_enc) { 432 + const size_t salt_sz = crypto_pwhash_SALTBYTES, 433 + salt_enc_sz = crypto_box_SEALBYTES + salt_sz, 434 + pub_sz = sizeof(key_pub), 435 + priv_sz = sizeof(key_priv); 436 + 437 + alert(a_debug, "loading public key"); 438 + ssize_t sr = read(db, pub, pub_sz); 439 + if (sr != pub_sz) return bad_db_corrupt; 440 + hexdump(pub, pub_sz); 441 + 442 + alert(a_debug, "loading password salt"); 443 + sr = read(db, salt, salt_sz); 444 + if (sr != salt_sz) return bad_db_corrupt; 445 + hexdump(salt, salt_sz); 446 + 447 + alert(a_debug, "loading encrypted private key"); 448 + read(db, priv_enc, priv_sz); 449 + hexdump(priv_enc, priv_sz); 450 + 451 + alert(a_debug, "loading verification hash"); 452 + read(db, salt_enc, salt_enc_sz); 453 + hexdump(salt_enc, salt_enc_sz); 454 + 455 + return ok; 380 456 } 381 457 382 458 enum bad 383 -dbdecrypt(int db, uint8_t* pubkey, uint8_t* privkey) { 459 +dbunlock(byte* priv_enc, byte* salt, byte* priv) { 460 + const size_t priv_sz = sizeof(key_priv); 461 + byte key [db_privkey_len]; 462 + 384 463 password dbpw; size_t pwlen; 385 464 bad e = pwread(true, dbpw, &pwlen,_str("database key: ")); 386 - 387 - uint8_t salt [crypto_pwhash_SALTBYTES], 388 - key [db_privkey_len], 389 - priv_enc [db_privkey_len], 390 - priv [db_privkey_len], 391 - pub [db_pubkey_len]; 392 - uint8_t salt_enc [crypto_box_SEALBYTES + sz(salt)], 393 - salt_dec [sz(salt)]; 394 - 395 - alert(a_debug, "loading public key"); 396 - ssize_t sr = read(db, pub, sz(pub)); 397 - if (sr != sz(pub)) return bad_db_corrupt; 398 - hexdump(pub, sz(pub)); 399 - 400 - alert(a_debug, "loading password salt"); 401 - sr = read(db, salt, sz(salt)); 402 - if (sr != sz(salt)) return bad_db_corrupt; 403 - hexdump(salt, sz(salt)); 465 + if (e != ok) return e; 404 466 405 467 alert(a_debug, "deriving secret"); 406 468 if(crypto_pwhash(key, sz(key), dbpw, pwlen, salt, 407 469 crypto_pwhash_OPSLIMIT_INTERACTIVE, 408 470 crypto_pwhash_MEMLIMIT_INTERACTIVE, 409 471 crypto_pwhash_ALG_DEFAULT) != 0) { 410 472 return bad_mem; 411 473 } 412 474 hexdump(key, sz(key)); 413 475 414 - alert(a_debug, "loading encrypted private key"); 415 - read(db, priv_enc, sz(priv_enc)); 416 - hexdump(priv_enc, sz(priv_enc)); 417 - 418 - alert(a_debug, "decrypting private key"); 476 + alert(a_debug, "attempting to decrypt private key"); 419 477 for (size_t i = 0; i < sz(key); ++i) { 420 478 priv[i] = priv_enc[i] ^ key[i]; 421 479 } 422 - hexdump(priv, sz(priv)); 480 + hexdump(priv, sz(key)); 423 481 424 - alert(a_debug, "loading verification hash"); 425 - read(db, salt_enc, sz(salt_enc)); 426 - hexdump(salt_enc, sz(salt_enc)); 482 + return ok; 483 +} 484 + 485 +enum bad 486 +dbverify(byte* salt, byte* salt_enc, byte* pub, byte* priv) { 487 + byte salt_dec [crypto_pwhash_SALTBYTES]; 427 488 428 489 alert(a_debug, "decrypting verification hash"); 429 490 int r = crypto_box_seal_open(salt_dec, salt_enc, 430 - sz(salt_enc), pub, priv); 491 + sz(salt_dec) + crypto_box_SEALBYTES, pub, priv); 431 492 if (r != 0) return bad_pw; 432 493 hexdump(salt_dec, sz(salt_dec)); 433 494 434 - if (memcmp(salt,salt_dec,sz(salt)) != 0) return bad_db_corrupt; 495 + if (memcmp(salt,salt_dec,sz(salt_dec)) != 0) return bad_db_corrupt; 496 + else return ok; 497 +} 498 + 499 +enum bad 500 +dbdecrypt(int db, byte* pubkey, byte* privkey) { 501 + byte salt [crypto_pwhash_SALTBYTES], 502 + priv_enc [db_privkey_len], 503 + priv [db_privkey_len], 504 + pub [db_pubkey_len]; 505 + byte salt_enc [crypto_box_SEALBYTES + sz(salt)]; 506 + bad e; 507 + 508 + if ((e = dbheader_load(db, salt, salt_enc, pub, priv_enc)) != ok) 509 + return e; 510 + if ((e = dbunlock(priv_enc, salt, priv)) != ok) 511 + return e; 512 + if ((e = dbverify(salt, salt_enc, pub, priv)) != ok) 513 + return e; 435 514 436 515 /* TODO refactor to avoid unnecessary memcpy */ 437 516 memcpy(privkey, priv, sz(priv)); 438 517 memcpy(pubkey, pub, sz(pub)); 439 518 440 519 return ok; 441 520 } 442 521 443 -#include<stdio.h> 444 -void bright(int fd, const char* str, size_t len) { 522 +void 523 +bright(int fd, const char* str, size_t len) { 445 524 if (_g_term_type[fd] >= ansi_term) write(fd, _str("\x1b[1m")); 446 525 write(fd, str, len); 447 526 if (_g_term_type[fd] >= ansi_term) write(fd, _str("\x1b[21m")); 448 527 } 528 + 529 +void* 530 +transcribe(void* dest, void* src, size_t sz) { 531 + memcpy(dest, src, sz); return dest + sz; 532 +} 533 + 534 +enum bad 535 +emit_usage(const char* text) { 536 + say("\x1b[1musage:\x1b[m "); 537 + write(2, _g_binary_name, strlen(_g_binary_name)); 538 + if (text == NULL) { 539 + write(2, kpw_optstr, sz(kpw_optstr)); 540 + write(2, kpw_usage, sz(kpw_usage)); 541 + } else write(2, text, strlen(text)); 542 + return bad_usage; 543 +} 449 544 450 545 int 451 546 kpw(int argc, const char** argv) { 452 547 if (argc == 0) return bad_insane; 453 548 _g_binary_name = argv[0]; 454 549 455 550 enum genmode 456 551 mode = lower; 457 - enum {usage,getpw,addpw,delpw,lspw,genpw, 458 - chpw,keyin,logout,createdb,rekeydb} 552 + enum {usage,getpw,addpw,delpw,lspw,genpw,regen, 553 + chpw,keyin,logout,createdb,rekeydb,help} 459 554 op = getpw; 460 555 461 556 const char* params[3]; 462 557 uint8_t param = 0; 463 558 464 559 bool print = false, 465 560 clobber = false, ................................................................................ 490 585 } 491 586 } else { 492 587 if (param > sz(params)) return bad_syntax; 493 588 params[param++] = *arg; 494 589 } 495 590 } 496 591 497 - if (op == getpw && param == 0) { 498 - size_t namelen = strlen(argv[0]); 499 - say("\x1b[1musage:\x1b[m "); 500 - write(2, argv[0], namelen); 501 - write(2, kpw_optstr, sz(kpw_optstr)); 502 - write(2, kpw_usage, sz(kpw_usage)); 503 - return bad_usage; 504 - } 592 + if (op == getpw && param == 0) return emit_usage(NULL); 505 593 506 594 if (sodium_init() < 0) 507 595 return bad_lib_sodium_init; 508 596 509 597 switch(op) { 510 598 511 - case genpw: /* kpw -g[lmu] <acct> [<len>] */ 512 - case addpw: { /* kpw -a <acct> [<pw>] */ 599 + case genpw: 600 + case addpw: { 601 + if (param == 0) return emit_usage( 602 + op == addpw ? " -a[p] <account> [<pw>]\n" : 603 + /* genpw */" -g[lmup] <account> [<pw len>]\n"); 604 + 513 605 if (param > 2 || param < 1) return bad_syntax; 514 606 const char* acct = params[0], 515 607 * prm = (param == 2 ? params[1] : NULL); 516 608 517 609 alert(a_debug, "opening database"); 518 610 int db = dbopen(O_RDWR); 519 611 if (db == -1) return bad_db_load; 520 612 alert(a_debug, "reading in public key"); 521 - uint8_t key [db_pubkey_len]; 613 + byte key [db_pubkey_len]; 522 614 ssize_t e = read(db, key, sz(key)); 523 615 if(e < sz(key)) return bad_db_corrupt; 524 616 525 617 lseek(db, 0, SEEK_END); 526 618 bool tty_in = isatty(0), 527 619 tty_out = isatty(1); 528 620 ................................................................................ 563 655 write(1, pw, len); 564 656 if(tty_out) write(1, "\n", 1); 565 657 } 566 658 pwlen = len; 567 659 } 568 660 if (copy_pw) copy(pw, pwlen); 569 661 alert(a_debug, "encoding database entry"); 570 - uint8_t acctlen = strlen(acct); 571 - uint8_t plaintext[1 + acctlen + 572 - 1 + pwlen]; 662 + db_sz acctlen = strlen(acct); 663 + byte plaintext[1 + acctlen + 664 + 1 + pwlen]; 573 665 plaintext[0] = acctlen; 574 666 strncpy(plaintext + 1, acct, acctlen); 575 667 plaintext[1 + acctlen] = pwlen; 576 668 strncpy(plaintext + acctlen + 2, pw, pwlen); 577 669 hexdump(plaintext, sz(plaintext)); 578 670 579 671 alert(a_debug, "enciphering database entry"); 580 672 581 - uint8_t ciphertext[sz(plaintext) + crypto_box_SEALBYTES]; 673 + byte ciphertext[sz(plaintext) + crypto_box_SEALBYTES]; 582 674 crypto_box_seal(ciphertext, plaintext, sz(plaintext), key); 583 675 hexdump(ciphertext, sz(ciphertext)); 584 676 585 677 alert(a_debug, "writing ciphertext to db"); 586 - uint8_t ciphertext_len = sz(ciphertext); 678 + db_sz ciphertext_len = sz(ciphertext); 587 679 write(db, &ciphertext_len, 1); 588 680 write(db, &ciphertext, ciphertext_len); 589 681 590 682 close(db); 591 683 break; 592 684 } 593 685 594 686 case delpw:{ /* kpw -d <acct> */ 687 + if (param == 0) return emit_usage(" -d <account>\n"); 688 + if (param != 1) return bad_syntax; 689 + const char* target = params[0]; 690 + bad e; 691 + 692 + int db = dbopen(O_RDWR); 693 + if (db == -1) return bad_db_load; 694 + 695 + const size_t dbsz = lseek(db, 0, SEEK_END); 696 + lseek(db, 0, SEEK_SET); 697 + 698 + key_pub pub; 699 + key_priv priv, priv_enc; 700 + 701 + byte salt [crypto_pwhash_SALTBYTES], 702 + salt_enc [crypto_box_SEALBYTES + sz(salt)]; 703 + 704 + if ((e = dbheader_load(db, salt, salt_enc, pub, priv_enc)) != ok) 705 + return e; 706 + if ((e = dbunlock(priv_enc, salt, priv)) != ok) 707 + return e; 708 + if ((e = dbverify(salt, salt_enc, pub, priv)) != ok) 709 + return e; 710 + 711 + byte newdb [dbsz]; 712 + byte* cursor = newdb; 713 + 714 + /* header is unchanged, so we copy it back out as is */ 715 + cursor = transcribe(cursor, pub, sz(pub)); 716 + cursor = transcribe(cursor, salt, sz(salt)); 717 + cursor = transcribe(cursor, priv_enc, sz(priv_enc)); 718 + cursor = transcribe(cursor, salt_enc, sz(salt_enc)); 719 + 720 + /* now we iterate through each record, decrypting them 721 + * with the keys we've obtained to compare the name 722 + * against the `target` specified by the user. all 723 + * records that do not match are written back to newdb, 724 + * while records that match are skipped. */ 725 + db_sz ctlen, ptlen; bool found = false; size_t scanned = 0; 726 + while((e = dbtell(db, &ctlen, &ptlen)) == ok) { 727 + ++ scanned; 728 + /* dbtell gives us the length of the buffers we 729 + * need to allocate, allowing us to keep all the 730 + * work on the stack and avoiding any malloc bs */ 731 + byte ctbuf [ctlen], 732 + ptbuf [ptlen]; 733 + struct dbrecord rec; 734 + 735 + bad d; 736 + if((d = dbnext(db, &rec, ctlen, 737 + pub, priv, ctbuf, ptbuf)) != ok) return d; 738 + 739 + if(strncmp(target, rec.acct.ptr, rec.acct.len) == 0) { 740 + /* found a matching record; do not copy it */ 741 + alert(a_debug, "found record to delete"); 742 + found = true; 743 + } else { 744 + /* not our target, copy it into the buffer */ 745 + cursor = transcribe(cursor, &ctlen, sizeof(db_sz)); 746 + cursor = transcribe(cursor, ctbuf, sz(ctbuf)); 747 + } 748 + 749 + } if (e != fail) return e; 750 + if (scanned == 0) return bad_db_empty; 751 + if (!found) return bad_index; 752 + /* newdb should now be an image of the database without 753 + * the offending record. we can now copy it back out to 754 + * disk, truncating the file to start from scratch. */ 755 + alert(a_debug, "writing modified db back out to disk"); 756 + ftruncate(db,0); 757 + lseek(db, 0, SEEK_SET); 758 + write(db, newdb, cursor-newdb); 759 + 760 + /* we're done here, time to close up shop */ 761 + close(db); 762 + 595 763 break; 596 764 } 597 765 598 766 case getpw: /* kpw <acct> */ 599 767 case lspw: { /* kpw -t[p] [<prefix>] */ 600 - alert(a_debug, "opening database for reading"); 601 - int db = dbopen(O_RDONLY); 602 - if (db == -1) return bad_db_load; 603 - 604 768 const char* target; 605 769 if (param == 1) target = params[0]; 606 770 else if (param == 0) target = NULL; 607 771 else return bad_syntax; 608 772 609 - uint8_t priv [db_privkey_len], 610 - pub [db_pubkey_len]; 773 + alert(a_debug, "opening database for reading"); 774 + int db = dbopen(O_RDONLY); 775 + if (db == -1) return bad_db_load; 776 + 777 + key_pub pub; 778 + key_priv priv; 611 779 612 780 /* try to decrypt db */ { 613 781 bad e = dbdecrypt(db,pub,priv); 614 782 if (e != ok) return e; 615 783 /* TODO allow multiple tries */ 616 784 } 617 785 618 - /* cursor should now be positioned 619 - * on first record */ 786 + /* cursor should be positioned on first 787 + * record if we've made it this far */ 620 788 alert(a_debug, "beginning to scan records"); 621 - read_rec: { 622 - uint8_t acctlen; 623 - if (read(db, &acctlen, 1) != 1) 624 - goto done_reading; 625 - uint8_t ciphertext[acctlen]; 626 - if (read(db, &ciphertext, acctlen) != acctlen) 627 - return bad_db_corrupt; 628 - alert(a_debug, "scanned record"); 629 - hexdump(ciphertext, sz(ciphertext)); 630 - 631 - uint8_t plaintext[sz(ciphertext) - crypto_box_SEALBYTES]; 632 - if(crypto_box_seal_open(plaintext, ciphertext, sz(ciphertext), pub, priv) != 0) 633 - return bad_db_corrupt; 634 - 635 - alert(a_debug, "record deciphered"); 636 - hexdump(plaintext, sz(plaintext)); 637 - 638 - uint8_t record_name_len = plaintext[0], 639 - record_pw_len = plaintext[record_name_len + 1]; 640 - 641 - pstr record_name = {record_name_len, plaintext + 1}, 642 - record_pw = {record_pw_len, 643 - plaintext + record_name_len + 2}; 789 + struct dbrecord rec; 790 + bool found = (op == lspw); 791 + enum bad result; 792 + db_sz ciphlen, plainlen; 793 + size_t scanned = 0; 794 + while ((result = dbtell(db, &ciphlen, &plainlen)) == ok) { 795 + ++ scanned; 796 + byte ctbuf[ciphlen], ptbuf[plainlen]; 797 + if ((result = dbnext(db, &rec, ciphlen, 798 + pub, priv, 799 + ctbuf, ptbuf)) != ok) 800 + break; 644 801 645 802 if(op == lspw) { 646 - bright(1, record_name.ptr, record_name.len); 803 + bright(1, rec.acct.ptr, rec.acct.len); 647 804 if (print || !isatty(1)) { 648 805 write(1, ": ", 2); 649 - write(1, record_pw.ptr, record_pw.len); 806 + write(1, rec.pw.ptr, rec.pw.len); 650 807 } 651 808 write(1, "\n", 1); 652 809 } else if (op == getpw) { 653 - if (strncmp(record_name.ptr,target,record_name.len) == 0) { 810 + if (strncmp(rec.acct.ptr,target,rec.acct.len) == 0) { 654 811 if (print || _g_term_type[1] == plain_term) { 655 - write(1, record_pw.ptr, record_pw.len); 812 + write(1, rec.pw.ptr, rec.pw.len); 656 813 if(_g_term_type[1] > plain_term) 657 814 write(1, "\n", 1); 658 815 } 659 816 660 817 if (_g_term_type[1] > plain_term) { 661 - if (copy_pw) copy(record_pw.ptr, record_pw.len); 818 + if (copy_pw) copy(rec.pw.ptr, rec.pw.len); 662 819 } 663 - goto done_reading; 820 + found = true; 821 + break; 664 822 } 665 823 } 666 - 667 - goto read_rec; 668 824 } 669 - return bad_index; 670 - 671 - done_reading: break; 825 + if (scanned == 0) return bad_db_empty; 826 + if (result != fail) return result; 827 + else if (!found) return bad_index; 828 + 829 + break; 672 830 } 673 831 674 832 case createdb: { /* kpw -C [<db>] */ 675 833 alert(a_debug, "creating new database"); 676 834 if (clobber) 677 835 alert(a_warn, "will clobber any existing database"); 678 836 /* before we open our new file, we need to generate 679 837 * our keypairs. the private key will be encrypted 680 838 * with a blake2 hash of a user-supplied passphrase 681 839 * and stored in the database after the unencrypted 682 840 * public key. 683 841 */ 684 - uint8_t pub [db_pubkey_len], 685 - priv[db_privkey_len]; 686 - uint8_t priv_enc[sz(priv)]; 842 + byte pub [db_pubkey_len], 843 + priv[db_privkey_len]; 844 + byte priv_enc[sz(priv)]; 687 845 688 846 alert(a_debug, "generating keypair"); 689 847 crypto_box_keypair(pub, priv); 690 848 691 849 /* kpw works very differently compared to 692 850 * most password managers. it uses public-key 693 851 * encryption so that new passwords can be saved ................................................................................ 707 865 e = pwread(!print, dbpw_conf, NULL, _str("- confirm: ")); 708 866 if (e != ok) return e; 709 867 710 868 if(strcmp(dbpw,dbpw_conf) != 0) 711 869 return bad_pw_match; 712 870 } 713 871 714 - uint8_t salt[crypto_pwhash_SALTBYTES], 715 - key[db_privkey_len]; 716 - uint8_t salt_enc[crypto_box_SEALBYTES + sz(salt)]; 872 + byte salt [crypto_pwhash_SALTBYTES], 873 + key[db_privkey_len]; 874 + byte salt_enc[crypto_box_SEALBYTES + sz(salt)]; 717 875 718 876 alert(a_debug, "generating salt"); 719 877 if (syscall(SYS_getrandom, salt, sz(salt), 0) == -1) 720 878 return bad_entropy; 721 879 hexdump(salt, sz(salt)); 722 880 723 881 alert(a_debug, "hashing database keyphrase");
Modified kpw.d/optab from [652ae10981] to [c9d99a07ce].
1 1 C create op = createdb create a new password database 2 2 R rekey op = rekeydb change database passphrase 3 +! clobber clobber = true disable safety checks 3 4 a add op = addpw add password to the database 4 5 g gen op = genpw add account with a random password 5 6 d del op = delpw delete password from the database 6 7 t list op = lspw list all accounts (with passwords if -p is set) 7 8 c chpw op = chpw change password in the database 9 +r regen op = regen generate new password for existing account 8 10 l lower mode = lower generate lowercase password 9 11 m mix mode = mix generate mix-case password 10 12 u upper mode = upper generate uppercase password 11 13 s stupid mode = stupid circumvent dumb pw restrictions 12 14 k key op = keyin save database key in session memory 13 15 o logout op = logout delete db key from session memory 14 16 n no-copy copy_pw = false print password instead of copying to clipboard _CLIPBOARD 15 17 p print print = true display passwords onscreen 16 18 q quiet _g_alert_quiet = true hide non-fatal reports 17 19 v verbose _g_debug_msgs = true display debug reports 18 -! clobber clobber = true disable safety checks 20 +h help op = help display help text