2

I have a swift server, where currently authentication is handled through a simple email+hashed password combination. I want to replace this with an access token ( + expiration ) so I can remove the storage of email/password on the end-users device to slightly improve security, by making it easier to revoke access from specific end points.

Currently the implementation is cross platform, so I can develop locally ( xcode, macOS ) but run it on my ubuntu box. Therefore I need a cross platform way of generating random numbers.

After some searching obviously I came across /dev/urandom, so my question is is this safe enough to use? Or should I look into using something like arc4random+chacha20 and if so, why and is this implementation any good?

I am planning on using 128bits as a length, as I have read about 64bits simply not being secure enough ( though probably on my scale it would be. )

for reference, here is my current demo-implementation:

func random_data(_ length: Int) -> Data? {
    let stream = open("/dev/urandom", O_RDONLY)
    var buffer: [UInt8] = [UInt8](repeating: 0, count: length)

    let result = read(stream, &buffer, length)
    if result < 0 {
        return nil
    }
    return Data(bytes: buffer)
}

I have a secure strcmp function in my codebase to prevent timing attacks, but in any case I'll most likely be splitting it up in 2 int64's for verification. P.S. I still need to figure out if i want to zero out the memory of the randomly generated token after its work is done. This is a tedious task in swift.

Antwan van Houdt
  • 748
  • 1
  • 6
  • 9
  • yes, use `/urandom/`. DON'T try to roll your own with a chacha implementation you don't know all the details and advantages of. if in any doubt, and I mean any, use the most beaten path possible. In theory it can get (slightly) better than `/urandom/`, but you're FAR more likely to get something worse with a hidden implementation mistake, whereas urandom is "close the the best" and hard to screw up. – dandavis Jun 20 '17 at 18:26

2 Answers2

1

Yes, /dev/urandom is safe. There is no reason to use /dev/random instead - It's really not safer.

Dessa Simpson
  • 295
  • 3
  • 14
  • At the risk of starting a flamewar, `/dev/random` _can_ be safer in some situations. For example embedded devices or IoT devices, (ex. home routers), on first-time boot after the assembly line. In this case `/dev/urandom` will give you exactly the same bit-stream as every other device from the same assembly line, so you really do need to wait for `/dev/random` to finish blocking. It drives me nuts when people jump straight to a one-liner "Always / Never use `/dev/urandom`" while skipping over or ignoring all the context and subtlety. – Mike Ounsworth Aug 06 '17 at 01:07
1

/dev/urandom is the cross-platform solution you're looking for!

As @dandavis and @DuncanXSimpson have said, /dev/urandom is perfectly appropriate for this, and will behave the same way across all Linux and unix-like operating systems. If you want to be cross-platform with Windows, you'll need an if-statement to call into CAPI when in a Windows environment.

(Note that the internal implementations of /dev/urandom differ significantly between linux, BSD, OSX, and Solaris, causing much flame-war among cryptographers, but all are non-blocking, all are secure, and all will behave the same from your perspective.)


Note about rolling your own

Don't. As @dandavis said, taking a stream cipher like ChaCha and building an RNG out of it is surprisingly tricky to get right. And it's dangerous because it's the kind of thing that will look to a newbie like it's working when in fact it's riddled with subtle flaws.

As the old adage goes:

Anyone can build a system that he himself cannot break, but very few can build a system that nobody can break.

/dev/random and /dev/urandom are well-established RNGs intended for cryptographic use. Feel free to take advantage of them!


Note about /dev/random vs /dev/urandom

Welcome to the longest-running flame-war in cryptography!

There is no lack of google-able blog posts about this, but I will add that any article saying "Always use /dev/random" or "Always use /dev/urandom" is wrong, each has its place (except on FreeBSD and Solaris where they work totally differently and random is a symlink to urandom, existing only for cross-platform compatibility).

The subtle difference between them is that /dev/random will block and delay your program if it does not believe it has enough high-quality randomness to fill your request, while /dev/urandom will return something regardless of the quality (the 'u' stands for 'unlimited'). This is important in certain edge-cases, most notably in small embedded devices with no mouse/keyboard from which to draw randomness.

That said, for regular servers that have been up for more than an hour with lots of network traffic, or that are running on processors with built-in hardware RNGs (2013+ for Intel and 2015+ for AMD), then /dev/urandom is perfectly fine.

Mike Ounsworth
  • 57,707
  • 21
  • 150
  • 207