Overview
Comment: | my monster liiiiives |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
5089ec59d3defea859326376fc3e5d4e |
User & Date: | lexi on 2019-08-15 12:31:05 |
Other Links: | manifest | tags |
Context
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 | |
11:24 | FUCK THIS SHIT check-in: 218f1d20c2 user: lexi tags: trunk | |
Changes
Modified kpw.d/errtab from [59271087af] to [763d2287dd].
5 5 user kpw started as wrong user 6 6 option unrecognized option passed 7 7 syntax invalid invocation syntax 8 8 entropy could not acquire entropy 9 9 copy could not copy password 10 10 pipe could not create pipe 11 11 insane your environment is not sane 12 +index no such entry in database 12 13 db_create database could not be created 13 14 db_load database could not be read 14 15 db_corrupt database corrupt 15 16 cancel user canceled operation notice 16 17 pw invalid password 17 18 pw_match passwords do not match 18 19 usage usage displayed to user debug 64 19 20 lib unspecified library error fatal 128 20 21 lib_sodium_init could not initialize libsodium
Modified kpw.d/kpw.c from [22f71ce9d0] to [7a6fbd2214].
232 232 pstr account; 233 233 pstr pw; 234 234 }; 235 235 236 236 enum term_clear {term_clear_line, 237 237 term_clear_screen}; 238 238 239 -void term_clear(enum term_clear behavior) { 239 +void term_clear(int tty, enum term_clear behavior) { 240 240 switch(behavior) { 241 - case term_clear_line: write(1,"\r\x1b[2K",5); break; 242 - case term_clear_screen: write(1,"\r\x1b[3J",5); break; 241 + case term_clear_line: write(tty,"\r\x1b[2K",5); break; 242 + case term_clear_screen: write(tty,"\r\x1b[3J",5); break; 243 243 } 244 244 } 245 -void term_bell() { 246 - write(1,"\a",1); 245 +void term_bell(int tty) { 246 + write(tty,"\a",1); 247 247 } 248 248 249 249 typedef char password[kpw_db_pw_max + 1]; 250 250 bad pwread(bool obscure, char* dest, size_t* out_len, const char* prompt, const size_t plen) { 251 251 if (isatty(0)) { 252 + int tty = 1; 253 + if (!isatty(tty)) tty = open("/dev/tty", O_WRONLY); 254 + if (tty == -1) return bad_insane; 255 + 252 256 struct termios initial; { 253 257 /* in order to take PW input, we need to shut 254 258 * off echo and canonical mode. now we're in 255 259 * charge of reading each keypress. */ 256 - tcgetattr(1, &initial); 260 + tcgetattr(tty, &initial); 257 261 struct termios nt = initial; 258 262 nt.c_lflag &= (~ECHO & ~ICANON); 259 - tcsetattr(1, TCSANOW, &nt); 263 + tcsetattr(tty, TCSANOW, &nt); 260 264 } 261 265 262 266 *dest = 0; 263 267 char* p = dest; 264 268 265 269 do { 266 - term_clear(term_clear_line); 267 - if (_g_term_type[1] >= ansi_term) write(1, "\x1b[1m", 4); 268 - write(1, prompt, plen); 269 - if (_g_term_type[1] >= ansi_term) write(1, "\x1b[21m", 5); 270 + term_clear(tty,term_clear_line); 271 + if (_g_term_type[0] >= ansi_term) write(tty, "\x1b[1m", 4); 272 + write(tty, prompt, plen); 273 + if (_g_term_type[0] >= ansi_term) write(tty, "\x1b[21m", 5); 270 274 271 275 if (obscure) for(size_t i = 0; i < p - dest; ++i) 272 - write(1, "*", 1); 273 - else write(1, dest, p-dest); 276 + write(tty, "*", 1); 277 + else write(tty, dest, p-dest); 274 278 275 279 char c; 276 280 if (read(0, &c, 1) == 1) { 277 281 switch (c) { 278 282 case '\n': case '\r': 279 283 /* accept pw */ 280 284 if (p > dest) goto end_read_loop; 281 285 else break; 282 286 case '\x1b': /* escape */ 283 - term_clear(term_clear_line); 287 + term_clear(tty, term_clear_line); 284 288 return bad_cancel; 285 289 case '\b': case '\x7f': 286 290 if (p > dest) *p--=0; 287 - else term_bell(); 291 + else term_bell(tty); 288 292 break; 289 293 default: 290 294 if (p - dest != 64) *p++=c; 291 - else term_bell(); 295 + else term_bell(tty); 292 296 } 293 297 } else { 294 298 /* either EOF or an error - either way, 295 299 * we're finished here */ 296 300 break; 297 301 } 298 302 } while(1); 299 - end_read_loop: term_clear(term_clear_line); 303 + end_read_loop: term_clear(tty, term_clear_line); 300 304 *p = 0; 301 305 if (out_len!=NULL) *out_len = p - dest; 302 306 303 307 /* return the terminal to normal */ 304 - tcsetattr(1, TCSANOW, &initial); 308 + tcsetattr(tty, TCSANOW, &initial); 309 + 310 + if (tty != 1) close(tty); 305 311 } else { 306 312 alert(a_warn, "reading pw from standard input"); 307 313 ssize_t ct = read(0, dest, kpw_db_pw_max); 308 314 dest[ct] = 0; 309 315 } 310 316 } 311 317 312 -#include <stdio.h> 313 318 int 314 319 dbopen(int flags) { 315 320 const char* dbpath = getenv("kpw_db"); 316 321 int db; 317 322 if (dbpath == NULL) { 318 323 const char* cfg = getenv("XDG_CONFIG_HOME"); 319 324 if (cfg == NULL) { ................................................................................ 333 338 char buf[cfglen + path[1].len + 1]; 334 339 bzero(buf, sz(buf)); 335 340 impose(path, sz(path), NULL, buf); 336 341 337 342 db = open(buf, flags, 0600); 338 343 } 339 344 } else { 340 - printf("path is %s", dbpath); 341 345 db = open(dbpath, flags, 0600); 342 346 } 343 347 344 348 return db; 345 349 } 346 350 347 351 void bytedump(uint8_t* bytes, size_t sz) { ................................................................................ 349 353 char tpl[] ="\x1b[35m \x1b[m"; 350 354 char* c = tpl + 5; 351 355 *c = bytes[i]; 352 356 if (*c < ' ' || *c > '~') *c='.', write(2, tpl, sz(tpl)); 353 357 else write(2, c, 1); 354 358 } 355 359 } 360 + 356 361 void hexdump(uint8_t* bytes, size_t sz) { 357 362 if(!_g_debug_msgs) return; 358 363 alert(a_debug, "printing hex dump"); 359 364 uint8_t* st = bytes; 360 365 for (size_t i = 0; i < sz; ++i) { 361 366 char hex[5] = " "; 362 367 kitoa(16, bytes[i], hex, hex + 2, NULL, true); ................................................................................ 369 374 } else if (i == sz - 1) { 370 375 write(2, _str("│ ")); 371 376 bytedump(st, (bytes + sz) - st); 372 377 write(2, "\n", 1); 373 378 } 374 379 } 375 380 } 381 + 382 +enum bad 383 +dbdecrypt(int db, uint8_t* pubkey, uint8_t* privkey) { 384 + password dbpw; size_t pwlen; 385 + 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)); 404 + 405 + alert(a_debug, "deriving secret"); 406 + if(crypto_pwhash(key, sz(key), dbpw, pwlen, salt, 407 + crypto_pwhash_OPSLIMIT_INTERACTIVE, 408 + crypto_pwhash_MEMLIMIT_INTERACTIVE, 409 + crypto_pwhash_ALG_DEFAULT) != 0) { 410 + return bad_mem; 411 + } 412 + hexdump(key, sz(key)); 413 + 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"); 419 + for (size_t i = 0; i < sz(key); ++i) { 420 + priv[i] = priv_enc[i] ^ key[i]; 421 + } 422 + hexdump(priv, sz(priv)); 423 + 424 + alert(a_debug, "loading verification hash"); 425 + read(db, salt_enc, sz(salt_enc)); 426 + hexdump(salt_enc, sz(salt_enc)); 427 + 428 + alert(a_debug, "decrypting verification hash"); 429 + int r = crypto_box_seal_open(salt_dec, salt_enc, 430 + sz(salt_enc), pub, priv); 431 + if (r != 0) return bad_pw; 432 + hexdump(salt_dec, sz(salt_dec)); 433 + 434 + if (memcmp(salt,salt_dec,sz(salt)) != 0) return bad_db_corrupt; 435 + 436 + /* TODO refactor to avoid unnecessary memcpy */ 437 + memcpy(privkey, priv, sz(priv)); 438 + memcpy(pubkey, pub, sz(pub)); 439 + 440 + return ok; 441 +} 442 + 443 +#include<stdio.h> 444 +void bright(int fd, const char* str, size_t len) { 445 + if (_g_term_type[fd] >= ansi_term) write(fd, _str("\x1b[1m")); 446 + write(fd, str, len); 447 + if (_g_term_type[fd] >= ansi_term) write(fd, _str("\x1b[21m")); 448 +} 376 449 377 450 int 378 451 kpw(int argc, const char** argv) { 379 452 if (argc == 0) return bad_insane; 380 453 _g_binary_name = argv[0]; 381 454 382 455 enum genmode ................................................................................ 430 503 return bad_usage; 431 504 } 432 505 433 506 if (sodium_init() < 0) 434 507 return bad_lib_sodium_init; 435 508 436 509 switch(op) { 437 - case getpw:{ /* kpw <acct> */ 438 - break; 439 - } 440 - 510 + 441 511 case genpw: /* kpw -g[lmu] <acct> [<len>] */ 442 512 case addpw: { /* kpw -a <acct> [<pw>] */ 443 513 if (param > 2 || param < 1) return bad_syntax; 444 514 const char* acct = params[0], 445 515 * prm = (param == 2 ? params[1] : NULL); 446 516 447 517 alert(a_debug, "opening database"); ................................................................................ 521 591 break; 522 592 } 523 593 524 594 case delpw:{ /* kpw -d <acct> */ 525 595 break; 526 596 } 527 597 598 + case getpw: /* kpw <acct> */ 528 599 case lspw: { /* kpw -t[p] [<prefix>] */ 529 600 alert(a_debug, "opening database for reading"); 530 - int db = dbopen(O_RDONLY); 531 - if (db == -1) return bad_db_load; 532 - password dbpw; size_t pwlen; 533 - bad e = pwread(!print, dbpw, &pwlen,_str("database key: ")); 534 - 535 - uint8_t salt [crypto_pwhash_SALTBYTES], 536 - key [db_privkey_len], 537 - priv_enc [db_privkey_len], 538 - priv [db_privkey_len], 539 - pub [db_pubkey_len]; 540 - uint8_t salt_enc [crypto_box_SEALBYTES + sz(salt)], 541 - salt_dec [sz(salt)]; 542 - bzero(salt_dec, sz(salt_dec)); 543 - 544 - alert(a_debug, "loading public key"); 545 - ssize_t sr = read(db, pub, sz(pub)); 546 - if (sr != sz(pub)) return bad_db_corrupt; 547 - hexdump(pub, sz(pub)); 548 - 549 - alert(a_debug, "loading password salt"); 550 - sr = read(db, salt, sz(salt)); 551 - if (sr != sz(salt)) return bad_db_corrupt; 552 - hexdump(salt, sz(salt)); 553 - 554 - alert(a_debug, "deriving secret"); 555 - if(crypto_pwhash(key, sz(key), dbpw, pwlen, salt, 556 - crypto_pwhash_OPSLIMIT_INTERACTIVE, 557 - crypto_pwhash_MEMLIMIT_INTERACTIVE, 558 - crypto_pwhash_ALG_DEFAULT) != 0) { 559 - return bad_mem; 601 + int db = dbopen(O_RDONLY); 602 + if (db == -1) return bad_db_load; 603 + 604 + const char* target; 605 + if (param == 1) target = params[0]; 606 + else if (param == 0) target = NULL; 607 + else return bad_syntax; 608 + 609 + uint8_t priv [db_privkey_len], 610 + pub [db_pubkey_len]; 611 + 612 + /* try to decrypt db */ { 613 + bad e = dbdecrypt(db,pub,priv); 614 + if (e != ok) return e; 615 + /* TODO allow multiple tries */ 616 + } 617 + 618 + /* cursor should now be positioned 619 + * on first record */ 620 + 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}; 644 + 645 + if(op == lspw) { 646 + bright(1, record_name.ptr, record_name.len); 647 + if (print || !isatty(1)) { 648 + write(1, ": ", 2); 649 + write(1, record_pw.ptr, record_pw.len); 650 + } 651 + write(1, "\n", 1); 652 + } else if (op == getpw) { 653 + if (strncmp(record_name.ptr,target,record_name.len) == 0) { 654 + if (print || _g_term_type[1] == plain_term) { 655 + write(1, record_pw.ptr, record_pw.len); 656 + if(_g_term_type[1] > plain_term) 657 + write(1, "\n", 1); 658 + } 659 + 660 + if (_g_term_type[1] > plain_term) { 661 + if (copy_pw) copy(record_pw.ptr, record_pw.len); 662 + } 663 + goto done_reading; 664 + } 665 + } 666 + 667 + goto read_rec; 560 668 } 561 - hexdump(key, sz(key)); 669 + return bad_index; 562 670 563 - alert(a_debug, "loading encrypted private key"); 564 - read(db, priv_enc, sz(priv_enc)); 565 - hexdump(priv_enc, sz(priv_enc)); 566 - 567 - alert(a_debug, "decrypting private key"); 568 - for (size_t i = 0; i < sz(key); ++i) { 569 - priv[i] = priv_enc[i] ^ key[i]; 570 - } 571 - hexdump(priv, sz(priv)); 572 - 573 - alert(a_debug, "loading verification hash"); 574 - read(db, salt_enc, sz(salt_enc)); 575 - hexdump(salt_enc, sz(salt_enc)); 576 - 577 - alert(a_debug, "decrypting verification hash"); 578 - hexdump(pub, sz(pub)); 579 - hexdump(priv, sz(priv)); 580 - printf("sz salt_enc = %zu\n / crypto_box bytes = %zu", sz(salt_enc), crypto_box_SEALBYTES); 581 - int r = crypto_box_seal_open(salt_dec, salt_enc, 582 - sz(salt_enc), pub, priv); 583 - printf("result code: %d\n",r); 584 - hexdump(salt_dec, sz(salt_dec)); 585 - break; 671 + done_reading: break; 586 672 } 587 673 588 674 case createdb: { /* kpw -C [<db>] */ 589 675 alert(a_debug, "creating new database"); 590 676 if (clobber) 591 677 alert(a_warn, "will clobber any existing database"); 592 678 /* before we open our new file, we need to generate ................................................................................ 647 733 for (size_t i = 0; i < sz(key); ++i) { 648 734 priv_enc[i] = priv[i] ^ key[i]; 649 735 } 650 736 alert(a_debug, "private key encrypted"); 651 737 hexdump(priv_enc, sz(priv_enc)); 652 738 653 739 alert(a_debug, "encrypting salt"); 654 - crypto_box_seal(salt_enc, salt, sz(salt), priv); 740 + crypto_box_seal(salt_enc, salt, sz(salt), pub); 655 741 hexdump(salt_enc, sz(salt_enc)); 656 742 657 743 /* we have everything we need. now we create the 658 744 * file, failing if it already exists so as not 659 745 * to clobber anyone's passwords. 660 746 */ 661 747 alert(a_debug, "creating new database on disk");