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

347 lines
14 KiB
Java

package com.example.crypto.algorithms;
// import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;
import java.util.Properties;
/**
* Demonstrates various digital signature operations:
*
* 1) RSA-PSS (modern, safer) - CBOM/SAST: Classified as a Modern Digital
* Signature scheme using RSA-PSS. RSA-PSS with SHA-256 is recommended.
*
* 2) ECDSA with secp256r1 - CBOM/SAST: Classified as an Elliptic Curve Digital
* Signature Algorithm. Secure when used with a strong curve and proper
* randomness.
*
* 3) Ed25519 (RFC 8032) - CBOM/SAST: Classified as a modern, high-performance
* signature scheme.
*
* 4) SHA1withRSA (deprecated/unsafe example) - CBOM/SAST: Classified as a
* legacy digital signature scheme. SHA-1 and 1024-bit RSA are deprecated.
*
* Additional nuanced examples:
*
* - Signing and verifying an empty message. - Signing data with non-ASCII
* characters. - Demonstrating signature tampering and its detection. - A
* dynamic (runtime-selected) signature algorithm scenario ("known unknown").
*
* Requirements: - BouncyCastle for ECDSA, Ed25519, and RSA-PSS (if needed). -
* Java 11+ for native Ed25519 support or using BC for older versions.
*/
public class SignatureOperation {
// static {
// // Register the BouncyCastle provider.
// Security.addProvider(new BouncyCastleProvider());
// }
///////////////////////////////////////
// 1. RSA-PSS (Recommended)
///////////////////////////////////////
/**
* Generate an RSA key pair for RSA-PSS.
* Uses a 2048-bit key.
*
* CBOM/SAST Notes:
* - Parent: Modern Digital Signature (RSA-PSS).
*/
public KeyPair generateRSAPSSKeyPair() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
return kpg.generateKeyPair();
}
/**
* Sign data using RSA-PSS with SHA-256.
*
* CBOM/SAST Notes: - Parent: Modern Digital Signature (RSA-PSS).
*/
public byte[] signRSAPSS(PrivateKey privateKey, byte[] data) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSAandMGF1");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
/**
* Verify data using RSA-PSS with SHA-256.
*
* CBOM/SAST Notes: - Parent: Modern Digital Signature (RSA-PSS).
*/
public boolean verifyRSAPSS(PublicKey publicKey, byte[] data, byte[] sigBytes) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSAandMGF1");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(sigBytes);
}
///////////////////////////////////////
// 2. ECDSA (secp256r1)
///////////////////////////////////////
/**
* Generate an ECDSA key pair on secp256r1.
*
* CBOM/SAST Notes:
* - Parent: Elliptic Curve Digital Signature.
*/
public KeyPair generateECDSAKeyPair() throws Exception {
KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
return ecKpg.generateKeyPair();
}
/**
* Sign data using ECDSA with SHA-256.
*
* CBOM/SAST Notes: - Parent: Elliptic Curve Digital Signature.
*/
public byte[] signECDSA(PrivateKey privateKey, byte[] data) throws Exception {
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
/**
* Verify data using ECDSA with SHA-256.
*
* CBOM/SAST Notes: - Parent: Elliptic Curve Digital Signature.
*/
public boolean verifyECDSA(PublicKey publicKey, byte[] data, byte[] sigBytes) throws Exception {
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(sigBytes);
}
///////////////////////////////////////
// 3. Ed25519 (RFC 8032)
///////////////////////////////////////
/**
* Generate an Ed25519 key pair.
*
* CBOM/SAST Notes:
* - Parent: Modern Digital Signature (EdDSA).
*/
public KeyPair generateEd25519KeyPair() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519", "BC");
return kpg.generateKeyPair();
}
/**
* Sign data using Ed25519.
*
* CBOM/SAST Notes: - Parent: Modern Digital Signature (EdDSA).
*/
public byte[] signEd25519(PrivateKey privateKey, byte[] data) throws Exception {
Signature signature = Signature.getInstance("Ed25519", "BC");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
/**
* Verify data using Ed25519.
*
* CBOM/SAST Notes: - Parent: Modern Digital Signature (EdDSA).
*/
public boolean verifyEd25519(PublicKey publicKey, byte[] data, byte[] sigBytes) throws Exception {
Signature signature = Signature.getInstance("Ed25519", "BC");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(sigBytes);
}
///////////////////////////////////////
// 4. SHA1withRSA (Deprecated/Unsafe)
///////////////////////////////////////
/**
* Generate an RSA key pair for the deprecated/unsafe example.
* Uses a 1024-bit key.
*
* CBOM/SAST Notes:
* - Parent: Legacy Digital Signature.
* - RSA with SHA-1 and 1024-bit keys is deprecated and should be avoided.
*/
public KeyPair generateRSAUnsafeKeyPair() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
return kpg.generateKeyPair();
}
/**
* Sign data using SHA1withRSA.
*
* CBOM/SAST Notes: - Parent: Legacy Digital Signature. - SHA-1 is
* deprecated and RSA with 1024 bits is considered weak.
*/
public byte[] signSHA1withRSA(PrivateKey privateKey, byte[] data) throws Exception {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
/**
* Verify data using SHA1withRSA.
*
* CBOM/SAST Notes: - Parent: Legacy Digital Signature. - Verification of
* SHA1withRSA is insecure.
*/
public boolean verifySHA1withRSA(PublicKey publicKey, byte[] data, byte[] sigBytes) throws Exception {
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(sigBytes);
}
///////////////////////////////////////
// Nuanced Edge-Case Examples
///////////////////////////////////////
/**
* Demonstrates signing and verifying an empty message.
*
* CBOM/SAST Notes:
* - Edge Case: Signing empty input should be handled correctly but might be
* unexpected.
*/
public void signAndVerifyEmptyMessage() throws Exception {
byte[] emptyMessage = new byte[0];
KeyPair kp = generateRSAPSSKeyPair();
byte[] sig = signRSAPSS(kp.getPrivate(), emptyMessage);
boolean verified = verifyRSAPSS(kp.getPublic(), emptyMessage, sig);
System.out.println("Empty message signature verified? " + verified);
}
/**
* Demonstrates that even a slight tampering with the signature will cause
* verification to fail.
*
* CBOM/SAST Notes: - Edge Case: Signature integrity is critical. Any
* change-even a single byte-should invalidate the signature.
*/
public void tamperSignatureEdgeCase() throws Exception {
byte[] message = "Important Message".getBytes();
KeyPair kp = generateECDSAKeyPair();
byte[] originalSig = signECDSA(kp.getPrivate(), message);
// Tamper with the signature by flipping one bit.
byte[] tamperedSig = originalSig.clone();
tamperedSig[0] ^= 0x01;
boolean verifiedOriginal = verifyECDSA(kp.getPublic(), message, originalSig);
boolean verifiedTampered = verifyECDSA(kp.getPublic(), message, tamperedSig);
System.out.println("Original ECDSA signature verified? " + verifiedOriginal);
System.out.println("Tampered ECDSA signature verified? " + verifiedTampered);
}
/**
* Demonstrates dynamic signature algorithm selection. This is a "known
* unknown" scenario where the algorithm is chosen at runtime based on
* configuration. If the configuration is compromised or misconfigured, an
* insecure algorithm might be selected.
*
* CBOM/SAST Notes: - Known Unknown: Dynamic configuration introduces
* ambiguity and risk. - Ensure that fallback defaults are secure.
*/
public void dynamicSignatureSelectionDemo() throws Exception {
// Simulate loading a configuration.
Properties config = new Properties();
// For demonstration, let's assume the config might specify an algorithm.
// Possible values: "SHA256withRSAandMGF1", "SHA256withECDSA", "Ed25519",
// "SHA1withRSA"
// Here we simulate an unknown or insecure algorithm being selected.
config.setProperty("signature.algorithm", "SHA1withRSA"); // Insecure choice!
String algorithm = config.getProperty("signature.algorithm", "SHA256withRSAandMGF1");
KeyPair kp;
Signature signature;
if ("SHA256withRSAandMGF1".equalsIgnoreCase(algorithm)) {
kp = generateRSAPSSKeyPair();
signature = Signature.getInstance("SHA256withRSAandMGF1");
} else if ("SHA256withECDSA".equalsIgnoreCase(algorithm)) {
kp = generateECDSAKeyPair();
signature = Signature.getInstance("SHA256withECDSA", "BC");
} else if ("Ed25519".equalsIgnoreCase(algorithm)) {
kp = generateEd25519KeyPair();
signature = Signature.getInstance("Ed25519", "BC");
} else if ("SHA1withRSA".equalsIgnoreCase(algorithm)) {
kp = generateRSAUnsafeKeyPair();
signature = Signature.getInstance("SHA1withRSA");
} else {
// Fallback to a secure default.
kp = generateRSAPSSKeyPair();
signature = Signature.getInstance("SHA256withRSAandMGF1");
}
byte[] message = "Dynamic Signature Demo".getBytes();
signature.initSign(kp.getPrivate());
signature.update(message);
byte[] sigBytes = signature.sign();
// Verify using the same algorithm.
signature.initVerify(kp.getPublic());
signature.update(message);
boolean verified = signature.verify(sigBytes);
System.out.println("Dynamic algorithm (" + algorithm + ") signature verified? " + verified);
}
///////////////////////////////////////
// Demo Method: runSignatureDemos
///////////////////////////////////////
/**
* Demonstrates digital signature operations for various algorithms.
* It generates key pairs, signs a message, and verifies the signature for:
* - RSA-PSS
* - ECDSA (secp256r1)
* - Ed25519
* - SHA1withRSA (deprecated/unsafe)
* Additionally, it runs several edge-case demos.
*
* CBOM/SAST Classification:
* - Shows both modern, secure signature schemes and a deprecated example.
* - Also demonstrates handling of edge cases and dynamic selection risks.
*/
public void runSignatureDemos() throws Exception {
byte[] message = "Hello Signature World!".getBytes();
// ============ RSA-PSS ============
KeyPair rsaPssKP = generateRSAPSSKeyPair();
byte[] rsaPssSig = signRSAPSS(rsaPssKP.getPrivate(), message);
System.out.println("RSA-PSS Signature: " + Base64.getEncoder().encodeToString(rsaPssSig));
boolean rsaPssVerified = verifyRSAPSS(rsaPssKP.getPublic(), message, rsaPssSig);
System.out.println("RSA-PSS Verified? " + rsaPssVerified);
// ============ ECDSA (secp256r1) ============
KeyPair ecdsaKP = generateECDSAKeyPair();
byte[] ecdsaSig = signECDSA(ecdsaKP.getPrivate(), message);
System.out.println("ECDSA Signature: " + Base64.getEncoder().encodeToString(ecdsaSig));
boolean ecdsaVerified = verifyECDSA(ecdsaKP.getPublic(), message, ecdsaSig);
System.out.println("ECDSA Verified? " + ecdsaVerified);
// ============ Ed25519 ============
KeyPair ed25519KP = generateEd25519KeyPair();
byte[] ed25519Sig = signEd25519(ed25519KP.getPrivate(), message);
System.out.println("Ed25519 Signature: " + Base64.getEncoder().encodeToString(ed25519Sig));
boolean ed25519Verified = verifyEd25519(ed25519KP.getPublic(), message, ed25519Sig);
System.out.println("Ed25519 Verified? " + ed25519Verified);
// ============ SHA1withRSA (Deprecated/Unsafe) ============
KeyPair rsaUnsafeKP = generateRSAUnsafeKeyPair();
byte[] rsaUnsafeSig = signSHA1withRSA(rsaUnsafeKP.getPrivate(), message);
System.out.println("SHA1withRSA Signature (Insecure): " + Base64.getEncoder().encodeToString(rsaUnsafeSig));
boolean rsaUnsafeVerified = verifySHA1withRSA(rsaUnsafeKP.getPublic(), message, rsaUnsafeSig);
System.out.println("SHA1withRSA Verified? " + rsaUnsafeVerified);
// ============ Edge Cases ============
signAndVerifyEmptyMessage();
tamperSignatureEdgeCase();
dynamicSignatureSelectionDemo();
}
}