42 comments

[ 2.6 ms ] story [ 75.1 ms ] thread
Can someone much smarter than I tell me if this is safe to use? Or better yet, when a time period has passed to consider it safe to use?
It's probably save to use in the sense that there are a number of projects (dnscrypt, zeromq, tox, ...) are using it already.
When I first started paging through the docs it seemed like sort of a useless, dangerous thing. But now (after reading your comment and looking those projects up) it seems like it's an officially blessed version of NaCL, which makes it seem much safer.
It's better if you don't build crypto directly into your application at all, because you can still screw things up even if you build on Nacl. But with that said: Sodium/Nacl is better than virtually any of your other options for working directly with cryptography.
"It's better if you don't build crypto directly into your application at all"

Plaintext all of the things! :P

I'm curious to know what you'd recommend for people who are looking to build applications around novel network protocols that aren't interested in the the certificate authority aspect of TLS?
There's no reason you have to use CAs to authenticate TLS. Plenty of enterprise tools keep whitelists of certificate hashes instead.
There are several TLS modes that don't use certificates. SRP and PSK are the two that I have some limited experience with. Both require sharing a password or key beforehand through some other medium.

If you're not concerned with man-in-the-middle attacks, then you could also use the ANON modes.

If you control the client software, theres no reason to use a certificate authority instead of making your own CA or just using self-signed certificates.
> It's better if you don't build crypto directly into your application at all, because you can still screw things up even if you build on Nacl.

Nacl was built to provide an API that is incredibly hard to screw up. That was one of djbs primary motivations. If you just need asymmetric encryption, or signing, or hashing, then it's the bees knees. These broad concepts aren't difficult to comprehend, and every developer should strive to understand and be able to use them. We shouldn't be encouraging people to be afraid... especially when things like dumb, plaintext username and password authentication is routinely implemented by developers without a second thought already.

Nacl makes it hard to screw up the constructions. It doesn't make it hard to make invalid assumptions about what a signed encrypted blob actually means.
+ makes it easy to add two numbers. It doesn't make it hard to make invalid assumptions about what adding two numbers together actually means.
Nacl is a good thing. But crypto is just a tool. It's not a magic wand. People have already built vulnerable systems by making bogus assumptions about what Nacl can do.
Can you recommend how to wrap crypto _around_ our applications if we aren't building it in?
(comment deleted)
I believe it's safe to use in the sense of being stable. I don't believe they've had a full security audit yet, though.
Let's not wait 5 years then crowdfund it like TrueCrypt ;)
People have weird ideas about the protective powers of a "full security audit". This is Bernstein, Lange, and Schwabe's code. There aren't many auditors qualified to review it.
It's more about having a third party look at it rather than the credentials of the authors being in question.
I understand the idea, but again: there aren't many third parties that are qualified to evaluate crypto code at all.
To add to what others have said here, I'll point you to the authors of TweetNaCl, which sort-of competes with Sodium:

http://tweetnacl.cr.yp.to/papers.html

Little is said, other than that TweetNaCl is smaller and thus more easily auditable. No criticism. No pointing out failures. Considering the source, that's IMO a serious compliment. (For comparison, read what is said of OpenSSL...)

So in short, Sodium is a great library. It was forked from NaCl (the most trustable there is) and has some good features added, like scrypt, BLAKE2 and ChaCha.

I think NaCl, TweetNaCl, and Sodium are a great ecosystem, each with different strengths. All great libraries, and the only ones I'd recommend unless you're doing TLS.

