MASTG-KNOW-0070: Random Number Generator
Random number generation is a critical component of many cryptographic operations, including key generation, initialization vectors, nonces, and tokens. Apple systems provide a trusted Cryptographically Secure Pseudorandom Number Generator (CSPRNG) that applications should use to ensure the security and unpredictability of generated random values. This CSPRNG is seeded from multiple entropy sources during system startup and over the lifetime of the device. These include the Secure Enclave hardware's True Random Number Generator (TRNG), timing jitter, entropy collected from hardware interrupts, etc.
The kernel CSPRNG is based on the Fortuna design and is exposed to user space via the/dev/random and/dev/urandom device files, as well as thegetentropy(2) system call.
Note that on Apple systems like iOS,/dev/random and/dev/urandom areequivalent and both provide cryptographically secure random numbers. However, using these device files directly in application code is discouraged. Instead, developers should use higher-level APIs likeSecRandomCopyBytes for generating random numbers.
SecRandomCopyBytes¶
As part of its Security framework, Apple provides aRandomization Services API, which generates cryptographically secure random numbers when calling theSecRandomCopyBytes function.
In Swift, it is used as follows:
varrandomBytes=[UInt8](repeating:0,count:16)letstatus=SecRandomCopyBytes(kSecRandomDefault,randomBytes.count,&randomBytes)TheSecRandomCopyBytes API is the recommended approach for generating cryptographically secure random numbers on iOS. It wrapsCCRandomCopyBytes from the CommonCrypto library, which in turn uses the system's CSPRNG.
frida-trace-n'MASTestApp'-i"SecRandomCopyBytes"...2960msSecRandomCopyBytes()2960ms|CCRandomCopyBytes()2960ms||CCRandomGenerateBytes()Swift Standard Library¶
Swift 4.2 introduced a new, native random API throughSE-0202, which unified and simplified random number generation within the Swift standard library. This API allows developers to generate random numbers directly from numeric types such asInt,UInt,Float,Double, andBool using therandom(in:) method, eliminating the need for directly using thearc4random_uniform() function in most cases.
vartoken=""for_in0..<16{letb=UInt8.random(in:0...255)token+=String(format:"%02x",b)}Under the hood, the Swift standard library usesSystemRandomNumberGenerator, which leverages platform-specific secure random mechanisms (the system's CSPRNG) and is automatically seeded and thread safe. On Apple platforms, the above methods are implemented under the hood usingarc4random_buf. You can observe this behavior using Frida to trace calls to the Swift random API.UInt8.random can be traced via the mangled symbol using the following pattern:
frida-trace-n'MASTestApp'-i"*FixedWidthInteger*random*"...2959ms$ss17FixedWidthIntegerPsE6random2inxSNyxG_tFZ()2959ms|arc4random_buf(buf=0x16ef965a8,nbytes=0x8)Therefore, using the Swift standard library's random APIs with the defaultSystemRandomNumberGenerator is generally suitable for cryptographic purposes on Apple platforms because that generator is defined to use a cryptographically secure algorithm backed by the system CSPRNG.
Note: The API also offers additional overloads that accept a custom random number generator conforming to theRandomNumberGenerator protocol. For example, the previousUInt8.random(in: 0...255) is an alias for:
varrng=SystemRandomNumberGenerator()letb=UInt8.random(in:0...255,using:&rng)But developers can implement their ownRandomNumberGenerator, which may not be secure. Therefore, when using custom generators, ensure they are suitable for cryptographic use cases. SeeSE-0202 for more details.
CommonCrypto¶
The CommonCrypto library provides theCCRandomGenerateBytes andCCRandomCopyBytes functions for generating cryptographically secure random bytes. While these functions are secure, they are lower-level APIs compared toSecRandomCopyBytes and require more careful handling by developers.
/dev/random¶
Direct use of/dev/random viaopen andread is discouraged because it is a low level interface that is easy to misuse from application code. On Apple platforms,/dev/random and/dev/urandom are backed by the same Fortuna based kernel CSPRNG and behave equivalently, so the usual Linux advice about/dev/random blocking when entropy is low does not apply here. For iOS apps, Apple recommends using higher level APIs such asSecRandomCopyBytes or the Swift standard library random APIs instead of reading these device files directly.
arc4random¶
Thearc4random family of functions (arc4random(),arc4random_buf(),arc4random_uniform()) is also available on iOS. On modern Apple platforms these functions are backed by the same kernel CSPRNG asSecRandomCopyBytes, and are suitable for cryptographic use, but they are legacy C style interfaces and are easier to misuse than the Swift standard library orSecRandomCopyBytes. For example:
- Using
arc4random() % nto generate a bounded value can introducemodulo bias, where some outcomes are slightly more likely than others. arc4random_buf()produces cryptographically strong random bytes into a caller provided buffer, and does not itself suffer from modulo bias. Any bias only appears if you convert those bytes to a bounded range incorrectly, for example by doing% non derived integers.arc4random_uniform(n)is specifically designed to avoid modulo bias for arbitrary upper bounds, returning a uniformly distributed integer in the range[0, n), and should be preferred overarc4random() % n.
For new Swift code, preferUInt8.random(in:) and related APIs orSecRandomCopyBytes, and reserve thearc4random family for interoperating with existing C and Objective C code.
Standard C Library Functions¶
The standard C library functionsrand(),random(), and their seed setting counterpartssrand() andsrandom() are not suitable for cryptographic purposes. Implementations ofrand() are usually linear congruential generators, and on Apple systemsrandom() uses a non linear additive feedback generator, but in all cases these are deterministic pseudorandom generators whose output can be predicted once the internal state or seed is known. See"Bugs" section of rand(3) for more details.
These APIs still exist insidelibSystem at runtime, but the Darwin headers mark them as unavailable to Swift by attaching a Swift availability attribute. Instdlib.h the declarations forrand,srand,random,rand_r and several*rand48 functions carry the availability annotation__swift_unavailable. So calling them from Swift produces an error that tells you they are unavailable in Swift.
Some of the*rand48 functions, for exampledrand48(), are still available, but they are also unsuitable for cryptographic purposes and should be avoided. These functions implement a linear congruential generator with a 48-bit state, which is not secure for cryptographic applications. They are also not thread safe and can produce predictable outputs if the seed is known.