#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <crypto_scrypt.h>
#include "config.h"
#include "auth.h"
#include "util.h"
-
-#define TOKEN_SIZE 16
-#define MAX_PASSWORD_LENGTH 64
+#include "md5.h"
int auth_set_password(const char *username, const char *password) {
char filename[512];
- int fd, n;
+ unsigned char pwhash[SCRYPT_OUTPUT_SIZE];
+ unsigned char salt[SCRYPT_SALT_SIZE];
+ int fd, n, r;
if (!valid_name(username) || !blerg_exists(username))
return 0;
if (n > MAX_PASSWORD_LENGTH)
return 0;
+ /* Gather some salt */
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1) {
+ perror("Could not open /dev/urandom\n");
+ return 0;
+ }
+ read(fd, salt, SCRYPT_SALT_SIZE);
+ close(fd);
+
+ r = crypto_scrypt(password, n, salt, SCRYPT_SALT_SIZE, SCRYPT_N, SCRYPT_r, SCRYPT_p, pwhash, SCRYPT_OUTPUT_SIZE);
+ if (r != 0) {
+ printf("Failure in scrypt for %s\n", username);
+ return 0;
+ }
+
+ /* Write the password */
snprintf(filename, 512, "%s/%s/password", DATA_PATH, username);
fd = open(filename, O_WRONLY | O_CREAT, 0600);
- write(fd, password, n);
+ write(fd, pwhash, SCRYPT_OUTPUT_SIZE);
+ close(fd);
+
+ /* Write the salt */
+ snprintf(filename, 512, "%s/%s/password_salt", DATA_PATH, username);
+ fd = open(filename, O_WRONLY | O_CREAT, 0600);
+ write(fd, salt, SCRYPT_SALT_SIZE);
+ close(fd);
+
+ /* Mark this as a version 1 password */
+ snprintf(filename, 512, "%s/%s/password_version", DATA_PATH, username);
+ fd = open(filename, O_WRONLY | O_CREAT, 0600);
+ write(fd, "1\n", 2);
close(fd);
return 1;
}
+int auth_get_password_version(const char *username) {
+ char filename[512];
+ int fd;
+ char str[4];
+ int len;
+
+ sprintf(filename, "%s/%s/password_version", DATA_PATH, username);
+ if (access(filename, F_OK) != 0) {
+ return 0;
+ }
+
+ fd = open(filename, O_RDONLY);
+ len = read(fd, str, 4);
+ close(fd);
+ str[len] = 0;
+ /* strtol returns zero if there isn't a number */
+ return strtol(str, NULL, 10);
+}
+
int auth_get_password(const char *username, char *password) {
char filename[512];
int fd;
fd = open(filename, O_RDONLY);
if (fd == -1)
return 0;
- len = read(fd, password, MAX_PASSWORD_LENGTH);
+ switch(auth_get_password_version(username)) {
+ case 0:
+ len = read(fd, password, MD5_DIGEST_SIZE);
+ break;
+ case 1:
+ len = read(fd, password, SCRYPT_OUTPUT_SIZE);
+ break;
+ }
close(fd);
password[len] = 0;
return 1;
}
-int auth_check_password(const char *username, const char *password) {
- char epw[33];
+int auth_get_salt(const char *username, char *salt) {
+ char filename[512];
+ int fd, len;
+
+ if (!valid_name(username))
+ return 0;
+
+ sprintf(filename, "%s/%s/password_salt", DATA_PATH, username);
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ return 0;
+ len = read(fd, salt, SCRYPT_SALT_SIZE);
+ close(fd);
+
+ return 1;
+}
+
+int auth_check_password_v0(const char *username, const char *password) {
+ char epw[MD5_DIGEST_SIZE + 1];
+ unsigned char givenpw[MD5_DIGEST_SIZE];
+ struct MD5Context ctx;
+
+ if (auth_get_password(username, epw) == 0)
+ return 0;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, username, strlen(username));
+ MD5Update(&ctx, password, strlen(password));
+ MD5Final(givenpw, &ctx);
+
+ if (strncmp(givenpw, epw, MD5_DIGEST_SIZE) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+int auth_check_password_v1(const char *username, const char *password) {
+ unsigned char epw[SCRYPT_OUTPUT_SIZE];
+ unsigned char esalt[SCRYPT_SALT_SIZE];
+ unsigned char givenpw[SCRYPT_OUTPUT_SIZE];
+ int r;
if (auth_get_password(username, epw) == 0)
return 0;
- if (strncmp(password, epw, MAX_PASSWORD_LENGTH) == 0)
+ if (auth_get_salt(username, esalt) == 0)
+ return 0;
+
+ r = crypto_scrypt(password, strlen(password), esalt, SCRYPT_SALT_SIZE, SCRYPT_N, SCRYPT_r, SCRYPT_p, givenpw, SCRYPT_OUTPUT_SIZE);
+ if (r != 0) {
+ printf("Failure in scrypt for %s\n", username);
+ return 0;
+ }
+
+ if (memcmp(givenpw, epw, SCRYPT_OUTPUT_SIZE) == 0)
return 1;
else
return 0;
}
+int auth_check_password(const char *username, const char *password) {
+ int version = auth_get_password_version(username);
+
+ switch(version) {
+ case 0:
+ if (auth_check_password_v0(username, password)) {
+ /* Refresh to the newest version */
+ auth_set_password(username, password);
+ return 1;
+ } else {
+ return 0;
+ }
+ break;
+ case 1:
+ return auth_check_password_v1(username, password);
+ }
+}
+
void hexify(char *dst, char *src, int len) {
static char hex[] = "0123456789abcdef";
int i;