mirror of
https://github.com/github/codeql.git
synced 2026-02-15 22:43:43 +01:00
227 lines
9.0 KiB
Java
227 lines
9.0 KiB
Java
package com.example.crypto.algorithms;
|
|
|
|
//import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
import java.security.*;
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.KeyGenerator;
|
|
import javax.crypto.SecretKey;
|
|
import javax.crypto.SecretKeyFactory;
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
import javax.crypto.spec.PBEKeySpec;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
import java.security.SecureRandom;
|
|
import java.util.Arrays;
|
|
import java.util.Base64;
|
|
|
|
/**
|
|
* AesWrapAndPBEWithTest demonstrates key wrapping and password-based encryption
|
|
* using various transformations.
|
|
*
|
|
* This file includes:
|
|
*
|
|
* 1. AESWrap Examples: - secureAESWrap(): Uses a randomly generated wrapping
|
|
* key. - insecureAESWrap(): Uses a fixed, hard-coded wrapping key.
|
|
*
|
|
* 2. PBEWith Examples: - insecurePBEExample(): Uses the legacy
|
|
* PBEWithMD5AndDES. - securePBEExample(): Uses PBKDF2WithHmacSHA256. -
|
|
* additionalPBEExample(): Uses PBEWithSHA256And128BitAES-CBC-BC. -
|
|
* additionalPBEExample2(): Uses PBEWithSHA1And128BitAES-CBC-BC.
|
|
*
|
|
* 3. Dynamic PBE Encryption: - dynamicPBEEncryption(): Chooses the PBE
|
|
* transformation based on a configuration string.
|
|
*
|
|
* Best Practices: - Use secure random keys and salts. - Avoid legacy algorithms
|
|
* like PBEWithMD5AndDES. - Prefer modern KDFs (PBKDF2WithHmacSHA256) and secure
|
|
* provider-specific PBE transformations.
|
|
*
|
|
* SAST/CBOM Notes: - Insecure examples (PBEWithMD5AndDES, fixed keys) should be
|
|
* flagged. - Secure examples use random salt, high iteration counts, and strong
|
|
* algorithms.
|
|
*/
|
|
public class AesWrapAndPBEWith {
|
|
|
|
// static {
|
|
// // Register BouncyCastle as a provider.
|
|
// Security.addProvider(new BouncyCastleProvider());
|
|
// }
|
|
// ===========================
|
|
// 1. AESWrap Examples
|
|
// ===========================
|
|
/**
|
|
* Secure AES key wrapping. Generates a random 256-bit wrapping key to wrap
|
|
* a target AES key.
|
|
*
|
|
* @return The wrapped key (Base64-encoded).
|
|
* @throws Exception if an error occurs.
|
|
*/
|
|
public String secureAESWrap() throws Exception {
|
|
KeyGenerator kg = KeyGenerator.getInstance("AES");
|
|
kg.init(256, new SecureRandom());
|
|
SecretKey wrappingKey = kg.generateKey();
|
|
|
|
kg.init(128, new SecureRandom());
|
|
SecretKey targetKey = kg.generateKey();
|
|
|
|
Cipher cipher = Cipher.getInstance("AESWrap");
|
|
cipher.init(Cipher.WRAP_MODE, wrappingKey);
|
|
byte[] wrappedKey = cipher.wrap(targetKey);
|
|
|
|
return Base64.getEncoder().encodeToString(wrappedKey);
|
|
}
|
|
|
|
/**
|
|
* Insecure AES key wrapping. Uses a fixed (hard-coded) wrapping key.
|
|
*
|
|
* @return The wrapped key (Base64-encoded).
|
|
* @throws Exception if an error occurs.
|
|
*/
|
|
public String insecureAESWrap() throws Exception {
|
|
byte[] fixedKeyBytes = new byte[32];
|
|
Arrays.fill(fixedKeyBytes, (byte) 0x01);
|
|
SecretKey wrappingKey = new SecretKeySpec(fixedKeyBytes, "AES");
|
|
|
|
KeyGenerator kg = KeyGenerator.getInstance("AES");
|
|
kg.init(128, new SecureRandom());
|
|
SecretKey targetKey = kg.generateKey();
|
|
|
|
Cipher cipher = Cipher.getInstance("AESWrap");
|
|
cipher.init(Cipher.WRAP_MODE, wrappingKey);
|
|
byte[] wrappedKey = cipher.wrap(targetKey);
|
|
|
|
return Base64.getEncoder().encodeToString(wrappedKey);
|
|
}
|
|
|
|
// ===========================
|
|
// 2. PBEWith Examples
|
|
// ===========================
|
|
/**
|
|
* Insecure PBE example using PBEWithMD5AndDES.
|
|
*
|
|
* @param password The input password.
|
|
* @return The derived key (Base64-encoded).
|
|
* @throws Exception if key derivation fails.
|
|
*/
|
|
public String insecurePBEExample(String password) throws Exception {
|
|
byte[] salt = new byte[8];
|
|
Arrays.fill(salt, (byte) 0x00); // Fixed salt (insecure)
|
|
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 64);
|
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
|
|
byte[] keyBytes = factory.generateSecret(spec).getEncoded();
|
|
return Base64.getEncoder().encodeToString(keyBytes);
|
|
}
|
|
|
|
/**
|
|
* Secure PBE example using PBKDF2WithHmacSHA256.
|
|
*
|
|
* @param password The input password.
|
|
* @return The derived 256-bit AES key (Base64-encoded).
|
|
* @throws Exception if key derivation fails.
|
|
*/
|
|
public String securePBEExample(String password) throws Exception {
|
|
byte[] salt = new byte[16];
|
|
new SecureRandom().nextBytes(salt);
|
|
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10000, 256);
|
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
|
byte[] keyBytes = factory.generateSecret(spec).getEncoded();
|
|
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
|
|
return Base64.getEncoder().encodeToString(aesKey.getEncoded());
|
|
}
|
|
|
|
/**
|
|
* Additional PBE example using PBEWithSHA256And128BitAES-CBC-BC.
|
|
*
|
|
* @param password The input password.
|
|
* @param plaintext The plaintext to encrypt.
|
|
* @return The IV concatenated with ciphertext (Base64-encoded).
|
|
* @throws Exception if key derivation or encryption fails.
|
|
*/
|
|
public String additionalPBEExample(String password, String plaintext) throws Exception {
|
|
byte[] salt = new byte[16];
|
|
new SecureRandom().nextBytes(salt);
|
|
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10000, 128);
|
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithSHA256And128BitAES-CBC-BC");
|
|
SecretKey pbeKey = factory.generateSecret(spec);
|
|
SecretKey aesKey = new SecretKeySpec(pbeKey.getEncoded(), "AES");
|
|
|
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
|
byte[] iv = new byte[16];
|
|
new SecureRandom().nextBytes(iv);
|
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
|
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
|
|
byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
|
|
byte[] output = concatenate(iv, ciphertext);
|
|
return Base64.getEncoder().encodeToString(output);
|
|
}
|
|
|
|
/**
|
|
* Additional PBE example using PBEWithSHA1And128BitAES-CBC-BC. This is less
|
|
* preferred than PBKDF2WithHmacSHA256 but demonstrates another variant.
|
|
*
|
|
* @param password The input password.
|
|
* @param plaintext The plaintext to encrypt.
|
|
* @return The IV concatenated with ciphertext (Base64-encoded).
|
|
* @throws Exception if key derivation or encryption fails.
|
|
*/
|
|
public String additionalPBEExample2(String password, String plaintext) throws Exception {
|
|
byte[] salt = new byte[16];
|
|
new SecureRandom().nextBytes(salt);
|
|
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10000, 128);
|
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithSHA1And128BitAES-CBC-BC");
|
|
SecretKey pbeKey = factory.generateSecret(spec);
|
|
SecretKey aesKey = new SecretKeySpec(pbeKey.getEncoded(), "AES");
|
|
|
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
|
byte[] iv = new byte[16];
|
|
new SecureRandom().nextBytes(iv);
|
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
|
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
|
|
byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
|
|
byte[] output = concatenate(iv, ciphertext);
|
|
return Base64.getEncoder().encodeToString(output);
|
|
}
|
|
|
|
// ===========================
|
|
// 3. Dynamic PBE Encryption
|
|
// ===========================
|
|
/**
|
|
* Dynamically selects a PBE transformation based on a configuration string.
|
|
*
|
|
* Acceptable values: - "PBKDF2": Uses PBKDF2WithHmacSHA256. - "SHA256AES":
|
|
* Uses PBEWithSHA256And128BitAES-CBC-BC. - "SHA1AES": Uses
|
|
* PBEWithSHA1And128BitAES-CBC-BC. - Otherwise, falls back to insecure
|
|
* PBEWithMD5AndDES.
|
|
*
|
|
* @param config The configuration string.
|
|
* @param password The input password.
|
|
* @param plaintext The plaintext to encrypt.
|
|
* @return The Base64-encoded encrypted output.
|
|
* @throws Exception if an error occurs.
|
|
*/
|
|
public String dynamicPBEEncryption(String config, String password, String plaintext) throws Exception {
|
|
if ("PBKDF2".equalsIgnoreCase(config)) {
|
|
return securePBEExample(password);
|
|
} else if ("SHA256AES".equalsIgnoreCase(config)) {
|
|
return additionalPBEExample(password, plaintext);
|
|
} else if ("SHA1AES".equalsIgnoreCase(config)) {
|
|
return additionalPBEExample2(password, plaintext);
|
|
} else {
|
|
// Fallback insecure option.
|
|
return insecurePBEExample(password);
|
|
}
|
|
}
|
|
|
|
// ===========================
|
|
// Helper Methods
|
|
// ===========================
|
|
/**
|
|
* Concatenates two byte arrays.
|
|
*/
|
|
private byte[] concatenate(byte[] a, byte[] b) {
|
|
byte[] result = new byte[a.length + b.length];
|
|
System.arraycopy(a, 0, result, 0, a.length);
|
|
System.arraycopy(b, 0, result, a.length, b.length);
|
|
return result;
|
|
}
|
|
|
|
}
|