Files
codeql/java/ql/test/experimental/library-tests/quantum/jca/PrngTest.java
2025-10-06 10:46:09 -04:00

157 lines
5.9 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();
}
}