mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
147 lines
6.6 KiB
Java
147 lines
6.6 KiB
Java
package com.example.crypto.algorithms;
|
|
|
|
// import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
import java.security.*;
|
|
import java.util.Arrays;
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.KeyGenerator;
|
|
import javax.crypto.SecretKey;
|
|
import javax.crypto.spec.GCMParameterSpec;
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
|
|
public class ChainedEncryptionTest {
|
|
|
|
// static {
|
|
// Security.addProvider(new BouncyCastleProvider());
|
|
// }
|
|
// Encrypts using AES-GCM. Returns IV concatenated with ciphertext.
|
|
public static byte[] encryptAESGCM(SecretKey key, byte[] plaintext) throws Exception {
|
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
byte[] iv = new byte[12]; // 12-byte nonce for AES-GCM
|
|
new SecureRandom().nextBytes(iv);
|
|
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
|
|
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
|
|
byte[] ciphertext = cipher.doFinal(plaintext);
|
|
return concat(iv, ciphertext);
|
|
}
|
|
|
|
// Decrypts AES-GCM ciphertext where IV is prepended.
|
|
public static byte[] decryptAESGCM(SecretKey key, byte[] ivCiphertext) throws Exception {
|
|
byte[] iv = Arrays.copyOfRange(ivCiphertext, 0, 12);
|
|
byte[] ciphertext = Arrays.copyOfRange(ivCiphertext, 12, ivCiphertext.length);
|
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
|
|
cipher.init(Cipher.DECRYPT_MODE, key, spec);
|
|
return cipher.doFinal(ciphertext);
|
|
}
|
|
|
|
// Encrypts using ChaCha20-Poly1305. Returns nonce concatenated with ciphertext.
|
|
public static byte[] encryptChaCha20Poly1305(SecretKey key, byte[] plaintext) throws Exception {
|
|
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305", "BC");
|
|
byte[] nonce = new byte[12]; // 12-byte nonce for ChaCha20-Poly1305
|
|
new SecureRandom().nextBytes(nonce);
|
|
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(nonce));
|
|
byte[] ciphertext = cipher.doFinal(plaintext);
|
|
return concat(nonce, ciphertext);
|
|
}
|
|
|
|
// Decrypts ChaCha20-Poly1305 ciphertext where nonce is prepended.
|
|
public static byte[] decryptChaCha20Poly1305(SecretKey key, byte[] nonceCiphertext) throws Exception {
|
|
byte[] nonce = Arrays.copyOfRange(nonceCiphertext, 0, 12);
|
|
byte[] ciphertext = Arrays.copyOfRange(nonceCiphertext, 12, nonceCiphertext.length);
|
|
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305", "BC");
|
|
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(nonce));
|
|
return cipher.doFinal(ciphertext);
|
|
}
|
|
|
|
// Helper method to concatenate two byte arrays.
|
|
private static byte[] concat(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;
|
|
}
|
|
|
|
/**
|
|
* Performs chained encryption and decryption in one function. First,
|
|
* plaintext is encrypted with AES-GCM (inner layer), then that ciphertext
|
|
* is encrypted with ChaCha20-Poly1305 (outer layer). The decryption process
|
|
* reverses these steps.
|
|
*
|
|
* @param plaintext The input plaintext.
|
|
* @return The decrypted plaintext as a String.
|
|
* @throws Exception if any cryptographic operation fails.
|
|
*/
|
|
public static String chainEncryptDecrypt(String plaintext) throws Exception {
|
|
byte[] plainBytes = plaintext.getBytes("UTF-8");
|
|
|
|
// Generate keys for inner and outer encryption.
|
|
KeyGenerator aesGen = KeyGenerator.getInstance("AES");
|
|
aesGen.init(256, new SecureRandom());
|
|
SecretKey innerKey = aesGen.generateKey();
|
|
|
|
KeyGenerator chachaGen = KeyGenerator.getInstance("ChaCha20", "BC");
|
|
chachaGen.init(256, new SecureRandom());
|
|
SecretKey outerKey = chachaGen.generateKey();
|
|
|
|
// Inner Encryption with AES-GCM.
|
|
byte[] aesIV = new byte[12]; // Random 12-byte IV.
|
|
new SecureRandom().nextBytes(aesIV);
|
|
Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, aesIV);
|
|
aesCipher.init(Cipher.ENCRYPT_MODE, innerKey, gcmSpec);
|
|
byte[] innerCiphertext = aesCipher.doFinal(plainBytes);
|
|
|
|
// Outer Encryption with ChaCha20-Poly1305.
|
|
byte[] chachaNonce = new byte[12]; // Random 12-byte nonce.
|
|
new SecureRandom().nextBytes(chachaNonce);
|
|
Cipher chachaCipher = Cipher.getInstance("ChaCha20-Poly1305", "BC");
|
|
chachaCipher.init(Cipher.ENCRYPT_MODE, outerKey, new IvParameterSpec(chachaNonce));
|
|
byte[] outerCiphertext = chachaCipher.doFinal(innerCiphertext);
|
|
|
|
// Outer Decryption.
|
|
Cipher chachaDec = Cipher.getInstance("ChaCha20-Poly1305", "BC");
|
|
chachaDec.init(Cipher.DECRYPT_MODE, outerKey, new IvParameterSpec(chachaNonce));
|
|
byte[] decryptedInnerCiphertext = chachaDec.doFinal(outerCiphertext);
|
|
|
|
// Inner Decryption.
|
|
Cipher aesDec = Cipher.getInstance("AES/GCM/NoPadding");
|
|
aesDec.init(Cipher.DECRYPT_MODE, innerKey, new GCMParameterSpec(128, aesIV));
|
|
byte[] decryptedPlaintext = aesDec.doFinal(decryptedInnerCiphertext);
|
|
|
|
return new String(decryptedPlaintext, "UTF-8");
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
// Generate a 256-bit AES key for the first (inner) encryption.
|
|
KeyGenerator aesGen = KeyGenerator.getInstance("AES");
|
|
aesGen.init(256, new SecureRandom());
|
|
SecretKey aesKey = aesGen.generateKey();
|
|
|
|
// Generate a 256-bit key for ChaCha20-Poly1305 (outer encryption).
|
|
KeyGenerator chaChaGen = KeyGenerator.getInstance("ChaCha20");
|
|
chaChaGen.init(256, new SecureRandom());
|
|
SecretKey chaChaKey = chaChaGen.generateKey();
|
|
|
|
String originalText = "This is a secret message.";
|
|
byte[] plaintext = originalText.getBytes();
|
|
|
|
// Step 1: Encrypt plaintext with AES-GCM.
|
|
byte[] innerCiphertext = encryptAESGCM(aesKey, plaintext);
|
|
|
|
// Step 2: Encrypt the AES-GCM ciphertext with ChaCha20-Poly1305.
|
|
byte[] outerCiphertext = encryptChaCha20Poly1305(chaChaKey, innerCiphertext);
|
|
|
|
// Now, decrypt in reverse order.
|
|
// Step 3: Decrypt the outer layer (ChaCha20-Poly1305).
|
|
byte[] decryptedInnerCiphertext = decryptChaCha20Poly1305(chaChaKey, outerCiphertext);
|
|
|
|
// Step 4: Decrypt the inner layer (AES-GCM).
|
|
byte[] decryptedPlaintext = decryptAESGCM(aesKey, decryptedInnerCiphertext);
|
|
|
|
System.out.println("Original: " + originalText);
|
|
System.out.println("Decrypted: " + new String(decryptedPlaintext));
|
|
}
|
|
|
|
}
|