Files
codeql/java/ql/test/experimental/library-tests/quantum/jca/PrngTest.java
2025-10-03 13:32:02 -04:00

167 lines
6.0 KiB
Java

package com.example.crypto.algorithms;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import javax.crypto.SecretKey;
import javax.crypto.KeyGenerator;
/**
* PrngTest demonstrates various approaches for generating random data using
* PRNG/RNG APIs.
*
* It covers:
* 1) Secure random generation using SecureRandom (default and
* getInstanceStrong).
* 2) Insecure random generation using java.util.Random.
* 3) Flawed PRNG usage by setting a fixed seed.
* 4) Dynamic PRNG selection based on configuration.
* 5) Usage of random data as nonces/IVs in symmetric encryption.
*
* SAST/CBOM Notes:
* - SecureRandom (and SecureRandom.getInstanceStrong) are recommended.
* - java.util.Random is not suitable for cryptographic purposes.
* - Re-seeding or using a fixed seed with SecureRandom makes it predictable.
* - IVs and nonces must be unique for each operation; reusing fixed values is
* insecure.
*/
public class PrngTest {
// ---------- Secure Random Generation ----------
/**
* Generates random bytes using the default SecureRandom.
* SAST: SecureRandom is recommended for cryptographically secure random data.
*
* @param numBytes Number of bytes to generate.
* @return A byte array of random data.
*/
public byte[] generateSecureRandomBytes(int numBytes) {
SecureRandom secureRandom = new SecureRandom();
byte[] bytes = new byte[numBytes];
secureRandom.nextBytes(bytes);
return bytes;
}
/**
* Generates random bytes using SecureRandom.getInstanceStrong().
* SAST: getInstanceStrong() returns a strong RNG (may block in some
* environments).
*
* @param numBytes Number of bytes to generate.
* @return A byte array of random data.
* @throws NoSuchAlgorithmException if a strong RNG is not available.
*/
public byte[] generateSecureRandomBytesStrong(int numBytes) throws NoSuchAlgorithmException {
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
byte[] bytes = new byte[numBytes];
secureRandom.nextBytes(bytes);
return bytes;
}
// ---------- Insecure Random Generation ----------
/**
* Generates random bytes using java.util.Random.
* SAST: java.util.Random is predictable and insecure for cryptographic
* purposes.
*
* @param numBytes Number of bytes to generate.
* @return A byte array of random data.
*/
public byte[] generateInsecureRandomBytes(int numBytes) {
Random random = new Random();
byte[] bytes = new byte[numBytes];
random.nextBytes(bytes);
return bytes;
}
/**
* Generates random bytes using SecureRandom with a fixed seed.
* SAST: Fixed seeding makes SecureRandom predictable and insecure.
*
* @param numBytes Number of bytes to generate.
* @return A byte array of predictable random data.
*/
public byte[] generatePredictableRandomBytes(int numBytes) {
SecureRandom secureRandom = new SecureRandom();
// Fixed seed (predictable and insecure)
secureRandom.setSeed(0xDEADBEEF);
byte[] bytes = new byte[numBytes];
secureRandom.nextBytes(bytes);
return bytes;
}
// ---------- Dynamic PRNG Selection ----------
/**
* Dynamically selects a PRNG algorithm based on a configuration property.
* If the algorithm is unknown, falls back to java.util.Random (insecure).
* SAST: Dynamic selection may introduce risk if an insecure RNG is chosen.
*
* @param algorithmName The PRNG algorithm name (e.g. "SHA1PRNG",
* "NativePRNGNonBlocking", "getInstanceStrong").
* @param numBytes Number of bytes to generate.
* @return A byte array of random data.
* @throws NoSuchAlgorithmException if the algorithm is not available.
*/
public byte[] dynamicRandomGeneration(String algorithmName, int numBytes) throws NoSuchAlgorithmException {
SecureRandom secureRandom;
if ("SHA1PRNG".equalsIgnoreCase(algorithmName)) {
// SHA1PRNG is older and less preferred.
secureRandom = SecureRandom.getInstance("SHA1PRNG");
} else if ("NativePRNGNonBlocking".equalsIgnoreCase(algorithmName)) {
secureRandom = SecureRandom.getInstance("NativePRNGNonBlocking");
} else if ("getInstanceStrong".equalsIgnoreCase(algorithmName)) {
secureRandom = SecureRandom.getInstanceStrong();
} else {
// Fallback to insecure java.util.Random.
Random random = new Random();
byte[] bytes = new byte[numBytes];
random.nextBytes(bytes);
return bytes;
}
byte[] bytes = new byte[numBytes];
secureRandom.nextBytes(bytes);
return bytes;
}
// ---------- Usage Examples: Nonce/IV Generation for Symmetric Encryption
// ----------
/**
* Demonstrates secure generation of an IV for AES-GCM encryption.
* SAST: A unique, random IV is required for each encryption operation.
*
* @return A 12-byte IV.
*/
public byte[] generateRandomIVForGCM() {
return generateSecureRandomBytes(12);
}
/**
* Demonstrates insecure use of a fixed IV for AES-GCM encryption.
* SAST: Reusing a fixed IV in AES-GCM compromises security.
*
* @return A fixed 12-byte IV (all zeros).
*/
public byte[] generateFixedIVForGCM() {
return new byte[12]; // 12 bytes of zeros.
}
// ---------- Example: Using PRNG for Key Generation ----------
/**
* Generates a secure 256-bit AES key using SecureRandom.
* SAST: Strong key generation is critical for symmetric cryptography.
*
* @return A new AES SecretKey.
* @throws Exception if key generation fails.
*/
public SecretKey generateAESKey() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256, new SecureRandom());
return keyGen.generateKey();
}
}