@@ -169,4 +169,165 @@ private module CryptographyModel {
169169 // Note: There is not really a key-size argument, since it's always specified by the curve.
170170 override DataFlow:: Node getKeySizeArg ( ) { none ( ) }
171171 }
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+ }
172333}
0 commit comments