void main(int argc, char **argv) { int isnew; char *id, buf[Maxmsg], home[Maxmsg], prompt[100], *hexHi; char *pass, *passck; long expsecs; mpint *H = mpnew(0), *Hi = mpnew(0); PW *pw; Tm *tm; ARGBEGIN{ case 'v': verbose++; break; }ARGEND; if(argc!=1){ fprint(2, "usage: secuser [-v] <user>\n"); exits("usage"); } ensure_exists(SECSTORE_DIR, DMDIR|0755L); snprint(home, sizeof(home), "%s/who", SECSTORE_DIR); ensure_exists(home, DMDIR|0755L); snprint(home, sizeof(home), "%s/store", SECSTORE_DIR); ensure_exists(home, DMDIR|0700L); id = argv[0]; if(verbose) fprint(2,"secuser %s\n", id); if((pw = getPW(id,1)) == nil){ isnew = 1; print("new account (because %s/%s %r)\n", SECSTORE_DIR, id); pw = emalloc(sizeof(*pw)); pw->id = estrdup(id); snprint(home, sizeof(home), "%s/store/%s", SECSTORE_DIR, id); if(access(home, AEXIST) == 0) sysfatal("new user, but directory %s already exists", home); }else{ isnew = 0; } /* get main password for id */ for(;;){ if(isnew) snprint(prompt, sizeof(prompt), "%s password: "******"%s password [default = don't change]: ", id); pass = getpassm(prompt); if(pass == nil) sysfatal("getpassm failed"); if(verbose) print("%ld characters\n", strlen(pass)); if(pass[0] == '\0' && isnew == 0) break; if(strlen(pass) >= 7) break; print("password must be at least 7 characters\n"); } if(pass[0] != '\0'){ snprint(prompt, sizeof(prompt), "retype password: "******"confirming...\n"); passck = getpassm(prompt); if(passck == nil) sysfatal("getpassm failed"); if(strcmp(pass, passck) != 0) sysfatal("passwords didn't match"); memset(passck, 0, strlen(passck)); free(passck); hexHi = PAK_Hi(id, pass, H, Hi); memset(pass, 0, strlen(pass)); free(pass); free(hexHi); mpfree(H); pw->Hi = Hi; } /* get expiration time (midnight of date specified) */ if(isnew) expsecs = time(0) + 365*24*60*60; else expsecs = pw->expire; for(;;){ tm = localtime(expsecs); print("expires [DDMMYYYY, default = %2.2d%2.2d%4.4d]: ", tm->mday, tm->mon+1, tm->year+1900); userinput(buf, sizeof(buf)); if(strlen(buf) == 0) break; if(strlen(buf) != 8){ print("!bad date format: %s\n", buf); continue; } tm->mday = (buf[0]-'0')*10 + (buf[1]-'0'); if(tm->mday > 31 || tm->mday < 1){ print("!bad day of month: %d\n", tm->mday); continue; } tm->mon = (buf[2]-'0')*10 + (buf[3]-'0') - 1; if(tm->mon > 11 || tm->mon < 0){ print("!bad month: %d\n", tm->mon + 1); continue; } tm->year = atoi(buf+4) - 1900; if(tm->year < 70){ print("!bad year: %d\n", tm->year + 1900); continue; } tm->sec = 59; tm->min = 59; tm->hour = 23; tm->yday = 0; expsecs = tm2sec(tm); break; } pw->expire = expsecs; /* failed logins */ if(pw->failed != 0 ) print("clearing %d failed login attempts\n", pw->failed); pw->failed = 0; /* status bits */ if(isnew) pw->status = Enabled; for(;;){ print("Enabled or Disabled [default %s]: ", (pw->status & Enabled) ? "Enabled" : "Disabled" ); userinput(buf, sizeof(buf)); if(strlen(buf) == 0) break; if(buf[0]=='E' || buf[0]=='e'){ pw->status |= Enabled; break; } if(buf[0]=='D' || buf[0]=='d'){ pw->status = pw->status & ~Enabled; break; } } for(;;){ print("require STA? [default %s]: ", (pw->status & STA) ? "yes" : "no" ); userinput(buf, sizeof(buf)); if(strlen(buf) == 0) break; if(buf[0]=='Y' || buf[0]=='y'){ pw->status |= STA; break; } if(buf[0]=='N' || buf[0]=='n'){ pw->status = pw->status & ~STA; break; } } /* free form field */ if(isnew) pw->other = nil; print("comments [default = %s]: ", (pw->other == nil) ? "" : pw->other); userinput(buf, 72); /* 72 comes from password.h */ if(buf[0]) if((pw->other = strdup(buf)) == nil) sysfatal("strdup"); syslog(0, LOG, "CHANGELOGIN for '%s'", pw->id); if(putPW(pw) < 0) sysfatal("can't write password file: %r"); else{ print("change written\n"); if(isnew && create(home, OREAD, DMDIR | 0775L) < 0) sysfatal("unable to create %s: %r", home); } exits(""); }
int main(int argc, char **argv) { int encrypt = 0; /* 0=decrypt, 1=encrypt */ int n, nkey, pass_stdin = 0, pass_nvram = 0; char *pass; unsigned char key[AESmaxkey], key2[SHA1dlen]; unsigned char buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */ AESstate aes; DigestState *dstate; Nvrsafe nvr; ARGBEGIN{ case 'e': encrypt = 1; break; case 'i': pass_stdin = 1; break; case 'n': pass_nvram = 1; break; }ARGEND; if(argc!=0){ fprint(2,"usage: %s -d < cipher.aes > clear.txt\n", argv0); fprint(2," or: %s -e < clear.txt > cipher.aes\n", argv0); exits("usage"); } Binit(&bin, 0, OREAD); Binit(&bout, 1, OWRITE); if(pass_stdin){ n = readn(3, buf, (sizeof buf)-1); if(n < 1) exits("usage: echo password |[3=1] auth/aescbc -i ..."); buf[n] = 0; while(buf[n-1] == '\n') buf[--n] = 0; }else if(pass_nvram){ if(readnvram(&nvr, 0) < 0) exits("readnvram: %r"); strecpy((char*)buf, (char*)buf+sizeof buf, (char*)nvr.config); n = strlen((char*)buf); }else{ pass = getpassm("aescbc key:"); n = strlen(pass); if(n >= BUF) exits("key too long"); strcpy((char*)buf, pass); memset(pass, 0, n); free(pass); } if(n <= 0) sysfatal("no key"); dstate = sha1((unsigned char*)"aescbc file", 11, nil, nil); sha1(buf, n, key2, dstate); memcpy(key, key2, 16); nkey = 16; md5(key, nkey, key2, 0); /* so even if HMAC_SHA1 is broken, encryption key is protected */ if(encrypt){ safewrite(v2hdr, AESbsize); genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */ setupAESstate(&aes, key, nkey, buf); /* use first AESbsize bytes as IV */ aesCBCencrypt(buf+AESbsize, AESbsize, &aes); /* use second AESbsize bytes as initial plaintext */ safewrite(buf, 2*AESbsize); dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0); for(;;){ n = Bread(&bin, buf, BUF); if(n < 0) sysfatal("read error"); aesCBCencrypt(buf, n, &aes); safewrite(buf, n); dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate); if(n < BUF) break; /* EOF */ } hmac_sha1(0, 0, key2, MD5dlen, buf, dstate); safewrite(buf, SHA1dlen); }else{ /* decrypt */ saferead(buf, AESbsize); if(memcmp(buf, v2hdr, AESbsize) == 0){ saferead(buf, 2*AESbsize); /* read IV and random initial plaintext */ setupAESstate(&aes, key, nkey, buf); dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0); aesCBCdecrypt(buf+AESbsize, AESbsize, &aes); saferead(buf, SHA1dlen); while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){ dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate); aesCBCdecrypt(buf, n, &aes); safewrite(buf, n); memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */ } hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate); if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0) sysfatal("decrypted file failed to authenticate"); }else{ /* compatibility with past mistake */ // if file was encrypted with bad aescbc use this: // memset(key, 0, AESmaxkey); // else assume we're decrypting secstore files setupAESstate(&aes, key, AESbsize, buf); saferead(buf, CHK); aesCBCdecrypt(buf, CHK, &aes); while((n = Bread(&bin, buf+CHK, BUF)) > 0){ aesCBCdecrypt(buf+CHK, n, &aes); safewrite(buf, n); memmove(buf, buf+n, CHK); } if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0) sysfatal("decrypted file failed to authenticate"); } } exits(""); return 1; /* keep other compilers happy */ }