Skip to main content

Insecure generation of random numbers

Need

Secure generation of random numbers

Context

  • Usage of Dart for building cross-platform mobile, web, and desktop applications
  • Usage of dart:math for mathematical calculations and operations

Description

Non compliant code

import 'dart:math';

void main() {
var rng = new Random();
print(rng.nextInt(100)); // generates a random number between 0 and 99
}

In the code above, we're using Dart's built-in Random class to generate a random number. The nextInt function is used to generate a random integer from 0 (inclusive) to a specified upper limit (exclusive). In this case, the upper limit is 100, so the function will generate a random number between 0 and 99.

However, Dart's Random class and its nextInt function are known to be insecure for generating random numbers in cryptographic contexts. The random numbers generated by Random and nextInt are not truly random. They are determined by a pseudo-random number generator (PRNG), which uses an algorithm to produce a sequence of numbers that only approximate true randomness.

The problem with PRNGs is that if an attacker can predict the algorithm used by the PRNG, they can predict the sequence of numbers it will generate. In the context of a backend application, this could allow an attacker to guess sensitive information such as session IDs, tokens, or other secret keys that are generated using this insecure random number generator.

Therefore, it's important to use a secure method for generating random numbers in a cryptographic context. In Dart, you can use the Random.secure constructor to create a random number generator that produces cryptographically secure random numbers.

Steps

  • Replace the insecure random number generator with a secure one. Dart provides a secure random number generator in the 'dart:crypto' library.
  • Use the secure random number generator to generate random numbers. This generator uses a source of cryptographic randomness, which makes it much harder for an attacker to predict the sequence of numbers.
  • Ensure that the range of the random numbers is sufficient for your needs. A larger range makes it harder for an attacker to guess the number.
  • Consider adding additional entropy to the random number generation process. This could be done by incorporating user input or other unpredictable data into the generation process.

Compliant code

import 'dart:math';
import 'dart:typed_data';
import 'dart:convert';
import 'package:crypto/crypto.dart';

void main() {
var secureRandom = generateSecureRandom();
print(secureRandom); // generates a secure random number
}

int generateSecureRandom() {
var randomBytes = Random.secure().nextBytes(4);
var value = ByteData.view(randomBytes.buffer).getUint32(0);
return value;
}

The above code uses Dart's Random.secure() method to generate a secure random number. This method uses a source of cryptographic randomness, which makes it much harder for an attacker to predict the sequence of numbers.

The Random.secure().nextBytes(4) generates a list of 4 random bytes. The ByteData.view(randomBytes.buffer).getUint32(0) then converts these bytes into a 32-bit unsigned integer, which is our secure random number.

This secure random number generator is a significant improvement over the insecure Random() generator. It is much more resistant to attack, as it is much harder to predict the sequence of numbers it will generate.

Remember, the security of your random number generator is crucial in many contexts, such as generating random passwords, cryptographic keys, or in any other situation where predictability could be exploited by an attacker. Always use a secure random number generator like the one shown above in these situations.

References