Skip to content

Commit efc75e0

Browse files
authored
Merge pull request github#12168 from RasmusWL/crypto-stdlib-modeling
Python: Add modeling of `hmac`
2 parents 89aec09 + 1c7fe97 commit efc75e0

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added modeling of cryptographic operations in the `hmac` library.

python/ql/lib/semmle/python/frameworks/Stdlib.qll

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,6 +2669,7 @@ private module StdlibPrivate {
26692669

26702670
HashlibNewCall() {
26712671
this = hashlibNewCall(hashName) and
2672+
// we only want to consider it as an cryptographic operation if the input is available
26722673
exists(this.getParameter(1, "data"))
26732674
}
26742675

@@ -2751,6 +2752,78 @@ private module StdlibPrivate {
27512752
}
27522753
}
27532754

2755+
// ---------------------------------------------------------------------------
2756+
// hmac
2757+
// ---------------------------------------------------------------------------
2758+
abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range,
2759+
API::CallNode {
2760+
abstract API::Node getDigestArg();
2761+
2762+
override Cryptography::CryptographicAlgorithm getAlgorithm() {
2763+
exists(string algorithmName | result.matchesName(algorithmName) |
2764+
this.getDigestArg().asSink() = hashlibMember(algorithmName).asSource()
2765+
or
2766+
this.getDigestArg().getAValueReachingSink().asExpr().(StrConst).getText() = algorithmName
2767+
)
2768+
}
2769+
2770+
override Cryptography::BlockMode getBlockMode() { none() }
2771+
}
2772+
2773+
API::CallNode getHmacConstructorCall(API::Node digestArg) {
2774+
result = API::moduleImport("hmac").getMember(["new", "HMAC"]).getACall() and
2775+
digestArg = result.getParameter(2, "digestmod")
2776+
}
2777+
2778+
/**
2779+
* A call to `hmac.new`/`hmac.HMAC`.
2780+
*
2781+
* See https://docs.python.org/3.11/library/hmac.html#hmac.new
2782+
*/
2783+
class HmacNewCall extends HmacCryptographicOperation {
2784+
API::Node digestArg;
2785+
2786+
HmacNewCall() {
2787+
this = getHmacConstructorCall(digestArg) and
2788+
// we only want to consider it as an cryptographic operation if the input is available
2789+
exists(this.getParameter(1, "msg").asSink())
2790+
}
2791+
2792+
override API::Node getDigestArg() { result = digestArg }
2793+
2794+
override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() }
2795+
}
2796+
2797+
/**
2798+
* A call to `.update` on an HMAC object.
2799+
*
2800+
* See https://docs.python.org/3.11/library/hmac.html#hmac.HMAC.update
2801+
*/
2802+
class HmacUpdateCall extends HmacCryptographicOperation {
2803+
API::Node digestArg;
2804+
2805+
HmacUpdateCall() {
2806+
this = getHmacConstructorCall(digestArg).getReturn().getMember("update").getACall()
2807+
}
2808+
2809+
override API::Node getDigestArg() { result = digestArg }
2810+
2811+
override DataFlow::Node getAnInput() { result = this.getParameter(0, "msg").asSink() }
2812+
}
2813+
2814+
/**
2815+
* A call to `hmac.digest`.
2816+
*
2817+
* See https://docs.python.org/3.11/library/hmac.html#hmac.digest
2818+
*/
2819+
class HmacDigestCall extends HmacCryptographicOperation {
2820+
HmacDigestCall() { this = API::moduleImport("hmac").getMember("digest").getACall() }
2821+
2822+
override API::Node getDigestArg() { result = this.getParameter(2, "digest") }
2823+
2824+
override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() }
2825+
}
2826+
27542827
// ---------------------------------------------------------------------------
27552828
// logging
27562829
// ---------------------------------------------------------------------------
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import hmac
2+
import hashlib
3+
4+
key = b"<secret key>"
5+
6+
hmac_obj = hmac.new(key, b"secret message", "sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
7+
print(hmac_obj.digest())
8+
print(hmac_obj.hexdigest())
9+
10+
hmac_obj = hmac.new(key, msg=b"secret message", digestmod="sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
11+
print(hmac_obj.hexdigest())
12+
13+
14+
hmac_obj = hmac.new(key, digestmod="sha256")
15+
hmac_obj.update(b"secret") # $ CryptographicOperation CryptographicOperationInput=b"secret" CryptographicOperationAlgorithm=SHA256
16+
hmac_obj.update(msg=b" message") # $ CryptographicOperation CryptographicOperationInput=b" message" CryptographicOperationAlgorithm=SHA256
17+
print(hmac_obj.hexdigest())
18+
19+
20+
hmac_obj = hmac.new(key, b"secret message", hashlib.sha256) # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
21+
print(hmac_obj.hexdigest())
22+
23+
24+
# like hmac.new
25+
hmac_obj = hmac.HMAC(key, digestmod="sha256")
26+
hmac_obj.update(b"secret message") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
27+
print(hmac_obj.hexdigest())
28+
29+
30+
dig = hmac.digest(key, b"secret message", "sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
31+
print(dig)
32+
dig = hmac.digest(key, msg=b"secret message", digest="sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
33+
print(dig)

0 commit comments

Comments
 (0)