Skip to content

Commit ccf152d

Browse files
authored
Added support for progressive hashing in crypto-js module
1 parent c68c83c commit ccf152d

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,34 @@ private module NodeJSCrypto {
274274
* A model of the crypto-js library.
275275
*/
276276
private module CryptoJS {
277+
private class InstantiatedAlgorithm extends DataFlow::CallNode {
278+
CryptographicAlgorithm algorithm; // non-functional
279+
280+
InstantiatedAlgorithm() {
281+
/*
282+
* ```
283+
* const crypto = require("crypto-js");
284+
* const cipher = crypto.algo.SHA256.create();
285+
* ```
286+
* matched as:
287+
* ```
288+
* const crypto = require("crypto-js");
289+
* const cipher = crypto.algo.<algorithmName>.create();
290+
* ```
291+
*/
292+
293+
exists(DataFlow::SourceNode mod, DataFlow::PropRead propRead |
294+
mod = DataFlow::moduleImport("crypto-js") and
295+
propRead = mod.getAPropertyRead("algo").getAPropertyRead() and
296+
this = propRead.getAMemberCall("create") and
297+
not isStrongPasswordHashingAlgorithm(propRead.getPropertyName())
298+
)
299+
}
300+
301+
CryptographicAlgorithm getAlgorithm() { result = algorithm }
302+
}
303+
304+
277305
/**
278306
* Matches `CryptoJS.<algorithmName>` and `require("crypto-js/<algorithmName>")`
279307
*/
@@ -325,13 +353,39 @@ private module CryptoJS {
325353
input = result.getParameter(0)
326354
}
327355

356+
private DataFlow::CallNode getUpdatedApplication (DataFlow::Node input, InstantiatedAlgorithm instantiation) {
357+
/*
358+
* ```
359+
* var CryptoJS = require("crypto-js");
360+
* var hash = CryptoJS.algo.SHA256.create();
361+
* hash.update('message');
362+
* hash.update('password');
363+
* var hashInHex = hash.finalize();
364+
* ```
365+
* Matched as:
366+
* ```
367+
* var CryptoJS = require("crypto-js");
368+
* var hash = CryptoJS.algo.<algorithmName>.create();
369+
* hash.update(<input>);
370+
* hash.update(<input>);
371+
* var hashInHex = hash.finalize();
372+
* ```
373+
* Also matches where `CryptoJS.algo.<algorithmName>` has been
374+
* replaced by `require("crypto-js/<algorithmName>")`
375+
*/
376+
377+
result = instantiation.getAMemberCall("update") and
378+
input = result.getArgument(0)
379+
}
380+
328381
private class Apply extends CryptographicOperation::Range instanceof API::CallNode {
329382
API::Node input;
330383
CryptographicAlgorithm algorithm; // non-functional
331384

332385
Apply() {
333386
this = getEncryptionApplication(input, algorithm) or
334-
this = getDirectApplication(input, algorithm)
387+
this = getDirectApplication(input, algorithm) or
388+
this = getUpdatedApplication(input, instantiation)
335389
}
336390

337391
override DataFlow::Node getAnInput() { result = input.asSink() }

0 commit comments

Comments
 (0)