Skip to content

Commit 9ee4a7a

Browse files
committed
Adding a sketch for a CipherOperation concept to model encryption/decryption operations.
1 parent 3871c6a commit 9ee4a7a

File tree

2 files changed

+70
-32
lines changed
  • java/ql/lib/experimental/Quantum
  • shared/cryptography/codeql/cryptography

2 files changed

+70
-32
lines changed

java/ql/lib/experimental/Quantum/JCA.qll

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ module JCAModel {
8383
class CipherGetInstanceAlgorithmArg extends Crypto::EncryptionAlgorithmInstance,
8484
Crypto::ModeOfOperationAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof Expr
8585
{
86-
CipherGetInstanceAlgorithmArg() {
87-
exists(CipherGetInstanceCall call | this = call.getArgument(0))
88-
}
86+
CipherGetInstanceCall call;
87+
88+
CipherGetInstanceAlgorithmArg() { this = call.getAlgorithmArg() }
8989

9090
/**
9191
* Returns the `StringLiteral` from which this argument is derived, if known.
@@ -94,37 +94,43 @@ module JCAModel {
9494
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(result),
9595
DataFlow::exprNode(this.(Expr).getAChildExpr*()))
9696
}
97+
98+
CipherGetInstanceCall getCall() { result = call }
9799
}
98100

99101
// TODO: what if encrypt/decrypt mode isn't known
100102
private module CipherGetInstanceToFinalizeConfig implements DataFlow::StateConfigSig {
101-
class FlowState = string;
103+
class FlowState = Crypto::TCipherOperationMode;
102104

103105
predicate isSource(DataFlow::Node src, FlowState state) {
104-
state = "UNKNOWN" and
106+
state = Crypto::UnknownCipherOperationMode() and
105107
src.asExpr() instanceof CipherGetInstanceCall
106108
}
107109

108110
predicate isSink(DataFlow::Node sink, FlowState state) {
109-
state in ["ENCRYPT", "DECRYPT", "UNKNOWN"] and
110111
exists(CipherDoFinalCall c | c.getQualifier() = sink.asExpr())
111112
}
112113

113114
predicate isAdditionalFlowStep(
114115
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
115116
) {
116-
state1 in ["UNKNOWN", "ENCRYPT", "DECRYPT"] and
117117
exists(CipherInitCall c |
118118
c.getQualifier() = node1.asExpr() and
119119
// TODO: not taking into consideration if the mode traces to this arg
120120
exists(FieldAccess fa |
121121
c.getModeArg() = fa and
122122
(
123123
fa.getField().getName() = "ENCRYPT_MODE" and
124-
state2 = "ENCRYPT"
124+
state2 = Crypto::EncryptionMode()
125125
or
126126
fa.getField().getName() = "DECRYPT_MODE" and
127-
state2 = "DECRYPT"
127+
state2 = Crypto::DecryptionMode()
128+
or
129+
fa.getField().getName() = "WRAP_MODE" and
130+
state2 = Crypto::EncryptionMode()
131+
or
132+
fa.getField().getName() = "UNWRAP_MODE" and
133+
state2 = Crypto::DecryptionMode()
128134
)
129135
)
130136
) and
@@ -135,16 +141,29 @@ module JCAModel {
135141
module CipherGetInstanceToFinalizeFlow =
136142
DataFlow::GlobalWithState<CipherGetInstanceToFinalizeConfig>;
137143

138-
// TODO: what if the mode is UNKNOWN?
139-
class CipherEncryptionOperation extends Crypto::EncryptionOperationInstance instanceof Call {
144+
class CipherEncryptionOperation extends Crypto::CipherOperationInstance instanceof Call {
145+
Crypto::TCipherOperationMode mode;
146+
Crypto::EncryptionAlgorithmInstance algorithm;
147+
140148
CipherEncryptionOperation() {
141-
exists(CipherGetInstanceToFinalizeFlow::PathNode sink, CipherDoFinalCall c |
142-
CipherGetInstanceToFinalizeFlow::flowPath(_, sink) and
143-
sink.getNode().asExpr() = c.getQualifier() and
144-
sink.getState() = "ENCRYPT" and
145-
this = c
149+
exists(
150+
CipherGetInstanceToFinalizeFlow::PathNode sink,
151+
CipherGetInstanceToFinalizeFlow::PathNode src, CipherGetInstanceCall getCipher,
152+
CipherDoFinalCall doFinalize, CipherGetInstanceAlgorithmArg arg
153+
|
154+
CipherGetInstanceToFinalizeFlow::flowPath(src, sink) and
155+
src.getNode().asExpr() = getCipher and
156+
sink.getNode().asExpr() = doFinalize.getQualifier() and
157+
sink.getState() = mode and
158+
this = doFinalize and
159+
arg.getCall() = getCipher and
160+
algorithm = arg
146161
)
147162
}
163+
164+
override Crypto::EncryptionAlgorithmInstance getAlgorithm() { result = algorithm }
165+
166+
override Crypto::TCipherOperationMode getCipherOperationMode() { result = mode }
148167
}
149168

150169
/**

shared/cryptography/codeql/cryptography/Model.qll

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
7979

8080
abstract class KeyDerivationAlgorithmInstance extends LocatableElement { }
8181

82-
abstract class EncryptionOperationInstance extends LocatableElement { }
82+
abstract class CipherOperationInstance extends LocatableElement {
83+
abstract EncryptionAlgorithmInstance getAlgorithm();
84+
85+
abstract TCipherOperationMode getCipherOperationMode();
86+
}
8387

8488
abstract class EncryptionAlgorithmInstance extends LocatableElement { }
8589

@@ -115,7 +119,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
115119
// Operations (e.g., hashing, encryption)
116120
THashOperation(HashOperationInstance e) or
117121
TKeyDerivationOperation(KeyDerivationOperationInstance e) or
118-
TEncryptionOperation(EncryptionOperationInstance e) or
122+
TCipherOperation(CipherOperationInstance e) or
119123
TKeyEncapsulationOperation(KeyEncapsulationOperationInstance e) or
120124
// Algorithms (e.g., SHA-256, AES)
121125
TEncryptionAlgorithm(EncryptionAlgorithmInstance e) or
@@ -238,13 +242,14 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
238242
*/
239243
abstract Algorithm getAlgorithm();
240244

241-
/**
242-
* Gets the name of this operation, e.g., "hash" or "encrypt".
243-
*/
244-
abstract string getOperationType();
245-
246-
final override string getInternalType() { result = this.getOperationType() }
247-
245+
// TODO: I only removed this because I want the operation type to be non-string
246+
// since for CipherOperations the user will have to pick the right type,
247+
// and I want to force them to use a type that is restricted. In this case to a TCipherOperationType
248+
// /**
249+
// * Gets the name of this operation, e.g., "hash" or "encrypt".
250+
// */
251+
// abstract string getOperationType();
252+
// final override string getInternalType() { result = this.getOperationType() }
248253
override NodeBase getChild(string edgeName) {
249254
result = super.getChild(edgeName)
250255
or
@@ -290,8 +295,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
290295
*/
291296
abstract class HashOperation extends Operation, THashOperation {
292297
abstract override HashAlgorithm getAlgorithm();
293-
294-
override string getOperationType() { result = "HashOperation" }
298+
//override string getOperationType() { result = "HashOperation" }
295299
}
296300

297301
newtype THashType =
@@ -401,8 +405,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
401405
final override Location getLocation() {
402406
exists(LocatableElement le | this = TKeyDerivationOperation(le) and result = le.getLocation())
403407
}
404-
405-
override string getOperationType() { result = "KeyDerivationOperation" }
408+
//override string getOperationType() { result = "KeyDerivationOperation" }
406409
}
407410

408411
/**
@@ -681,15 +684,31 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
681684
abstract override string getRawAlgorithmName();
682685
}
683686

687+
newtype TCipherOperationMode =
688+
EncryptionMode() or
689+
DecryptionMode() or
690+
UnknownCipherOperationMode()
691+
684692
/**
685693
* An encryption operation that processes plaintext to generate a ciphertext.
686694
* This operation takes an input message (plaintext) of arbitrary content and length
687695
* and produces a ciphertext as the output using a specified encryption algorithm (with a mode and padding).
688696
*/
689-
abstract class EncryptionOperation extends Operation, TEncryptionOperation {
690-
override string getOperationType() { result = "EncryptionOperation" }
697+
// NOTE FOR NICK: making this concrete here as I don't think users need to worry about making/extending these operations, just instances
698+
class CipherOperation extends Operation, TCipherOperation {
699+
CipherOperationInstance instance;
700+
701+
CipherOperation() { this = TCipherOperation(instance) }
702+
703+
override Location getLocation() { result = instance.getLocation() }
704+
705+
final TCipherOperationMode getCipherOperationMode() {
706+
result = instance.getCipherOperationMode()
707+
}
708+
709+
final override EncryptionAlgorithm getAlgorithm() { result = instance.getAlgorithm() }
691710

692-
abstract override EncryptionAlgorithm getAlgorithm();
711+
override string getInternalType() { result = "CipherOperation" }
693712
// /**
694713
// * Gets the initialization vector associated with this encryption operation.
695714
// *

0 commit comments

Comments
 (0)