Jump to content
  • Join-Us

    https://metin2.dev is the 1st international community on Metin2 development. Join us to develop your skills and share your knowledge with the community, respectful and ethical forum.

Using BCrypt instead of the default MYSQL hashing for password storage


Recommended Posts

  • Premium

I was upgrading some stuff and I stumbled upon a little """"bug"""" with MariaDB who uses ma_make_scrambled_password instead of make_scrambled_password, which returned a completely different hash, so, instead of just settling in, I thought "why not just change it altogether?" 

At first I thought about SHA + salting but a colleague of mine told me about bcrypt, which, basically it already generates a random salt (it's more complicated than that, of course, but w/e, not important).

So, first of all, go to input_auth.cpp and search for:

	char szPasswd[PASSWD_MAX_LEN * 2 + 1];
	DBManager::instance().EscapeString(szPasswd, sizeof(szPasswd), passwd, strlen(passwd));

Replace with:

	char szPasswd[72]; //BCRYPT hash max length 71 + '\0'
	//DBManager::instance().EscapeString(szPasswd, sizeof(szPasswd), passwd, strlen(passwd)); //we are not passing passwd to the db anymore so we don't care to escape it

Then after

	char szLogin[LOGIN_MAX_LEN * 2 + 1];
	DBManager::instance().EscapeString(szLogin, sizeof(szLogin), login, strlen(login));

remove everything in the function but save in another txt what your QID_AUTH_LOGIN query was.

Then paste:

	std::unique_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT password FROM account WHERE login = '%s';", szLogin)); //select hashed password from db from login
	if(!pMsg->Get() || pMsg->Get()->uiNumRows == 0) //check if login exists
		LoginFailure(d, "NOID"); //login not exists
		sys_log(0, "   NOID");
		if(pMsg->Get()->uiNumRows > 0) //kinda redundant but ye
			MYSQL_ROW row;
			while ((row = mysql_fetch_row(pMsg->Get()->pSQLResult)))
				int col = 0;
				strncpy(szPasswd, row[col++], sizeof(szPasswd)); //copy the hash from db to szPasswd
		if(BCrypt::validatePassword(passwd,szPasswd)) //validate, and if it is valid, do the auth login query
			DBManager::instance().ReturnQuery(QID_AUTH_LOGIN, dwKey, p, 
				"SELECT social_id,id,status,availDt - NOW() > 0,"
				" FROM account WHERE login='%s'",
			LoginFailure(d, "WRONGPWD");
			sys_log(0, "   WRONGPWD");

Check your original query, add w/e it's missing, as long as it's not password related.


Then at the beginning of the file, add to the includes:

#include "bcrypt/BCrypt.hpp"
#include <memory> //IF NOT PRESENT ALREADY


Now, BCrypt.hpp, we don't have this. First of all, thanks to trusch who made a c++ wrapper for bcrypt (GitHub project 

This is the hidden content, please
), but you can also download the static lib already compiled
This is the hidden content, please
 (compiled on FreeBSD 13.0-Release, you can also compile it yourself reading the README file on the GitHub page).

Therefore, open Makefile (on the game sources folder) and add:

INCDIR += -I../../../Extern/include/bcrypt
LIBS += ../../../Extern/lib/libbcrypt.a

it should be something like:

# Boost
INCDIR += -I/usr/local/include/boost

INCDIR += -I../../../Extern/include/pcg

INCDIR += -I../../../Extern/include/bcrypt
LIBS += ../../../Extern/lib/libbcrypt.a

# DevIL
INCDIR += -I../../../Extern/include/IL
LIBS += ../../../Extern/lib/libIL.a\
INCDIR += -I/usr/local/include/mysql
LIBS += /usr/local/lib/mysql/libmariadbclient.a /usr/lib/libz.a

# CryptoPP
LIBS += ../../../Extern/lib/libcryptopp.a

just to give you an idea where you should place it.

Then of course, take the include folder from the GitHub link and add it to your extern folder.

Ah, shoot, remember the query? Well, it's not passing the password anymore, so open db.cpp and search for the function:

void DBManager::AnalyzeReturnQuery(SQLMsg * pMsg)

and replace this:

					// PASSWORD('%s'), password, securitycode, social_id, id, status
					char szEncrytPassword[45 + 1] = {0, };
					char szPassword[45 + 1] = {0, };


					// PASSWORD('%s'), password, securitycode, social_id, id, status
					//char szEncrytPassword[45 + 1] = {0, };
					//char szPassword[45 + 1] = {0, };

(or remove it, you know) and same thing for this:

					/*strlcpy(szEncrytPassword, row[col++], sizeof(szEncrytPassword));
					   	sys_err("error column %d", col);
					strlcpy(szPassword, row[col++], sizeof(szPassword));
						sys_err("error column %d", col); 

And we're done.

If you wanna generate your 12345 passwords or something you can use THIS link.


The end! 


EDIT: The end my ass, of course change your account table, the password column should be varchar(72) instead of the previous value.

Edited by xXIntelXx
  • Metin2 Dev 6
  • Love 9
  • Good 8
Link to comment
Share on other sites

  • 7 months later...
  • Premium

It's not working for me. I made a 12 round pw, always getting wrong password. doublechecked everything, there's no mistake

Link to comment
Share on other sites

  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.