@@ -169,4 +169,165 @@ private module CryptographyModel {
169
169
// Note: There is not really a key-size argument, since it's always specified by the curve.
170
170
override DataFlow:: Node getKeySizeArg ( ) { none ( ) }
171
171
}
172
+
173
+ /** Provides models for the `cryptography.hazmat.primitives.ciphers` package */
174
+ private module Ciphers {
175
+ /** Gets a reference to a `cryptography.hazmat.primitives.ciphers.algorithms` Class */
176
+ API:: Node algorithmClassRef ( string algorithmName ) {
177
+ result =
178
+ API:: moduleImport ( "cryptography" )
179
+ .getMember ( "hazmat" )
180
+ .getMember ( "primitives" )
181
+ .getMember ( "ciphers" )
182
+ .getMember ( "algorithms" )
183
+ .getMember ( algorithmName )
184
+ }
185
+
186
+ /**
187
+ * Internal module making it easy to hide verbose type-tracking helpers.
188
+ *
189
+ * These turned out to be so verbose, that it was impossible to get an overview of
190
+ * the relevant predicates without hiding them away.
191
+ */
192
+ private module InternalTypeTracking {
193
+ /** Gets a reference to a Cipher instance using algorithm with `algorithmName`. */
194
+ DataFlow:: LocalSourceNode cipherInstance ( DataFlow:: TypeTracker t , string algorithmName ) {
195
+ t .start ( ) and
196
+ exists ( DataFlow:: CallCfgNode call | result = call |
197
+ call =
198
+ API:: moduleImport ( "cryptography" )
199
+ .getMember ( "hazmat" )
200
+ .getMember ( "primitives" )
201
+ .getMember ( "ciphers" )
202
+ .getMember ( "Cipher" )
203
+ .getACall ( ) and
204
+ algorithmClassRef ( algorithmName ) .getReturn ( ) .getAUse ( ) in [
205
+ call .getArg ( 0 ) , call .getArgByName ( "algorithm" )
206
+ ]
207
+ )
208
+ or
209
+ // Due to bad performance when using normal setup with `cipherInstance(t2, algorithmName).track(t2, t)`
210
+ // we have inlined that code and forced a join
211
+ exists ( DataFlow:: TypeTracker t2 |
212
+ exists ( DataFlow:: StepSummary summary |
213
+ cipherInstance_first_join ( t2 , algorithmName , result , summary ) and
214
+ t = t2 .append ( summary )
215
+ )
216
+ )
217
+ }
218
+
219
+ pragma [ nomagic]
220
+ private predicate cipherInstance_first_join (
221
+ DataFlow:: TypeTracker t2 , string algorithmName , DataFlow:: Node res ,
222
+ DataFlow:: StepSummary summary
223
+ ) {
224
+ DataFlow:: StepSummary:: step ( cipherInstance ( t2 , algorithmName ) , res , summary )
225
+ }
226
+
227
+ /** Gets a reference to the encryptor of a Cipher instance using algorithm with `algorithmName`. */
228
+ DataFlow:: LocalSourceNode cipherEncryptor ( DataFlow:: TypeTracker t , string algorithmName ) {
229
+ t .start ( ) and
230
+ exists ( DataFlow:: AttrRead attr |
231
+ result .( DataFlow:: CallCfgNode ) .getFunction ( ) = attr and
232
+ attr .getAttributeName ( ) = "encryptor" and
233
+ attr .getObject ( ) = cipherInstance ( algorithmName )
234
+ )
235
+ or
236
+ // Due to bad performance when using normal setup with `cipherEncryptor(t2, algorithmName).track(t2, t)`
237
+ // we have inlined that code and forced a join
238
+ exists ( DataFlow:: TypeTracker t2 |
239
+ exists ( DataFlow:: StepSummary summary |
240
+ cipherEncryptor_first_join ( t2 , algorithmName , result , summary ) and
241
+ t = t2 .append ( summary )
242
+ )
243
+ )
244
+ }
245
+
246
+ pragma [ nomagic]
247
+ private predicate cipherEncryptor_first_join (
248
+ DataFlow:: TypeTracker t2 , string algorithmName , DataFlow:: Node res ,
249
+ DataFlow:: StepSummary summary
250
+ ) {
251
+ DataFlow:: StepSummary:: step ( cipherEncryptor ( t2 , algorithmName ) , res , summary )
252
+ }
253
+
254
+ /** Gets a reference to the dncryptor of a Cipher instance using algorithm with `algorithmName`. */
255
+ DataFlow:: LocalSourceNode cipherDecryptor ( DataFlow:: TypeTracker t , string algorithmName ) {
256
+ t .start ( ) and
257
+ exists ( DataFlow:: AttrRead attr |
258
+ result .( DataFlow:: CallCfgNode ) .getFunction ( ) = attr and
259
+ attr .getAttributeName ( ) = "decryptor" and
260
+ attr .getObject ( ) = cipherInstance ( algorithmName )
261
+ )
262
+ or
263
+ // Due to bad performance when using normal setup with `cipherDecryptor(t2, algorithmName).track(t2, t)`
264
+ // we have inlined that code and forced a join
265
+ exists ( DataFlow:: TypeTracker t2 |
266
+ exists ( DataFlow:: StepSummary summary |
267
+ cipherDecryptor_first_join ( t2 , algorithmName , result , summary ) and
268
+ t = t2 .append ( summary )
269
+ )
270
+ )
271
+ }
272
+
273
+ pragma [ nomagic]
274
+ private predicate cipherDecryptor_first_join (
275
+ DataFlow:: TypeTracker t2 , string algorithmName , DataFlow:: Node res ,
276
+ DataFlow:: StepSummary summary
277
+ ) {
278
+ DataFlow:: StepSummary:: step ( cipherDecryptor ( t2 , algorithmName ) , res , summary )
279
+ }
280
+ }
281
+
282
+ private import InternalTypeTracking
283
+
284
+ /** Gets a reference to a Cipher instance using algorithm with `algorithmName`. */
285
+ DataFlow:: Node cipherInstance ( string algorithmName ) {
286
+ cipherInstance ( DataFlow:: TypeTracker:: end ( ) , algorithmName ) .flowsTo ( result )
287
+ }
288
+
289
+ /**
290
+ * Gets a reference to the encryptor of a Cipher instance using algorithm with `algorithmName`.
291
+ *
292
+ * You obtain an encryptor by using the `encryptor()` method on a Cipher instance.
293
+ */
294
+ DataFlow:: Node cipherEncryptor ( string algorithmName ) {
295
+ cipherEncryptor ( DataFlow:: TypeTracker:: end ( ) , algorithmName ) .flowsTo ( result )
296
+ }
297
+
298
+ /**
299
+ * Gets a reference to the decryptor of a Cipher instance using algorithm with `algorithmName`.
300
+ *
301
+ * You obtain an decryptor by using the `decryptor()` method on a Cipher instance.
302
+ */
303
+ DataFlow:: Node cipherDecryptor ( string algorithmName ) {
304
+ cipherDecryptor ( DataFlow:: TypeTracker:: end ( ) , algorithmName ) .flowsTo ( result )
305
+ }
306
+
307
+ /**
308
+ * An encrypt or decrypt operation from `cryptography.hazmat.primitives.ciphers`.
309
+ */
310
+ class CryptographyGenericCipherOperation extends Cryptography:: CryptographicOperation:: Range ,
311
+ DataFlow:: CallCfgNode {
312
+ string algorithmName ;
313
+
314
+ CryptographyGenericCipherOperation ( ) {
315
+ exists ( DataFlow:: AttrRead attr |
316
+ this .getFunction ( ) = attr and
317
+ attr .getAttributeName ( ) = [ "update" , "update_into" ] and
318
+ (
319
+ attr .getObject ( ) = cipherEncryptor ( algorithmName )
320
+ or
321
+ attr .getObject ( ) = cipherDecryptor ( algorithmName )
322
+ )
323
+ )
324
+ }
325
+
326
+ override Cryptography:: CryptographicAlgorithm getAlgorithm ( ) {
327
+ result .matchesName ( algorithmName )
328
+ }
329
+
330
+ override DataFlow:: Node getAnInput ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "data" ) ] }
331
+ }
332
+ }
172
333
}
0 commit comments