[Plugin] Bcrypt
#1

Bcrypt for SA-MP

Latest release: v2.2.3 (Jan 31, 2015)


Downloads
Source code
Wiki
Change log
Introduction

Bcrypt is a hash function designed particularly for passwords, which implements an
automatic salt on all passwords, and allows the work factor to be changed as the computers
become more powerful.

Bcrypt is widely recommended, and often considered as the most secure method for hashing passwords. Source

Benefits
  • All passwords are automatically salted.

  • Bcrypt is slow, which makes offline bruteforce attacks very hard (depends on the work factor).

  • The work factor can be increased as the computers become more powerful.

  • The plugin is multi threaded, so the impact on server performance is negligible.

  • Compatible with PHP's password_verify() and password_hash() functions.
Installation

With sampctl

Code:
sampctl package install lassir/bcrypt-samp:v2.2.3
Alternatively
  • Download the latest version of the plugins here.
  • Copy the plugin file and the include file to their appropriate directories
Usage
  • Include the .inc file in your filterscript or gamemode (#include <bcrypt>)

  • Call function bcrypt_check when you would like to verify whether or not user input matches a given
    hash (e.g. on login). Once the verification is done, the defined callback will be called, and the
    result can be acquired by calling function bcrypt_is_equal() in the callback.

  • If you ever change the cost, you may use bcrypt_needs_rehash function to check if the hash in the
    database should be updated. The function returns true if the hash should be rehashes, and false if the
    hash is up-to-date.
Functions Hash

Function bcrypt_get_hash returns the result from bcrypt_hash, which is a 61-character-long string
(60 + null terminator), which is also defined as constant BCRYPT_HASH_LENGTH.

Below is the output for hashing "Hello World!" three times. The hash is completely unique every time,
because a random salt is used when calculating the hash every time.
Code:
1. $2y$12$33T1WbJGYD9YVKpBShTDsOOlS3248tApLCndjz28n0cyWZR1HYXy6
2. $2y$12$ExnQyld7o8w0QbWmAJgsJuygOwlFlbMITgzuw9g.6jbnscTd5kSK6
3. $2y$12$ivsAFLaGM52oCZnFe/QKBuoJy0osV8UsbJODPBUxeY3XSBhr739Yi
Cost

Cost represents the work factor, which is proportional to the amount of time it takes to calculate a
hash, and thus how secure the hash is. Increasing the cost by one approximately doubles the time
required to calculate the hash. Cost 10-13 should be adequate for most servers. The range of allowed
values for the cost is 4-31.

Example

pawn Code:
#include <a_samp>
#include <bcrypt>

#define BCRYPT_COST 12

forward OnPasswordHashed(playerid);
forward OnPasswordChecked(playerid);

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    switch(dialogid)
    {
        case DIALOG_REGISTRATION:
        {
            bcrypt_hash(inputtext, BCRYPT_COST, "OnPasswordHashed", "d", playerid);
        }

        case DIALOG_LOGIN:
        {
            // Variable hash is expected to contain the hash loaded from the database
            bcrypt_check(inputtext, hash, "OnPasswordChecked", "d", playerid);
        }
    }

    return 1;
}

public OnPasswordHashed(playerid)
{
    new hash[BCRYPT_HASH_LENGTH];
    bcrypt_get_hash(hash);
    printf("Password hashed for player %d: %s", playerid, hash);
    return 1;
}

public OnPasswordChecked(playerid)
{
    new bool:match = bcrypt_is_equal();
    printf("Password checked for %d: %s", playerid, (match) ? ("Match") : ("No match"));
    return 1;
}
Trouble shooting

Problem:
The program can’t start because MSVCR120.dll is missing from your computer.

Solution:
Please download and install the 32-bit version of Visual C++ Redistributable Packages for Visual Studio 2013 (vcredist_x86.exe).

Credits
  • Johnson_boy
  • maddinat0r
Reply
#2

Nice, i test it
Reply
#3

Finally someone made it.
Good job.
Reply
#4

I looked @ your source and as far as I can say, this could crash your server!
Your call to the callbacks are done in a seperated thread and this can corrupt the amx-stack!

Look @ http://forum.sa-mp.com/showpost.php?...4&postcount=12
Reply
#5

If you want to use multiple threads, please make it atleast thread safe. As above roschti posted it can corrupt your AMX stack.

Also I don't think it's healthy to create always a new thread, once the native function has been called.
Reply
#6

Thanks for the feedback guys. I've put a warning of this issue to the main post while the issue still persists.

I'll have a look at the mysql plugins and attempt to fix it.
Reply
#7

