int main(int argc, char *const argv[]) { const char *fullName = "Robert Lee Mitchel"; const char *masterPassword = "******"; const char *siteName = "masterpasswordapp.com"; const uint32_t siteCounter = 1; const MPSiteType siteType = MPSiteTypeGeneratedLong; const MPSiteVariant siteVariant = MPSiteVariantPassword; const char *siteContext = NULL; struct timeval startTime; // Start MPW unsigned int iterations = 100; mpw_getTime( &startTime ); for (int i = 0; i < iterations; ++i) { const uint8_t *masterKey = mpw_masterKeyForUser( fullName, masterPassword, MPAlgorithmVersionCurrent ); if (!masterKey) ftl( "Could not allocate master key: %d\n", errno ); free( (void *)mpw_passwordForSite( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext, MPAlgorithmVersionCurrent ) ); free( (void *)masterKey ); if (i % ( iterations / 100 ) == 0) fprintf( stderr, "\rmpw: iteration %d / %d (%d%%)..", i, iterations, i * 100 / iterations ); } const double mpwSpeed = mpw_showSpeed( startTime, iterations, "mpw" ); // Start SHA-256 iterations = 45000000; uint8_t hash[32]; mpw_getTime( &startTime ); for (int i = 0; i < iterations; ++i) { SHA256_Buf( masterPassword, strlen( masterPassword ), hash ); if (i % ( iterations / 100 ) == 0) fprintf( stderr, "\rsha256: iteration %d / %d (%d%%)..", i, iterations, i * 100 / iterations ); } const double sha256Speed = mpw_showSpeed( startTime, iterations, "sha256" ); // Start BCrypt int bcrypt_cost = 9; iterations = 1000; mpw_getTime( &startTime ); for (int i = 0; i < iterations; ++i) { crypt( masterPassword, crypt_gensalt( "$2b$", bcrypt_cost, fullName, strlen( fullName ) ) ); if (i % ( iterations / 100 ) == 0) fprintf( stderr, "\rbcrypt (cost %d): iteration %d / %d (%d%%)..", bcrypt_cost, i, iterations, i * 100 / iterations ); } const double bcrypt9Speed = mpw_showSpeed( startTime, iterations, "bcrypt9" ); // Summarize. fprintf( stdout, "\n== SUMMARY ==\nOn this machine,\n" ); fprintf( stdout, " - mpw is %f times slower than sha256 (reference: 320000 on an MBP Late 2013).\n", sha256Speed / mpwSpeed ); fprintf( stdout, " - mpw is %f times slower than bcrypt (cost 9) (reference: 22 on an MBP Late 2013).\n", bcrypt9Speed / mpwSpeed ); return 0; }
int main (int argc, char **argv) { char *pass; char *salt; char *secret; struct passwd *pwd; if (argc !=2) err_quit ("Usage: new_crypt username"); if ((pwd = getpwnam (argv [1])) == NULL) err_quit ("%s: No such user", argv [1]); pass = getpassphrase ("Password: "******"Password = \"%s\"\n", pass); printf ("Salt = \"%s\"\n", salt); printf ("Secret = \"%s\"\n", secret); return (0); }
std::string bcrypt_salt(unsigned long count) { BOOSTER_LOG(debug,__FUNCTION__); char entropy[16]; std::ifstream f(RANDOM_DEVICE); f.read(entropy, sizeof(entropy)); if (f.gcount() != sizeof(entropy)) { BOOSTER_LOG(error,__FUNCTION__) << "Unable to get an entropy"; f.close(); return ""; } f.close(); char* retval = crypt_gensalt(CRYPT_PREFIX, count, entropy, sizeof(entropy)); if ( (retval == NULL) || ((retval != NULL) && (retval[0] == '\0'))) { BOOSTER_LOG(error,__FUNCTION__) << "Unable to generate a salt"; return ""; } return std::string(retval); }
int main(int argc, char *argv[]) { int ch, i; int password_fd = -1; unsigned int salt_minlen = 0; unsigned int salt_maxlen = 0; unsigned int rounds_support = 0; const char *salt_prefix = NULL; const char *salt_arg = NULL; unsigned int rounds = 0; char *salt = NULL; char rounds_str[30]; char *password = NULL; #ifdef ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain(NLS_CAT_NAME, LOCALEDIR); textdomain(NLS_CAT_NAME); #endif /* prepend options from environment */ argv = merge_args(getenv("MKPASSWD_OPTIONS"), argv, &argc); while ((ch = GETOPT_LONGISH(argc, argv, "hH:m:5P:R:sS:V", longopts, 0)) > 0) { switch (ch) { case '5': optarg = (char *) "md5"; /* fall through */ case 'm': case 'H': if (!optarg || strcaseeq("help", optarg)) { display_methods(); exit(0); } for (i = 0; methods[i].method != NULL; i++) if (strcaseeq(methods[i].method, optarg)) { salt_prefix = methods[i].prefix; salt_minlen = methods[i].minlen; salt_maxlen = methods[i].maxlen; rounds_support = methods[i].rounds; break; } if (!salt_prefix) { fprintf(stderr, _("Invalid method '%s'.\n"), optarg); exit(1); } break; case 'P': { char *p; password_fd = strtol(optarg, &p, 10); if (p == NULL || *p != '\0' || password_fd < 0) { fprintf(stderr, _("Invalid number '%s'.\n"), optarg); exit(1); } } break; case 'R': { char *p; long r; r = strtol(optarg, &p, 10); if (p == NULL || *p != '\0' || r < 0) { fprintf(stderr, _("Invalid number '%s'.\n"), optarg); exit(1); } rounds = r; } break; case 's': password_fd = 0; break; case 'S': salt_arg = optarg; break; case 'V': display_version(); exit(0); case 'h': display_help(EXIT_SUCCESS); default: fprintf(stderr, _("Try '%s --help' for more information.\n"), argv[0]); exit(1); } } argc -= optind; argv += optind; if (argc == 2 && !salt_arg) { password = argv[0]; salt_arg = argv[1]; } else if (argc == 1) { password = argv[0]; } else if (argc == 0) { } else { display_help(EXIT_FAILURE); } /* default: DES password */ if (!salt_prefix) { salt_minlen = methods[0].minlen; salt_maxlen = methods[0].maxlen; salt_prefix = methods[0].prefix; } if (streq(salt_prefix, "$2a$") || streq(salt_prefix, "$2y$")) { /* OpenBSD Blowfish and derivatives */ if (rounds <= 5) rounds = 5; /* actually for 2a/2y it is the logarithm of the number of rounds */ snprintf(rounds_str, sizeof(rounds_str), "%02u$", rounds); } else if (rounds_support && rounds) snprintf(rounds_str, sizeof(rounds_str), "rounds=%u$", rounds); else rounds_str[0] = '\0'; if (salt_arg) { unsigned int c = strlen(salt_arg); if (c < salt_minlen || c > salt_maxlen) { if (salt_minlen == salt_maxlen) fprintf(stderr, ngettext( "Wrong salt length: %d byte when %d expected.\n", "Wrong salt length: %d bytes when %d expected.\n", c), c, salt_maxlen); else fprintf(stderr, ngettext( "Wrong salt length: %d byte when %d <= n <= %d" " expected.\n", "Wrong salt length: %d bytes when %d <= n <= %d" " expected.\n", c), c, salt_minlen, salt_maxlen); exit(1); } while (c-- > 0) { if (strchr(valid_salts, salt_arg[c]) == NULL) { fprintf(stderr, _("Illegal salt character '%c'.\n"), salt_arg[c]); exit(1); } } salt = NOFAIL(malloc(strlen(salt_prefix) + strlen(rounds_str) + strlen(salt_arg) + 1)); *salt = '\0'; strcat(salt, salt_prefix); strcat(salt, rounds_str); strcat(salt, salt_arg); } else { #ifdef HAVE_SOLARIS_CRYPT_GENSALT salt = crypt_gensalt(salt_prefix, NULL); if (!salt) perror("crypt_gensalt"); #elif defined HAVE_LINUX_CRYPT_GENSALT void *entropy = get_random_bytes(64); salt = crypt_gensalt(salt_prefix, rounds, entropy, 64); if (!salt) { fprintf(stderr, "crypt_gensalt failed.\n"); exit(2); } free(entropy); #else unsigned int salt_len = salt_maxlen; if (salt_minlen != salt_maxlen) { /* salt length can vary */ srand(time(NULL) + getpid()); salt_len = rand() % (salt_maxlen - salt_minlen + 1) + salt_minlen; } salt = NOFAIL(malloc(strlen(salt_prefix) + strlen(rounds_str) + salt_len + 1)); *salt = '\0'; strcat(salt, salt_prefix); strcat(salt, rounds_str); generate_salt(salt + strlen(salt), salt_len); #endif } if (password) { } else if (password_fd != -1) { FILE *fp; char *p; if (isatty(password_fd)) fprintf(stderr, _("Password: "******"r"); if (!fp) { perror("fdopen"); exit(2); } if (!fgets(password, 128, fp)) { perror("fgets"); exit(2); } p = strpbrk(password, "\n\r"); if (p) *p = '\0'; } else { password = getpass(_("Password: "******"getpass"); exit(2); } } { const char *result; result = crypt(password, salt); /* xcrypt returns "*0" on errors */ if (!result || result[0] == '*') { fprintf(stderr, "crypt failed.\n"); exit(2); } /* yes, using strlen(salt_prefix) on salt. It's not * documented whether crypt_gensalt may change the prefix */ if (!strneq(result, salt, strlen(salt_prefix))) { fprintf(stderr, _("Method not supported by crypt(3).\n")); exit(2); } printf("%s\n", result); } exit(0); }
/*ARGSUSED*/ int files_update(attrlist *items, pwu_repository_t *rep, void *buf) { struct pwbuf *pwbuf = (struct pwbuf *)buf; struct passwd *pw; struct spwd *spw; attrlist *p; int aging_needed = 0; int aging_set = 0; int disable_aging; char *pword; int len; pw = pwbuf->pwd; spw = pwbuf->spwd; pwbuf->update_history = 0; /* * if sp_max==0 : disable passwd aging after updating the password */ disable_aging = (spw != NULL && spw->sp_max == 0); for (p = items; p != NULL; p = p->next) { switch (p->type) { case ATTR_NAME: break; /* We are able to handle this, but... */ case ATTR_UID: pw->pw_uid = (uid_t)p->data.val_i; break; case ATTR_GID: pw->pw_gid = (gid_t)p->data.val_i; break; case ATTR_AGE: pw->pw_age = p->data.val_s; break; case ATTR_COMMENT: pw->pw_comment = p->data.val_s; break; case ATTR_GECOS: pw->pw_gecos = p->data.val_s; break; case ATTR_HOMEDIR: pw->pw_dir = p->data.val_s; break; case ATTR_SHELL: pw->pw_shell = p->data.val_s; break; /* * Nothing special needs to be done for * server policy */ case ATTR_PASSWD: case ATTR_PASSWD_SERVER_POLICY: /* * There is a special case only for files: if the * password is to be deleted (-d to passwd), * p->data.val_s will be NULL. */ if (p->data.val_s == NULL) { spw->sp_pwdp = ""; } else { char *salt = NULL; char *hash = NULL; salt = crypt_gensalt(spw->sp_pwdp, pw); if (salt == NULL) { if (errno == ENOMEM) return (PWU_NOMEM); /* algorithm problem? */ syslog(LOG_AUTH | LOG_ALERT, "passwdutil: crypt_gensalt %m"); return (PWU_UPDATE_FAILED); } hash = crypt(p->data.val_s, salt); free(salt); if (hash == NULL) { errno = ENOMEM; return (PWU_NOMEM); } pword = strdup(hash); if (pword == NULL) { errno = ENOMEM; return (PWU_NOMEM); } if (pwbuf->new_sp_pwdp) free(pwbuf->new_sp_pwdp); pwbuf->new_sp_pwdp = pword; spw->sp_pwdp = pword; aging_needed = 1; pwbuf->update_history = 1; } spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */ spw->sp_lstchg = DAY_NOW_32; break; case ATTR_LOCK_ACCOUNT: if (spw->sp_pwdp == NULL) { spw->sp_pwdp = LOCKSTRING; } else if ((strncmp(spw->sp_pwdp, LOCKSTRING, sizeof (LOCKSTRING)-1) != 0) && (strcmp(spw->sp_pwdp, NOLOGINSTRING) != 0)) { len = sizeof (LOCKSTRING)-1 + strlen(spw->sp_pwdp) + 1; pword = malloc(len); if (pword == NULL) { errno = ENOMEM; return (PWU_NOMEM); } (void) strlcpy(pword, LOCKSTRING, len); (void) strlcat(pword, spw->sp_pwdp, len); if (pwbuf->new_sp_pwdp) free(pwbuf->new_sp_pwdp); pwbuf->new_sp_pwdp = pword; spw->sp_pwdp = pword; } spw->sp_lstchg = DAY_NOW_32; break; case ATTR_UNLOCK_ACCOUNT: if (spw->sp_pwdp != NULL && strncmp(spw->sp_pwdp, LOCKSTRING, sizeof (LOCKSTRING)-1) == 0) { (void) strcpy(spw->sp_pwdp, spw->sp_pwdp + sizeof (LOCKSTRING)-1); } spw->sp_lstchg = DAY_NOW_32; break; case ATTR_NOLOGIN_ACCOUNT: spw->sp_pwdp = NOLOGINSTRING; if (pwbuf->new_sp_pwdp) { free(pwbuf->new_sp_pwdp); pwbuf->new_sp_pwdp = NULL; } spw->sp_lstchg = DAY_NOW_32; break; case ATTR_EXPIRE_PASSWORD: spw->sp_lstchg = 0; break; case ATTR_LSTCHG: spw->sp_lstchg = p->data.val_i; break; case ATTR_MIN: if (spw->sp_max == -1 && p->data.val_i != -1 && max_present(p->next) == 0) return (PWU_AGING_DISABLED); spw->sp_min = p->data.val_i; aging_set = 1; break; case ATTR_MAX: if (p->data.val_i == -1) { /* Turn aging off -> Reset min and warn too */ spw->sp_min = -1; spw->sp_warn = -1; } else { /* Turn aging on */ if (spw->sp_min == -1) { /* * If minage has not been set with * a command-line option, we set it * to zero. */ spw->sp_min = 0; } /* * If aging was turned off, we update lstchg. * * We take care not to update lstchg if the * user has no password, otherwise the user * might not be required to provide a password * the next time they log-in. * * Also, if lstchg != -1 (i.e., not set in * /etc/shadow), we keep the old value. */ if (spw->sp_max == -1 && spw->sp_pwdp != NULL && *spw->sp_pwdp && spw->sp_lstchg == -1) { spw->sp_lstchg = DAY_NOW_32; } } spw->sp_max = p->data.val_i; aging_set = 1; break; case ATTR_WARN: if (spw->sp_max == -1 && p->data.val_i != -1 && max_present(p->next) == 0) return (PWU_AGING_DISABLED); spw->sp_warn = p->data.val_i; break; case ATTR_INACT: spw->sp_inact = p->data.val_i; break; case ATTR_EXPIRE: spw->sp_expire = p->data.val_i; break; case ATTR_FLAG: spw->sp_flag = p->data.val_i; break; case ATTR_INCR_FAILED_LOGINS: { int count = (spw->sp_flag & FAILCOUNT_MASK) + 1; spw->sp_flag &= ~FAILCOUNT_MASK; spw->sp_flag |= min(FAILCOUNT_MASK, count); p->data.val_i = count; } break; case ATTR_RST_FAILED_LOGINS: p->data.val_i = spw->sp_flag & FAILCOUNT_MASK; spw->sp_flag &= ~FAILCOUNT_MASK; break; default: break; } } /* * What should the new aging values look like? * * There are a number of different conditions * * a) aging is already configured: don't touch it * * b) disable_aging is set: disable aging * * c) aging is not configured: turn on default aging; * * b) and c) of course only if aging_needed and !aging_set. * (i.e., password changed, and aging values not changed) */ if (spw != NULL && spw->sp_max <= 0) { /* a) aging not yet configured */ if (aging_needed && !aging_set) { if (disable_aging) { /* b) turn off aging */ spw->sp_min = spw->sp_max = spw->sp_warn = -1; } else { /* c) */ turn_on_default_aging(spw); } } } return (PWU_SUCCESS); }