Skip to content

Commit 700f34e

Browse files
committed
Crypto: Bad Mac use tests, and fix for BadMacOrderMacOnEncryptPlaintext (barriers were blocking flow through an encrypt to a subsequent mac on the same plaintext)
1 parent b9b0037 commit 700f34e

File tree

6 files changed

+95
-8
lines changed

6 files changed

+95
-8
lines changed

java/ql/src/experimental/quantum/Examples/BadMacOrderMacOnEncryptPlaintext.ql

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@ module CommonDataFlowNodeConfig implements DataFlow::ConfigSig {
2828
sink = any(Crypto::FlowAwareElement other).getInputNode()
2929
}
3030

31-
predicate isBarrierOut(DataFlow::Node node) {
32-
node = any(Crypto::FlowAwareElement element).getInputNode()
33-
}
34-
35-
predicate isBarrierIn(DataFlow::Node node) {
36-
node = any(Crypto::FlowAwareElement element).getOutputNode()
37-
}
38-
3931
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
4032
node1.(AdditionalFlowInputStep).getOutput() = node2
4133
or

java/ql/test/experimental/query-tests/quantum/examples/BadMacUse/BadMacOrderDecryptToMac.expected

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
query: experimental/quantum/Examples/BadMacOrderDecryptToMac.ql
2+
postprocess:
3+
- utils/test/PrettyPrintModels.ql
4+
- utils/test/InlineExpectationsTestQuery.ql

java/ql/test/experimental/query-tests/quantum/examples/BadMacUse/BadMacOrderMacOnEncryptPlaintext.expected

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
query: experimental/quantum/Examples/BadMacOrderMacOnEncryptPlaintext.ql
2+
postprocess:
3+
- utils/test/PrettyPrintModels.ql
4+
- utils/test/InlineExpectationsTestQuery.ql
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import java.security.*;
2+
import java.util.Arrays;
3+
import java.util.Base64;
4+
import javax.crypto.Cipher;
5+
import javax.crypto.KeyGenerator;
6+
import javax.crypto.Mac;
7+
import javax.crypto.SecretKey;
8+
import javax.crypto.SecretKeyFactory;
9+
import javax.crypto.spec.PBEKeySpec;
10+
import javax.crypto.spec.SecretKeySpec;
11+
12+
13+
class BadMacUse {
14+
15+
private byte[] generateSalt(int length) {
16+
byte[] salt = new byte[length];
17+
new SecureRandom().nextBytes(salt);
18+
return salt;
19+
}
20+
21+
public void CipherThenMac(byte[] encryptionKeyBytes, byte[] macKeyBytes) throws Exception {
22+
// Create keys directly from provided byte arrays
23+
SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES");
24+
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");
25+
26+
// Encrypt some sample data using the encryption key
27+
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
28+
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, new SecureRandom());
29+
byte[] plaintext = "Further Use Test Data".getBytes();
30+
byte[] ciphertext = cipher.doFinal(plaintext);
31+
32+
// Compute HMAC over the ciphertext using the MAC key
33+
Mac mac = Mac.getInstance("HmacSHA256");
34+
mac.init(macKey);
35+
byte[] computedMac = mac.doFinal(ciphertext);
36+
37+
// Concatenate ciphertext and MAC
38+
byte[] output = new byte[ciphertext.length + computedMac.length];
39+
System.arraycopy(ciphertext, 0, output, 0, ciphertext.length);
40+
System.arraycopy(computedMac, 0, output, ciphertext.length, computedMac.length);
41+
}
42+
43+
44+
public void BadDecryptThenMacOnPlaintextVerify(byte[] encryptionKeyBytes, byte[] macKeyBytes, byte[] input) throws Exception {
45+
// Split input into ciphertext and MAC
46+
int macLength = 32; // HMAC-SHA256 output length
47+
byte[] ciphertext = Arrays.copyOfRange(input, 0, input.length - macLength);
48+
byte[] receivedMac = Arrays.copyOfRange(input, input.length - macLength, input.length);
49+
50+
// Decrypt first (unsafe)
51+
SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES");
52+
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
53+
cipher.init(Cipher.DECRYPT_MODE, encryptionKey, new SecureRandom());
54+
byte[] plaintext = cipher.doFinal(ciphertext); // $Source
55+
56+
// Now verify MAC (too late)
57+
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");
58+
Mac mac = Mac.getInstance("HmacSHA256");
59+
mac.init(macKey);
60+
byte[] computedMac = mac.doFinal(plaintext); // $Alert[java/quantum/bad-mac-order-decrypt-to-mac]
61+
62+
if (!MessageDigest.isEqual(receivedMac, computedMac)) {
63+
throw new SecurityException("MAC verification failed");
64+
}
65+
}
66+
67+
public void BadMacOnPlaintext(byte[] encryptionKeyBytes, byte[] macKeyBytes, byte[] plaintext) throws Exception {// $Alert[java/quantum/bad-mac-order-encrypt-plaintext-also-in-mac]
68+
// Create keys directly from provided byte arrays
69+
SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES");
70+
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");
71+
72+
// BAD Compute MAC over plaintext (not ciphertext)
73+
Mac mac = Mac.getInstance("HmacSHA256");
74+
mac.init(macKey);
75+
byte[] computedMac = mac.doFinal(plaintext); // Integrity not tied to encrypted data
76+
77+
// Encrypt the plaintext
78+
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
79+
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, new SecureRandom());
80+
byte[] ciphertext = cipher.doFinal(plaintext);
81+
82+
// Concatenate ciphertext and MAC
83+
byte[] output = new byte[ciphertext.length + computedMac.length];
84+
System.arraycopy(ciphertext, 0, output, 0, ciphertext.length);
85+
System.arraycopy(computedMac, 0, output, ciphertext.length, computedMac.length);
86+
}
87+
}

0 commit comments

Comments
 (0)