mirror of
https://github.com/github/codeql.git
synced 2026-02-15 22:43:43 +01:00
132 lines
5.3 KiB
Java
132 lines
5.3 KiB
Java
package com.example.crypto.algorithms;
|
|
|
|
//import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
import java.security.SecureRandom;
|
|
import java.util.Base64;
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.KeyGenerator;
|
|
import javax.crypto.SecretKey;
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
|
|
/**
|
|
* SymmetricModesTest demonstrates the use of advanced cipher modes for
|
|
* symmetric encryption:
|
|
*
|
|
* 1. AES/KWP/NoPadding: Uses AES Key Wrap with Padding (KWP) to securely wrap
|
|
* (encrypt) a key. - Secure usage: Uses a randomly generated wrapping key.
|
|
*
|
|
* 2. AES/OFB8/NoPadding: Uses AES in Output Feedback mode with an 8-bit
|
|
* feedback size. - Secure usage: Uses a random IV for each encryption. -
|
|
* Insecure usage: Using a fixed IV (or nonce) in OFB mode compromises
|
|
* confidentiality.
|
|
*
|
|
* In production, algorithm parameters (such as mode, padding, and IV
|
|
* generation) should be externalized via configuration files to support crypto
|
|
* agility.
|
|
*/
|
|
public class SymmetricModesTest {
|
|
|
|
// static {
|
|
// // Register BouncyCastle provider for additional cipher modes.
|
|
// Security.addProvider(new BouncyCastleProvider());
|
|
// }
|
|
// ---------------------------
|
|
// AES/KWP/NoPadding Example
|
|
// ---------------------------
|
|
/**
|
|
* Securely wraps a target AES key using AES/KWP/NoPadding.
|
|
*
|
|
* Best Practice: - The wrapping key must be generated randomly. - AES/KWP
|
|
* provides key wrapping with padding, suitable for keys whose lengths are
|
|
* not multiples of the block size.
|
|
*
|
|
* @return The Base64-encoded wrapped key.
|
|
* @throws Exception if an error occurs during key wrapping.
|
|
*/
|
|
public String secureAESKWPWrap() throws Exception {
|
|
// Generate a random wrapping key (256-bit) for key wrapping.
|
|
KeyGenerator kg = KeyGenerator.getInstance("AES");
|
|
kg.init(256, new SecureRandom());
|
|
SecretKey wrappingKey = kg.generateKey();
|
|
|
|
// Generate a target AES key to be wrapped (128-bit).
|
|
kg.init(128, new SecureRandom());
|
|
SecretKey targetKey = kg.generateKey();
|
|
|
|
// Use AES/KWP (Key Wrap with Padding) to wrap the target key.
|
|
Cipher cipher = Cipher.getInstance("AES/KWP/NoPadding", "BC");
|
|
cipher.init(Cipher.WRAP_MODE, wrappingKey);
|
|
byte[] wrappedKey = cipher.wrap(targetKey);
|
|
|
|
return Base64.getEncoder().encodeToString(wrappedKey);
|
|
}
|
|
|
|
// ---------------------------
|
|
// AES/OFB8/NoPadding Examples
|
|
// ---------------------------
|
|
/**
|
|
* Securely encrypts plaintext using AES in OFB mode with an 8-bit feedback
|
|
* size (AES/OFB8/NoPadding).
|
|
*
|
|
* Best Practice: - Use a fresh, random IV for each encryption operation.
|
|
*
|
|
* @param key The AES key.
|
|
* @param plaintext The plaintext to encrypt.
|
|
* @return The ciphertext (Base64-encoded) with the IV prepended.
|
|
* @throws Exception if encryption fails.
|
|
*/
|
|
public String secureAesOfb8Encryption(SecretKey key, byte[] plaintext) throws Exception {
|
|
Cipher cipher = Cipher.getInstance("AES/OFB8/NoPadding", "BC");
|
|
byte[] iv = new byte[16]; // IV size for AES block cipher (128-bit) even if feedback is 8-bit.
|
|
new SecureRandom().nextBytes(iv);
|
|
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
|
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
|
byte[] ciphertext = cipher.doFinal(plaintext);
|
|
// Prepend IV to ciphertext (as is common practice)
|
|
byte[] output = new byte[iv.length + ciphertext.length];
|
|
System.arraycopy(iv, 0, output, 0, iv.length);
|
|
System.arraycopy(ciphertext, 0, output, iv.length, ciphertext.length);
|
|
return Base64.getEncoder().encodeToString(output);
|
|
}
|
|
|
|
/**
|
|
* Insecurely encrypts plaintext using AES in OFB mode with an 8-bit
|
|
* feedback size (AES/OFB8/NoPadding) by using a fixed IV.
|
|
*
|
|
* Best Practice Violation: - Using a fixed IV (or nonce) with any
|
|
* encryption mode (including OFB) compromises the cipher's security.
|
|
*
|
|
* @param key The AES key.
|
|
* @param plaintext The plaintext to encrypt.
|
|
* @return The ciphertext (Base64-encoded) with the fixed IV prepended.
|
|
* @throws Exception if encryption fails.
|
|
*/
|
|
public String insecureAesOfb8Encryption(SecretKey key, byte[] plaintext) throws Exception {
|
|
Cipher cipher = Cipher.getInstance("AES/OFB8/NoPadding", "BC");
|
|
// Fixed IV: Insecure because it causes nonce/IV reuse.
|
|
byte[] fixedIV = new byte[16]; // All zeros.
|
|
IvParameterSpec ivSpec = new IvParameterSpec(fixedIV);
|
|
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
|
|
byte[] ciphertext = cipher.doFinal(plaintext);
|
|
byte[] output = new byte[fixedIV.length + ciphertext.length];
|
|
System.arraycopy(fixedIV, 0, output, 0, fixedIV.length);
|
|
System.arraycopy(ciphertext, 0, output, fixedIV.length, ciphertext.length);
|
|
return Base64.getEncoder().encodeToString(output);
|
|
}
|
|
|
|
// ---------------------------
|
|
// Helper Methods
|
|
// ---------------------------
|
|
/**
|
|
* Generates a secure 256-bit AES key.
|
|
*
|
|
* @return A new AES SecretKey.
|
|
* @throws Exception if key generation fails.
|
|
*/
|
|
public SecretKey generateAESKey() throws Exception {
|
|
KeyGenerator kg = KeyGenerator.getInstance("AES");
|
|
kg.init(256, new SecureRandom());
|
|
return kg.generateKey();
|
|
}
|
|
}
|