C/C++ Salt Generation on FreeBSD and Password Hashing

SomeWG

New Member


Messages: 11

Hello.

I'm new to FreeBSD, and having trouble with generating salt for my user authentication system. I want to use bcrypt to hash (salted hash) passwords before storing them in MySQL/MariaDB. I'm using C CGI for now.

Answered questions:

- What is the difference between arc4random(3) and arc4random(9)?
- I'm having trouble understanding its syntax (I have read the man page), as to how to use it. I have seen a C++ example here: link . I would be happy if someone can provide a easy to understand C example.
- What is the return value of arc4random_buf ? nothing is given on the man page? Should I assume NULL if it fails?
- Is the FreeBSD arc4random still using RC4 or has it been updated to ChaCha20 ? Just saw the revision log
https://svnweb.freebsd.org/base/head/lib/libc/gen/arc4random.c?view=log
But it appears to be limited to FreeBSD 12. The FreeBSD 11 appears to not have it:
https://svnweb.freebsd.org/base/stable/11/lib/libc/gen/arc4random.c?view=log

Remaining questions:
- Is "arc4random" best suited to generate a random salt for hashing passwords with bcrypt? It seems, it would work, for now.
- Is this how I have to use Crypt(3) : char *myRV = crypt(passwordstring, $2$saltinbase64encoding); ? <-- do I have to base64 encode the data generated from arc4random?
-What should be the length of the salt for bcrypt? Is it exactly 128bits i.e., 16bytes ? I have confirmed it from someone else, and it appears to be exactly 128bit or 16 bytes
- Is FreeBSD implementation of bcrypt using ECB mode? Is it safe to use? (I'm asking because: https://packages.debian.org/stretch/bcrypt )

- What about securing the memory? At what point should I use explicit_bzero and perhaps mlock to prevent it from being swapped out?
 
Last edited:

Bobi B.

Well-Known Member

Reaction score: 197
Messages: 416

Section 3 are library functions, whereas section 9 are kernel APIs. Therefore arc4random(3) you would use from user space and arc4random(9) is when writing kernel code.

Basically calling just arc4random() would return a random 32-bit unsigned number. If you need a random number in range [0, 99] you do v = arc4random_uniform(100); for [100, 200] you do v = 100 + arc4random_uniform(101).

arc4random_buf() is declared as void, meaning it returns nothing.

How strong are your C programming language skills? I would strongly suggest you to go thru a good C programming language book first.
 
OP
S

SomeWG

New Member


Messages: 11

1. In regards to my C skills: Well I have implemented almost everything else, except the encryption part.

2. I have tried the following:

Code:
void *saltys = 0;
size_t saltysnum = 8;
arc4random_buf(saltys, saltysnum);
printf("Content-type: text/html\n\n");
printf("The random no is: %p", saltys);

My script is working fine without it. Compiling properly with it. But I'm getting a "500 internal server error" on running with this. Apache error log says: End of script output before headers: Test.cgi

following is working for me (as you suggested) but I don't need it to be exactly 32-bit (see point 6 in my original post above):
Code:
uint32_t saltys;
saltys = arc4random();
printf("Content-type: text/html\r\n");
printf("The random no is: %u \n", saltys);
 
Last edited:

Bobi B.

Well-Known Member

Reaction score: 197
Messages: 416

And I bet if you run dmesg(8) you'll see that your app dumped core, or likewise, crashed.

You need a C programming language book; take my word for it.

Your mistake is that you pass a null pointer to arc4random_buf(3), namely void *saltys = 0. In this particular case you can allocate a buffer on the stack:
C:
unsigned char salt[8];
arc4random_buf(salt, sizeof salt);
... but the printf(3) part is incorrect; that would print the buffer's address, not the random bits.
 
OP
S

SomeWG

New Member


Messages: 11

Regarding printf being wrong: Is it a problem of format specifier? What is the correct way of doing it.
 

ralphbsz

Son of Beastie

Reaction score: 2,357
Messages: 3,245

1. In regards to my C skills:
Let's look in your C code below for that:

Code:
1   void *saltys = 0;
2   size_t saltysnum = 8;
3   arc4random_buf(saltys, saltysnum);
4   printf("Content-type: text/html\n\n");
5   printf("The random no is: %p", saltys);
(I added line numbers)
Line 1: You just created a null pointer. You understand what the syntax "void *" means, right? It may be OK to create a null pointer here or there, but you shall never ever use it.

Line 2: You created a variable that has the value 8. Note that I said it is a variable, something that can change. Why did you create it? It will be used only once, in line 3. And there it is used as a constant. Why didn't you make it a constant instead? You could do the traditional C style way of making a constant (with a #define statement), or you could make it a C++-style constant. And since it is only used once, it's not clear to me that it actually makes sense to create a constant.

Line 3: You just used a null pointer. Your code will die.

Line 5: You are not actually printing the random values. You are printing the address of the buffer (pointed to by saltys) that shall contain the random values.

In summary, your C understanding is nearly non-existing, other than a superficial knowledge of the syntax.

Bobi B already posted a version of the code that fixes the problems in lines 1 through 4. Do you clearly understand the differences between his code and yours? Do you know the difference between a variable, a pointer, and an array? Do you know the rules for an array being turned into a pointer (for example when calling a function) and vice versa? Do you know the difference between heap and stack memory (a.k.a. allocated memory and local variables? If you are not 110% sure you can answer "yes" to these questions, then please please please get a C (or C++) book and read it and understand it.

To your last question: What printf format should be used? Well, that depends on the desired output. The arc4random function returns random bits. You seem to want 64 random bits, namely 8 bytes worth. How are you going to use them? Printing them in a string format makes very little sense, since interpreting many (most?) of the random bytes as characters will not give you printable characters. And some of the random characters will be the nul character (the one with a zero value, which terminates a string), namely on average 1/32nd of the time. Most likely, the next step of your program will want to use them as a binary value in an integer, so the data type "void *" (or the unsigned char, as Bobi B suggested) is probably not useful. Treating random numbers as integers is usually not useful either, since you tend to get very large numbers. I would print them as hexadecimal, that makes it clear that they are just collections of random bits. If you want to use unsigned char for now, this would work:
Code:
... Bobi B's code here
for (size_t i=0; i<8; ++i)
    printf("%2.2x", saltys[i])
printf("\n");

Here is a version with a more sensible data type:
Code:
uint64_t salt;
arc4random_buf(salt, sizeof salt);
printf("The salt is %16.16x\n", salt)
 
OP
S

SomeWG

New Member


Messages: 11

Hello Ralphbsz, thank you for your reply.

1. Regarding "void *" : No I'm not familiar with it. Can you explain in simpler words. Please. I had looked at the arc4random(3) man page, specifically:
void arc4random_buf([I][B][U]void[/U][/B][/I] [I]*buf[/I], [I]size[/I]_[I]t[/I] [I]nbytes[/I]);

2. I was only trying it out in a elementary way (start with something simple and then harden it). Besides, the code above was written in haste and before overdue-sleep. So yes, I made a noobish mistake. And yes I know constant definition for such usage.

5. Can you explain this a bit further. This is the part I least understand. I know what is the difference between a data pointed by a pointer and address of the pointer in memory. But I don't understand how the "%16.16x" works.

- Yes I looked at Bobi B. 's last reply and understood it. Yes I know the difference between the three. I would say that memory management is not my forte. But I'm working on it. And yes I have ample amount of good C books. Please don't repeat it again and again. I got your point.

- About what I want from arc4random: Well, I'm not sure exactly. It depends on bcrypt. What type of input for a salt does it take? I'm guessing random bits. But I'm not sure. Earlier I had just used the perl module for Bcrypt, so I had to think fairly less than in C. I only printed it to see that the script is working up till this point or not, (that much should have been obvious) even if it doesn't print all the random bits.

- Also, could

Well I'm surprised that no one has addressed the question in terms of bcrypt and other cryptography-related points of my original post. I had assumed that Bcrypt being a corner stone of not just the BSDs, but also the internet, would have many adept users here. I'm not calling anyone bad, and I know people have RL and all, but I'm genuinely a bit surprised on that account.

update:

I found this: https://www.usenix.org/legacy/event...s_html/node6.html#SECTION00051000000000000000

Q. Is this relevant and true? The current implementation in FreeBSD uses exactly 128-bit of Salt? Or is it upto 128-bit?

Also I found this:
https://packages.debian.org/stretch/bcrypt
bugs.debian.org/700758

Q. Is it a problem related to only the Debian package, or Bcrypt in general? I'm guessing the earlier hopefully.

Also it seems it is missing from GnuPG Available Hashing Algorithms list:
https://www.gnupg.org/documentation...ash-algorithms.html#Available-hash-algorithms
 

ralphbsz

Son of Beastie

Reaction score: 2,357
Messages: 3,245

1. Regarding "void *" : No I'm not familiar with it. Can you explain in simpler words.
In C and C++, "void" is a funny thing. It looks like it is a data type, like "int" or "double". Except it really isn't. When used as a return type or the argument list of a function, it means that a function doesn't return anything, or takes no arguments. So it is not a data type, but an indicator that shows you that there is nothing there.
"int foo(double x) { ... }" is a function that takes a double argument, and returns an int.
"void bar(void) { ... }" is a function that takes no arguments and returns nothing (in isolation, such a function would be useless, but let's use it as a didactic example). Now you could ask, why didn't the people who designed C make it more logical by simply having nothing? They could have done "bar() { ... }" to indicate the same thing. Well, the lack of return type would have broken the C parser (it wouldn't know whether you are defining a function or calling it). And the lack of argument list was used early on to distinguish between ANSI and K&R style argument lists (30 years ago). So the "data type" void is really just a historical artifact.

In contrast, void can be used to define a pointer. For example, "int* pInt" is a variable of type "pointer to an integer", and "double* pDouble" is a variable of type "pointer to a double" (I'm using a naming convention here that uses the prefix "p" for every pointer, just for extra clarity). Note that C distinguishes different pointer types by the kind of thing they point to; the reasons for that are partly historical (there used to be computers where a pointer to a character was different in hardware from a pointer to an integer, like the old Cyber 6xxx hardware with 60-bit integers and 6-bit characters, and character pointers had to have more bits), and partly architectural within the language (when you dereference an int*, the compiler knows that the result is an integer, not anything else). But since C is a low-level language, where you often have to deal directly with hardware or memory, it allows using a "void*" to indicate a pointer to some form of memory, without specifying what is inside the memory. To actually use a "void*", you have to cast it to a pointer to a concrete type. In C, that casting operation is implicit in function calls: If you have some data that is for example of type "char" (like a buffer of characters, meaning of single bytes), you can pass the address of a character (perhaps the beginning of the buffer) around in a void*, and use that as an argument to functions.
5. Can you explain this a bit further. This is the part I least understand. ... But I don't understand how the "%16.16x" works.
OK, so you have a pointer, and for our discussion it doesn't matter whether it is a char* or a void*. The printf family of functions is special, in that it can interpret the arguments passed to it in many ways. If your print format contains a "%p", then it will take the argument passed to it, assume it is a pointer, and print the value of the pointer itself in a readable format. For example, if "char* pChar" points to some characters that are in memory at address 0x12345678, then printing "printf("%p", pChar) will probably return the string "0x12345678". On the other hand, if you use the print format %s, then printf will assume that the pointer is a pointer to a string in memory (where a string is nothing but a set of char's, with a terminating nun), and it will print the content of the memory pointed to by pChar, which could for example be "the quick brown fox jumps over the lazy dog".

Now, let's talk about the %x printf format. It simply assumes that the data you give it is an integer, and shall be printed in hexadecimal. So if you do "i=100; printf("%x", i)", the result will be the string "64" (since the decimal number 100 is hexadecimal 0x64). Now, let's add the two decorations. First, let's assume that we have a variable "ell", which is of a 64-bit type (like uint64). If we do "printf("%16x", ell), then it will print exactly 16 characters. If I initialize ell to the value 0x1234567812345678, then the result of the printf will be the string "1234567812345678", and if I initialize ell to zero, the result will be " 0" (there are 15 spaces before the zero). General rule for printf formats: If you put a number in front of the format specifier, it will tell printf how long to make the output, in this case 16 characters. By the way, why did I pick 16 characters? Because a 64-bit number can always be printed using 16 hex characters (every hex character can show you 4 bits). Next complication: If you use the style "%16.16x", then for integer formats (like %d, %u and %x), this means print at least 16 non-blank characters. If I had used that format, the output would be the same "1234567812345678", but for the second example it would be "0000000000000000". I like doing that for hexadecimal numbers, because it shows the user the bit pattern. Another example where this comes in useful is printing money amounts: printf("$%d.%2d", dollars, cents) works really badly: while $1.99 looks good, $2. 0" looks stupid, with the extra space in-between and missing the second zero. Another really bad version is printf("$%d.%d", dollars, cents): it is also good for $1.99, but $2.0 looks even more wrong for a two-dollar price. So for printing this, you should use printf("$%d.%2.2d", dollars, cents) to get the expected $2.00.

Warning: The style "%4.2f" for floating-point (double) numbers means something completely different: Print a number with a total of 4 characters, and exactly two digits after the decimal point. That's a sad inconsistency in C, where the second number in the printf specification means something different for integers versus floating point. In general, the C language sucks, but that's a fact of life.

About your questions on salt in modern password encryption: No idea. Not my area of expertise.
 

Bobi B.

Well-Known Member

Reaction score: 197
Messages: 416

Op, no offense meant, but you're not yet ready to write backend code, even more: security-related code. Judging from your questions, you lack some essential C programming skills.

If you worked in our company you would not be allowed to write production code with no supervision.
 
OP
S

SomeWG

New Member


Messages: 11

Bobi B. I can't change your thinking, but I must say that its a long journey between "a start" and the production code. Have patience ;).

ralphbsz I will get back to you on the topic of "void" in a bit. I have understood the first part, the second part requires a bit careful reading.

Edit: Gentleman, after re-reading this thread a few times, I reckon I should not deny your sincere offer. Since you have repeated the 'get a good C programming book' notion for a total of 3 times, (in words that can demotivate a poor little heart) please do also suggest a good C programming book for me (that is up-to-date). Btw, my current favourite is C Primer Plus (5th Ed).

Thanks a lot guys in terms of the C code. Now I wait for someone to actually explain the cryptography part. Perhaps ShelLuser can help??
 
OP
S

SomeWG

New Member


Messages: 11

Hmm, I wonder why no has answered the cryptography part so far. Anyways, I have crossed out those questions, for which I have already found an answer in the meantime.

Also, On the crypt(3) page, there seems to be no mention of cost? bcrypt is suppose to have a cost between 4 to 31. Where do I have to put the cost setting?
If I look at the man page of linux version:
http://man7.org/linux/man-pages/man3/crypt.3.html
it recommends a format of "rounds=[I]xxx[/I]$" after $id$
is this the same in FreeBSD as well? Does it mean that the man page of crypt is lacking?

ralphbsz : In the meantime, I have confirmed that bcrypt requires exactly 128-bit salts. What data type should I use now? A c string "char *"? How do I print it out? %32.32x? And do you have any idea regarding mlock and explicit_bzero?

on the page: https://github.com/openbsd/src/blob/master/lib/libc/crypt/bcrypt.c
I saw this:
Code:
#define BCRYPT_MAXSALT 16
uint8_t csalt[BCRYPT_MAXSALT];
arc4random_buf(csalt, sizeof(csalt));

can you tell me why uint8_t is enough in their case? Btw, I'm using us-ascii charset.
 

ralphbsz

Son of Beastie

Reaction score: 2,357
Messages: 3,245

You need 128 bits. The variable csalt is an array of 16 uint8's, each of which is 8 bits (obviously, thence the name). So you have a buffer of 16x8 = 128 bits. The important thing to understand here: The variable csalt is not one uint8, nor is it a 128-bit integer, it is an array of 16 things.

You ask about printing it. That's not so easy, because it is an array, no longer a single variable. One option is very painful: printf("%2.2x%2.2x%2.2x ...", csalt[0], csalt[1], csalt[2], ...), with each of the "..." repeated 16 times. Painful but simple and obviously correct.

The other option is perverse. You can fake the compiler out, and tell it that csalt is really a 128-bit number. That would in theory work as follows:
Code:
uint8_t csalt[16];
arc4random(...);
__uint128_t* csalt_as_128 = (__uint128_t*) csalt;
printf("...");
The problem with this is: On normal 64-bit machines, there is no 128 bit standard data type. That's why I had to use the non-standard Gnu-C and Clang data type with the two leading underscores. The worse problem is: I don't know how to print a non-standard 128 bit variable.

Left as an exercise to the reader: Print the 128-bit buffer as four 32-bit numbers instead.
 

unitrunker

Aspiring Daemon

Reaction score: 250
Messages: 549

__int128 x = 12345678;
printf("%032llx\n", x);

Likely not portable but should work on x64.
 

Ahmad_1

New Member


Messages: 1

So what is the standard way of supplying salt to crypt(3) -- modular crypt, given it doesn't have salt generation functions built into it (as of 12.1) .. unlike OpenBSD's version of crypt(3)?

what is considered as best practice?
 
Top