I think I got it working. Could you check processtick branch (https://github.com/LassiR/bcrypt-samp/tree/processtick) and see if it looks alright? If it does, I'll merge it to master.
Reply
#8

Great! Now we aren't obligated to improvise salt for whirlpool hashed passwords!. Excellent work!
Reply
#9

Nice release, might consider switching to this over whirlpool hash.
Reply
#10

Ouch STL containers are not really thread safe. I've experimented with threads (from WINAPI) once, and it just accessed bad memory while the first thread was inserting information and the second one attempted to read it.

Also you are creating threads after the native function gets called. Realize your server attempts to call this native several times, and you are creating too many threads at once (again this can crash your application)
Reply
#11

Quote:
Originally Posted by BigETI
View Post
Ouch STL containers are not really thread safe. I've experimented with threads (from WINAPI) once, and it just accessed bad memory while the first thread was inserting information and the second one attempted to read it.

Also you are creating threads after the native function gets called. Realize your server attempts to call this native several times, and you are creating too many threads at once (again this can crash your application)
I decided to test this by calling bcrypt_hash (work factor 12) 400 times with a for loop. The server did not crash and calculated the hash for each call. It might be that the server crashes if even more concurrent threads are created, but I really doubt that's going to happen under normal circumstances.


Edit: As to the issue with thread safety, what would you recommend as a solution? Based on quick research, the use of mutexes seems promising.
Reply
#12

Happy to see this finally in a plugin!
Reply
#13

Suggestions:

http://www.boost.org/doc/libs/1_54_0...free.queue_hpp

Don't use more than 2 threads.

Implement a blocking function aswell for those having powerful servers.

Make `cost` a default parameter. Also, playerid parameter is useless, you'd better add an "threadidex" parameter.
pawn Code:
native bcrypt_hash(threadid, threadidex, password[], cost = 4);
Also, this means that you have to change the callback:
pawn Code:
forward OnBcryptHashed(threadid, threadidex, password[], hash[]);
Reply
#14

nice another hashin implementation
good will give ti a shot!
Reply
#15

I decided to use std::lock_guard to overcome the issue with vector's thread safety. It seemed the most suitable and secure solution (unlocks even on exceptions)

Quote:
Originally Posted by Dan..
View Post
Suggestions:

http://www.boost.org/doc/libs/1_54_0...free.queue_hpp

Don't use more than 2 threads.

Implement a blocking function aswell for those having powerful servers.

Make `cost` a default parameter. Also, playerid parameter is useless, you'd better add an "threadidex" parameter.
pawn Code:
native bcrypt_hash(threadid, threadidex, password[], cost = 4);
Also, this means that you have to change the callback:
pawn Code:
forward OnBcryptHashed(threadid, threadidex, password[], hash[]);
Thanks for the suggestions.

I added the default cost and changed playerid to thread_idx.

About limiting the amount of threads used to 2: Why should this be done? Does it increase stability?
Reply
#16

The amount of resources wasted creating a new thread, executing it parallelly, collecting the result (there is a mutex that will waste a little more), sending it back to the main thread, killing the thread is way too big. You shouldn't need more than two threads (SA-MP's ProcessTick - to communicate with the AMX and another one for computing).
Reply
#17

Quote:
Originally Posted by ******
View Post
I would actually disagree with that. Creating threads does have a lot of overhead, but if you can create a pool of workers somewhat equal to the virtual cores on your machine then you will improve performance with more than 2.
You can't compare this situation to real life workers. Believe me or not for some unknown reason at some point it will behave weird, especially if you are working with dynamic memory. I can rely on facts I've collected by doing tests on multiple threads. I've made once a test application running at 3 threads (all threads include an inner infinite loop for processing 3 tasks at once all the time). No STL containers was involved, but at some point suddenly you access bad memory by even testing pointers for not returning zero. However at using 2 threads, it was running quite harmless (Yes, I am still using a dual core processor). Also you have to decide how many threads you want to use at once, because a processor with 2, 4, 6 or 8 cores can only work efficient at the amount of current important threads equals the amount of cores a processor has. I don't know what is more efficient, but are 8 threads doing something on a dual core processor more efficient than 4 threads doing something on a dual core processor?
Reply
#18

Finally! Well done!

Is it possible for a non-threaded version? Thanks.
Reply
#19

Quote:
Originally Posted by ******
View Post
I would actually disagree with that. Creating threads does have a lot of overhead, but if you can create a pool of workers somewhat equal to the virtual cores on your machine then you will improve performance with more than 2.
Creating threads doesn't have a lot of overhead, but creating a new thread, executing it parallelly, collecting the result (there is a mutex that will waste a little more), sending it back to the main thread, killing the thread does.
Reply
#20

Quote:
Originally Posted by Lorenc_
View Post
Finally! Well done!

Is it possible for a non-threaded version? Thanks.
It's possible, but does not really make sense. If everything is executed in one thread, the server will have to wait while the hash is calculated, which will be noticed as lag by the players. Calculating a bcrypt hash takes a significant amount of time, about 0.5 seconds, when a work factor of appropriate magnitude is used.
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)