@@ -25,6 +25,26 @@ abstract class CryptographicOperation extends Expr {
2525 */
2626abstract class CryptographicKey extends DataFlow:: ValueNode { }
2727
28+ /**
29+ * The creation of a cryptographic key.
30+ */
31+ abstract class CryptographicKeyCreation extends DataFlow:: Node {
32+ /**
33+ * Gets the algorithm used to create the key.
34+ */
35+ abstract CryptographicAlgorithm getAlgorithm ( ) ;
36+
37+ /**
38+ * Gets the size of the key.
39+ */
40+ abstract int getSize ( ) ;
41+
42+ /**
43+ * Gets whether the key is symmetric.
44+ */
45+ abstract predicate isSymmetricKey ( ) ;
46+ }
47+
2848/**
2949 * A key used in a cryptographic algorithm, viewed as a `CredentialsExpr`.
3050 */
@@ -141,21 +161,62 @@ private module NodeJSCrypto {
141161 * Also matches `createHash`, `createHmac`, `createSign` instead of `createCipher`.
142162 */
143163
144- exists ( DataFlow:: SourceNode mod , string createSuffix |
145- createSuffix = "Hash" or
146- createSuffix = "Hmac" or
147- createSuffix = "Sign" or
148- createSuffix = "Cipher"
149- |
164+ exists ( DataFlow:: SourceNode mod |
150165 mod = DataFlow:: moduleImport ( "crypto" ) and
151- this = mod .getAMemberCall ( "create" + createSuffix ) and
166+ this = mod .getAMemberCall ( "create" + [ "Hash" , "Hmac" , "Sign" , "Cipher" ] ) and
152167 algorithm .matchesName ( getArgument ( 0 ) .getStringValue ( ) )
153168 )
154169 }
155170
156171 CryptographicAlgorithm getAlgorithm ( ) { result = algorithm }
157172 }
158173
174+ private class CreateKey extends CryptographicKeyCreation , DataFlow:: CallNode {
175+ boolean symmetric ;
176+
177+ CreateKey ( ) {
178+ // crypto.generateKey(type, options, callback)
179+ // crypto.generateKeyPair(type, options, callback)
180+ // crypto.generateKeyPairSync(type, options)
181+ // crypto.generateKeySync(type, options)
182+ exists ( DataFlow:: SourceNode mod , string keyType |
183+ keyType = "Key" and symmetric = true
184+ or
185+ keyType = "KeyPair" and symmetric = false
186+ |
187+ mod = DataFlow:: moduleImport ( "crypto" ) and
188+ this = mod .getAMemberCall ( "generate" + keyType + [ "" , "Sync" ] )
189+ )
190+ }
191+
192+ override CryptographicAlgorithm getAlgorithm ( ) {
193+ result .matchesName ( getArgument ( 0 ) .getStringValue ( ) )
194+ }
195+
196+ override int getSize ( ) {
197+ symmetric = true and
198+ result = getOptionArgument ( 1 , "length" ) .getIntValue ( )
199+ or
200+ symmetric = false and
201+ result = getOptionArgument ( 1 , "modulusLength" ) .getIntValue ( )
202+ }
203+
204+ override predicate isSymmetricKey ( ) { symmetric = true }
205+ }
206+
207+ private class CreateDiffieHellmanKey extends CryptographicKeyCreation , DataFlow:: CallNode {
208+ // require("crypto").createDiffieHellman(prime_length);
209+ CreateDiffieHellmanKey ( ) {
210+ this = DataFlow:: moduleMember ( "crypto" , "createDiffieHellman" ) .getACall ( )
211+ }
212+
213+ override CryptographicAlgorithm getAlgorithm ( ) { none ( ) }
214+
215+ override int getSize ( ) { result = getArgument ( 0 ) .getIntValue ( ) }
216+
217+ override predicate isSymmetricKey ( ) { none ( ) }
218+ }
219+
159220 private class Apply extends CryptographicOperation , MethodCallExpr {
160221 InstantiatedAlgorithm instantiation ;
161222
@@ -282,6 +343,35 @@ private module CryptoJS {
282343 )
283344 }
284345 }
346+
347+ private class CreateKey extends CryptographicKeyCreation , DataFlow:: CallNode {
348+ string algorithm ;
349+ int optionArg ;
350+
351+ CreateKey ( ) {
352+ // var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
353+ this =
354+ getAlgorithmExpr ( any ( CryptographicAlgorithm algo | algo .getName ( ) = algorithm ) ) .getACall ( ) and
355+ optionArg = 2
356+ or
357+ // var key = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
358+ this =
359+ DataFlow:: moduleMember ( "crypto-js" , "algo" )
360+ .getAPropertyRead ( algorithm )
361+ .getAMethodCall ( "create" ) and
362+ optionArg = 0
363+ }
364+
365+ override CryptographicAlgorithm getAlgorithm ( ) { result .matchesName ( algorithm ) }
366+
367+ override int getSize ( ) {
368+ result = getOptionArgument ( optionArg , "keySize" ) .getIntValue ( ) * 32 // size is in words
369+ or
370+ result = getArgument ( optionArg ) .getIntValue ( ) * 32 // size is in words
371+ }
372+
373+ override predicate isSymmetricKey ( ) { any ( ) }
374+ }
285375}
286376
287377/**
@@ -467,6 +557,39 @@ private module Forge {
467557 private class Key extends CryptographicKey {
468558 Key ( ) { this = any ( KeyCipher cipher ) .getKey ( ) }
469559 }
560+
561+ private class CreateKey extends CryptographicKeyCreation , DataFlow:: CallNode {
562+ CryptographicAlgorithm algorithm ;
563+
564+ CreateKey ( ) {
565+ // var cipher = forge.rc2.createEncryptionCipher(key, 128);
566+ this =
567+ getAnImportNode ( )
568+ .getAPropertyRead ( any ( string s | algorithm .matchesName ( s ) ) )
569+ .getAMemberCall ( "createEncryptionCipher" )
570+ or
571+ // var key = forge.random.getBytesSync(16);
572+ // var cipher = forge.cipher.createCipher('AES-CBC', key);
573+ this =
574+ getAnImportNode ( )
575+ .getAPropertyRead ( "cipher" )
576+ .getAMemberCall ( [ "createCipher" , "createDecipher" ] ) and
577+ algorithm .matchesName ( this .getArgument ( 0 ) .getStringValue ( ) )
578+ }
579+
580+ override CryptographicAlgorithm getAlgorithm ( ) { result = algorithm }
581+
582+ override int getSize ( ) {
583+ result = this .getArgument ( 1 ) .getIntValue ( )
584+ or
585+ exists ( DataFlow:: CallNode call | call .getCalleeName ( ) = [ "getBytes" , "getBytesSync" ] |
586+ getArgument ( 1 ) .getALocalSource ( ) = call and
587+ result = call .getArgument ( 0 ) .getIntValue ( ) * 8 // bytes to bits
588+ )
589+ }
590+
591+ override predicate isSymmetricKey ( ) { any ( ) }
592+ }
470593}
471594
472595/**
@@ -556,13 +679,38 @@ private module Hasha {
556679
557680 override CryptographicAlgorithm getAlgorithm ( ) { result = algorithm }
558681 }
682+ }
559683
560- /**
561- * Provides classes for working with the `express-jwt` package (https://github.com/auth0/express-jwt);
562- */
563- module ExpressJwt {
564- private class Key extends CryptographicKey {
565- Key ( ) { this = DataFlow:: moduleMember ( "express-jwt" , "sign" ) .getACall ( ) .getArgument ( 1 ) }
684+ /**
685+ * Provides classes for working with the `express-jwt` package (https://github.com/auth0/express-jwt);
686+ */
687+ private module ExpressJwt {
688+ private class Key extends CryptographicKey {
689+ Key ( ) { this = DataFlow:: moduleMember ( "express-jwt" , "sign" ) .getACall ( ) .getArgument ( 1 ) }
690+ }
691+ }
692+
693+ /**
694+ * Provides classes for working with the `node-rsa` package (https://www.npmjs.com/package/node-rsa)
695+ */
696+ private module NodeRsa {
697+ private class CreateKey extends CryptographicKeyCreation , API:: InvokeNode {
698+ CryptographicAlgorithm algorithm ;
699+
700+ CreateKey ( ) {
701+ this = API:: moduleImport ( "node-rsa" ) .getAnInstantiation ( )
702+ or
703+ this = API:: moduleImport ( "node-rsa" ) .getInstance ( ) .getMember ( "generateKeyPair" ) .getACall ( )
566704 }
705+
706+ override CryptographicAlgorithm getAlgorithm ( ) { result .matchesName ( "rsa" ) }
707+
708+ override int getSize ( ) {
709+ result = this .getArgument ( 0 ) .getIntValue ( )
710+ or
711+ result = this .getOptionArgument ( 0 , "b" ) .getIntValue ( )
712+ }
713+
714+ override predicate isSymmetricKey ( ) { none ( ) }
567715 }
568716}
0 commit comments