mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Crypto: Add jca unit tests.
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
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.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user