sqlickrypt: add support for salted SHA-512 passwords, and fix NULL bug.

Passwords will now be securely encrypted with random salt.  Also avoid
storing NULL in the database, because that makes dgamelaunch segfault.
This commit is contained in:
John "Elwin" Edwards 2013-10-20 21:19:13 -07:00
parent b760c1d444
commit 29edae364e

View file

@ -8,6 +8,7 @@
#define DATABASE "/dgldir/dgamelaunch.db" #define DATABASE "/dgldir/dgamelaunch.db"
#define IBUFSIZE 200 #define IBUFSIZE 200
#define RANDOMSRC "/dev/urandom"
/* General idea for return status: /* General idea for return status:
* 0: success * 0: success
@ -42,6 +43,41 @@ void cleanup(sqlite3 *db, sqlite3_stmt *stmt, int status) {
return; return;
} }
char encode64(unsigned char c) {
if (c < 26)
return 'a' + c;
else if (c < 52)
return 'A' + c - 26;
else if (c < 62)
return '0' + c - 52;
else if (c == 62)
return '.';
else
return '/';
}
/* Initializes a SHA-512 salt. salt must contain at least 20 bytes. */
void setsalt(char *salt) {
unsigned char rnbytes[3], rnvals[4];
FILE *urandom;
int loop;
salt[0] = salt[2] = salt[19] = '$'; /* Delimiters */
salt[1] = '6'; /* SHA-512 */
urandom = fopen(RANDOMSRC, "r");
for (loop = 0; loop < 4; loop++) {
fread(rnbytes, 1, 3, urandom);
rnvals[0] = rnbytes[0] >> 2;
rnvals[1] = ((rnbytes[0] & 0x03) << 4) | ((rnbytes[1] & 0xf0) >> 4);
rnvals[2] = ((rnbytes[1] & 0x0f) << 2) | ((rnbytes[2] & 0xc0) >> 6);
rnvals[3] = rnbytes[2] & 0x3f;
salt[loop * 4 + 3] = encode64(rnvals[0]);
salt[loop * 4 + 4] = encode64(rnvals[1]);
salt[loop * 4 + 5] = encode64(rnvals[2]);
salt[loop * 4 + 6] = encode64(rnvals[3]);
}
fclose(urandom);
}
int check(char *uname, char *pw) { int check(char *uname, char *pw) {
char *pwhash, *comphash; char *pwhash, *comphash;
char *query = "SELECT password FROM dglusers WHERE username=?;"; char *query = "SELECT password FROM dglusers WHERE username=?;";
@ -76,10 +112,11 @@ int check(char *uname, char *pw) {
int insertuser(char *uname, char *pw, char *email) { int insertuser(char *uname, char *pw, char *email) {
char *checkquery = "SELECT * FROM dglusers WHERE username = ?;"; char *checkquery = "SELECT * FROM dglusers WHERE username = ?;";
char *addquery = "INSERT INTO dglusers (username, password, email) VALUES (?, ?, ?);"; char *addquery = "INSERT INTO dglusers (username, password, email, flags, env) VALUES (?, ?, ?, ?, ?);";
int status; int status;
sqlite3 *db; sqlite3 *db;
sqlite3_stmt *qstmt; sqlite3_stmt *qstmt;
char salt[20];
opendb(&db, &qstmt, checkquery); opendb(&db, &qstmt, checkquery);
/* Check for existing account in the same transaction with creating it. */ /* Check for existing account in the same transaction with creating it. */
@ -96,13 +133,16 @@ int insertuser(char *uname, char *pw, char *email) {
return 3; return 3;
} }
/* The username doesn't exist yet, so create a new account. */ /* The username doesn't exist yet, so create a new account. */
setsalt(salt);
sqlite3_finalize(qstmt); sqlite3_finalize(qstmt);
sqlite3_prepare_v2(db, addquery, -1, &qstmt, NULL); sqlite3_prepare_v2(db, addquery, -1, &qstmt, NULL);
if (qstmt == NULL) if (qstmt == NULL)
cleanup(db, NULL, 3); cleanup(db, NULL, 3);
sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT); sqlite3_bind_text(qstmt, 1, uname, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(qstmt, 2, strdup(crypt(pw, pw)), -1, free); sqlite3_bind_text(qstmt, 2, strdup(crypt(pw, salt)), -1, free);
sqlite3_bind_text(qstmt, 3, email, -1, SQLITE_TRANSIENT); sqlite3_bind_text(qstmt, 3, email, -1, SQLITE_TRANSIENT);
sqlite3_bind_int(qstmt, 4, 0);
sqlite3_bind_text(qstmt, 5, "", -1, SQLITE_STATIC);
status = sqlite3_step(qstmt); status = sqlite3_step(qstmt);
if (status != SQLITE_DONE) if (status != SQLITE_DONE)
cleanup(db, qstmt, 3); cleanup(db, qstmt, 3);
@ -160,10 +200,10 @@ int setpw(char *uname, char *newpw) {
sqlite3_stmt *qstmt; sqlite3_stmt *qstmt;
int status; int status;
char *hash; char *hash;
char salt[20];
/* This is not a smart use of crypt, but it needs to be compatible with setsalt(salt);
* dgamelaunch. */ hash = crypt(newpw, salt);
hash = crypt(newpw, newpw);
opendb(&db, &qstmt, setquery); opendb(&db, &qstmt, setquery);
status = sqlite3_bind_text(qstmt, 2, uname, -1, SQLITE_TRANSIENT); status = sqlite3_bind_text(qstmt, 2, uname, -1, SQLITE_TRANSIENT);
if (status) if (status)