The ecosystem is actually bigger, and includes projects such as TweetNaCl.js (pure Javascript implementation), Salt (pure PHP implementation) and Chaos.NaCl (pure C# implementation).

All these projects play well with each other: they have a decent set of primitives and constructions in common, accessible via a very similar API.

The only part of this I care about right now is the random number generation. It looks good. Pity there's no way to get a float though, for a drop-in drand replacement.
Generate 8 random bytes, shove them in an unsigned 64-bit int, then divide that number by 2^64 - 1. I assume that's what any function which returns a random value between 0.0 and 1.0 is actually doing.
It would probably be faster to directly 'hack' a raw IEEE 754 floating number:

http://en.wikipedia.org/wiki/IEEE_754-1985

The helpful Examples section already contains the numbers 0 and 1.

Let us assume that the output is supposed to be between 0 and 1; it seems that 0 should be inclusive and 1 exclusive for the most balanced 'quick' output.

Those two numbers have the leading binary format:

0 (8 or 11 bits exponent) (23 or 52 bits fraction) For either 32 or 64 bit floats.

Thus for a float (32 bit):

0 0 (7 bits) (23 bits) 30 bits of randomness are necessary, HOWEVER 0 01111111 is already one when the fraction is all 0s. The easiest solution I can see is to evenly drop some precision:

A reference for the casting procedure: http://en.wikipedia.org/wiki/Fast_inverse_square_root#Overvi...

Pseudo:

    uint32 randomNumber;
    ... set the random somehow, maybe rand() maybe /dev/urandom etc ...
    randomNumber &= 0x3F7FFFFF;
    return * (float *) &randomNumber;
There's a really big problem with dumping random bytes straight into a float, which is that you'll end up with a distribution that, while random, is not linear - i.e. the chance of it being between 0 and 0.5 will not be the same as the chance of it being between 0.5 and 1.0. This is because the gaps between representable numbers increases as the magnitude increases, i.e. there are "more numbers" between 0 and 1 than 100 and 101. The best technique I've found (so far) is to dump the bytes into an int, and divide.
Now that you mention it, that would also be an issue for the technique you describe; specifiable to the rounding characteristics for truncated numbers.

It's probably a better design idea to have a predictable sequence of float (like, application dependent) results and randomly select from within said sequence.

In my (naive and possibly flawed) tests, the division method is giving uniformly distributed results. Can you explain more what the limitations of that approach are?
The default rounding method is round-to-even, so e.g. 0.9999999 would be expected to come up slightly more often than 0.99999994 (the last two floats smaller than 1).

Being more precise would probably require thinking about all the possible int values.

If you put 0 (i.e., plus) in the sign bit, and 1023 (i.e., zero) in the exponent field, and 52 random bits in the fraction field, of an IEEE double, then you get a number between 1 (inclusive) and 2 (exclusive); the representable numbers in that range are evenly spaced, and if your random bits are good then they are all equally likely, so you've got a uniform random number between 1 and 2. Subtract 1 if you want a uniform random number between 0 and 1 (this doesn't lose information; if a number between 1 and 2 is representable, subtracting 1 yields a representable number).

If your machine happens to work the same way as mine, the following will do it (unportable, untested, yadda yadda):

    double randomDouble() {
      uint64_t bits = random64bits();
      bits &= ~(3ull<<62); // clear sign and MSB of expt
      bits |= (1023ull<<52); // rest of exponent is 1-bits
      return (*(double*)&bits) - 1;
    }
Interesting, I'll test this. Thanks!

Btw, what is the advantage of this over dividing? Is it faster, does it give better distribution?

It should be faster than dividing. It will give you a uniform distribution over some (but not all) of the representable values between 0.0 and 1.0 (there are as many representable values between e.g. 0.25 and 0.5 as there are between 0.5 and 1.0, so a uniform distribution over representable values probably isn't what you want), which is probably as good as you can do.
I'm dividing by UULONG_MAX + 1.0, because it expects a number between 0 (inclusive) and 1.0 (exclusive). I'm not sure how portable it is though.
How often do you need cryptographically secure random floats? (I'm genuinely interested in the use cases.)
I don't think it would be a common use-case when creating new software, but when patching legacy software to use better RNGs it's not unheard of for them to be using older RNGs that return a float between 0 and 1 (drand48 as an example).
I was reading around the zeroMQ implementation of secure messaging that uses this library. It seemed sensible enough (plaintext handshake, exchange session keys and hashes to verify long term keys). But it was entirely couched in "I am not a cryptographer" and "strawman only" caveats.

I appreciate the dangers of thinking "encryption cures all other bad decisions" but it would be useful to have a spectrum of security we can talk about.

I would love to see something like Big O notation for security - where we are 95% confident that the implementation has closed off vulnerabilities "on the order of published exploits, on the order of passive sniffing inside network, on the order of State level actor targeting your data"

I just wonder if we ever can say "hell yes this will do" as opposed to "well even Fort Knox might have a vulnerable point"

Edit: perhaps I mean "design patterns for security layers"