Merge pull request #20696 from bdrodes/bad_mac_decrypt_then_mac

Crypto: Adding bad decrypt then mac order query.
This commit is contained in:
Nicolas Will
2025-10-24 22:07:26 +02:00
committed by GitHub
9 changed files with 329 additions and 47 deletions

View File

@@ -0,0 +1,36 @@
#select
| BadMacUse.java:152:42:152:51 | ciphertext | BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:152:42:152:51 | ciphertext | Incorrect decryption and MAC order: Decryption of cipher text occurs before validation of MAC on cipher text. |
edges
| BadMacUse.java:84:42:84:53 | bytes : byte[] | BadMacUse.java:92:31:92:35 | bytes : byte[] | provenance | |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:100:39:100:48 | ciphertext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:100:39:100:48 | ciphertext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:108:39:108:47 | plaintext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:108:39:108:47 | plaintext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:118:52:118:60 | plaintext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:118:52:118:60 | plaintext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:146:48:146:57 | ciphertext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:146:48:146:57 | ciphertext : byte[] | provenance | Config |
| BadMacUse.java:99:39:99:55 | ciphertext : byte[] | BadMacUse.java:100:39:100:48 | ciphertext : byte[] | provenance | |
| BadMacUse.java:100:39:100:48 | ciphertext : byte[] | BadMacUse.java:84:42:84:53 | bytes : byte[] | provenance | |
| BadMacUse.java:100:39:100:48 | ciphertext : byte[] | BadMacUse.java:84:42:84:53 | bytes : byte[] | provenance | |
| BadMacUse.java:108:39:108:47 | plaintext : byte[] | BadMacUse.java:84:42:84:53 | bytes : byte[] | provenance | |
| BadMacUse.java:118:52:118:60 | plaintext : byte[] | BadMacUse.java:84:42:84:53 | bytes : byte[] | provenance | |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] | BadMacUse.java:99:39:99:55 | ciphertext : byte[] | provenance | |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] | BadMacUse.java:152:42:152:51 | ciphertext | provenance | |
nodes
| BadMacUse.java:84:42:84:53 | bytes : byte[] | semmle.label | bytes : byte[] |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | semmle.label | bytes : byte[] |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | semmle.label | bytes : byte[] |
| BadMacUse.java:99:39:99:55 | ciphertext : byte[] | semmle.label | ciphertext : byte[] |
| BadMacUse.java:100:39:100:48 | ciphertext : byte[] | semmle.label | ciphertext : byte[] |
| BadMacUse.java:100:39:100:48 | ciphertext : byte[] | semmle.label | ciphertext : byte[] |
| BadMacUse.java:108:39:108:47 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:118:52:118:60 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] | semmle.label | ciphertext : byte[] |
| BadMacUse.java:152:42:152:51 | ciphertext | semmle.label | ciphertext |
subpaths
testFailures
| BadMacUse.java:50:56:50:65 | // $Source | Missing result: Source |
| BadMacUse.java:63:118:63:127 | // $Source | Missing result: Source |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | Unexpected result: Source |
| BadMacUse.java:146:95:146:104 | // $Source | Missing result: Source |

View File

@@ -0,0 +1,4 @@
query: experimental/quantum/Examples/BadMacOrderDecryptThenMac.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -34,3 +34,4 @@ testFailures
| BadMacUse.java:63:118:63:127 | // $Source | Missing result: Source |
| BadMacUse.java:92:16:92:36 | doFinal(...) : byte[] | Unexpected result: Source |
| BadMacUse.java:124:42:124:51 | ciphertext | Unexpected result: Alert |
| BadMacUse.java:146:95:146:104 | // $Source | Missing result: Source |

View File

@@ -1,14 +1,51 @@
#select
| BadMacUse.java:76:44:76:52 | plaintext | BadMacUse.java:63:82:63:97 | plaintext : byte[] | BadMacUse.java:76:44:76:52 | plaintext | Incorrect MAC usage: Encryption plaintext also used for MAC. Flow shows plaintext to final use through intermediate mac or encryption operation here $@ | BadMacUse.java:71:42:71:50 | plaintext | plaintext |
| BadMacUse.java:152:42:152:51 | ciphertext | BadMacUse.java:139:79:139:90 | input : byte[] | BadMacUse.java:152:42:152:51 | ciphertext | Incorrect MAC usage: Encryption plaintext also used for MAC. Flow shows plaintext to final use through intermediate mac or encryption operation here $@ | BadMacUse.java:92:31:92:35 | bytes | bytes |
edges
| BadMacUse.java:63:82:63:97 | plaintext : byte[] | BadMacUse.java:71:42:71:50 | plaintext : byte[] | provenance | |
| BadMacUse.java:71:42:71:50 | plaintext : byte[] | BadMacUse.java:71:42:71:50 | plaintext : byte[] | provenance | Config |
| BadMacUse.java:71:42:71:50 | plaintext : byte[] | BadMacUse.java:76:44:76:52 | plaintext | provenance | |
| BadMacUse.java:84:42:84:53 | bytes : byte[] | BadMacUse.java:92:31:92:35 | bytes : byte[] | provenance | |
| BadMacUse.java:84:42:84:53 | bytes : byte[] [[]] : Object | BadMacUse.java:92:31:92:35 | bytes : byte[] [[]] : Object | provenance | |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | BadMacUse.java:146:48:146:57 | ciphertext : byte[] | provenance | Config |
| BadMacUse.java:92:31:92:35 | bytes : byte[] [[]] : Object | BadMacUse.java:146:48:146:57 | ciphertext : byte[] | provenance | Config |
| BadMacUse.java:99:39:99:55 | ciphertext : byte[] [[]] : Object | BadMacUse.java:100:39:100:48 | ciphertext : byte[] [[]] : Object | provenance | |
| BadMacUse.java:100:39:100:48 | ciphertext : byte[] [[]] : Object | BadMacUse.java:84:42:84:53 | bytes : byte[] [[]] : Object | provenance | |
| BadMacUse.java:107:39:107:54 | plaintext : byte[] | BadMacUse.java:108:39:108:47 | plaintext : byte[] | provenance | |
| BadMacUse.java:108:39:108:47 | plaintext : byte[] | BadMacUse.java:84:42:84:53 | bytes : byte[] | provenance | |
| BadMacUse.java:114:92:114:107 | plaintext : byte[] | BadMacUse.java:118:52:118:60 | plaintext : byte[] | provenance | |
| BadMacUse.java:118:52:118:60 | plaintext : byte[] | BadMacUse.java:84:42:84:53 | bytes : byte[] | provenance | |
| BadMacUse.java:139:79:139:90 | input : byte[] | BadMacUse.java:142:48:142:52 | input : byte[] | provenance | |
| BadMacUse.java:142:29:142:82 | copyOfRange(...) : byte[] [[]] : Object | BadMacUse.java:146:48:146:57 | ciphertext : byte[] [[]] : Object | provenance | |
| BadMacUse.java:142:48:142:52 | input : byte[] | BadMacUse.java:142:29:142:82 | copyOfRange(...) : byte[] [[]] : Object | provenance | MaD:1 |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] | BadMacUse.java:152:42:152:51 | ciphertext | provenance | |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] [[]] : Object | BadMacUse.java:99:39:99:55 | ciphertext : byte[] [[]] : Object | provenance | |
models
| 1 | Summary: java.util; Arrays; false; copyOfRange; ; ; Argument[0].ArrayElement; ReturnValue.ArrayElement; value; manual |
nodes
| BadMacUse.java:63:82:63:97 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:71:42:71:50 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:71:42:71:50 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:76:44:76:52 | plaintext | semmle.label | plaintext |
| BadMacUse.java:84:42:84:53 | bytes : byte[] | semmle.label | bytes : byte[] |
| BadMacUse.java:84:42:84:53 | bytes : byte[] [[]] : Object | semmle.label | bytes : byte[] [[]] : Object |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | semmle.label | bytes : byte[] |
| BadMacUse.java:92:31:92:35 | bytes : byte[] [[]] : Object | semmle.label | bytes : byte[] [[]] : Object |
| BadMacUse.java:99:39:99:55 | ciphertext : byte[] [[]] : Object | semmle.label | ciphertext : byte[] [[]] : Object |
| BadMacUse.java:100:39:100:48 | ciphertext : byte[] [[]] : Object | semmle.label | ciphertext : byte[] [[]] : Object |
| BadMacUse.java:107:39:107:54 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:108:39:108:47 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:114:92:114:107 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:118:52:118:60 | plaintext : byte[] | semmle.label | plaintext : byte[] |
| BadMacUse.java:139:79:139:90 | input : byte[] | semmle.label | input : byte[] |
| BadMacUse.java:142:29:142:82 | copyOfRange(...) : byte[] [[]] : Object | semmle.label | copyOfRange(...) : byte[] [[]] : Object |
| BadMacUse.java:142:48:142:52 | input : byte[] | semmle.label | input : byte[] |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] | semmle.label | ciphertext : byte[] |
| BadMacUse.java:146:48:146:57 | ciphertext : byte[] [[]] : Object | semmle.label | ciphertext : byte[] [[]] : Object |
| BadMacUse.java:152:42:152:51 | ciphertext | semmle.label | ciphertext |
subpaths
testFailures
| BadMacUse.java:50:56:50:65 | // $Source | Missing result: Source |
| BadMacUse.java:139:79:139:90 | input : byte[] | Unexpected result: Source |
| BadMacUse.java:146:95:146:104 | // $Source | Missing result: Source |
| BadMacUse.java:152:42:152:51 | ciphertext | Unexpected result: Alert |

View File

@@ -53,7 +53,7 @@ class BadMacUse {
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(macKey);
byte[] computedMac = mac.doFinal(plaintext); // $Alert[java/quantum/examples/bad-mac-order-decrypt-to-mac]
byte[] computedMac = mac.doFinal(plaintext); // $Alert[java/quantum/examples/bad-mac-order-decrypt-to-mac]
if (!MessageDigest.isEqual(receivedMac, computedMac)) {
throw new SecurityException("MAC verification failed");
@@ -129,4 +129,30 @@ class BadMacUse {
System.arraycopy(computedMac, 0, output, ciphertext.length, computedMac.length);
return output;
}
/**
* Correct inputs to a decrypt and MAC operation, but the ordering is unsafe.
* The function decrypts THEN computes the MAC on the plaintext.
* It should have the MAC computed on the ciphertext first.
*/
public void decryptThenMac(byte[] encryptionKeyBytes, byte[] macKeyBytes, byte[] input) throws Exception {
// Split input into ciphertext and MAC
int macLength = 32; // HMAC-SHA256 output length
byte[] ciphertext = Arrays.copyOfRange(input, 0, input.length - macLength);
byte[] receivedMac = Arrays.copyOfRange(input, input.length - macLength, input.length);
// Decrypt first (unsafe)
byte[] plaintext = decryptUsingWrapper(ciphertext, encryptionKeyBytes, new byte[16]); // $Source
// Now verify MAC (too late)
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(macKey);
byte[] computedMac = mac.doFinal(ciphertext); // $Alert[java/quantum/examples/bad-mac-order-decrypt-then-mac], False positive for Plaintext reuse
if (!MessageDigest.isEqual(receivedMac, computedMac)) {
throw new SecurityException("MAC verification failed");
}
}
}