Skip to content

Commit 0f8a923

Browse files
ghislainpiotsonartech
authored andcommitted
SONARPY-2791 Expand support for Argon2 to S5344 (#196)
GitOrigin-RevId: bb4b754dce1d48498aeb49407e117d404fbd68db
1 parent f5ccb46 commit 0f8a923

2 files changed

Lines changed: 38 additions & 4 deletions

File tree

python-checks/src/main/java/org/sonar/python/checks/hotspots/FastHashingOrPlainTextCheck.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,35 @@ public class FastHashingOrPlainTextCheck extends PythonSubscriptionCheck {
183183
}
184184
});
185185

186-
private static final Map<String, Collection<CallValidator>> CALL_EXPRESSION_VALIDATORS = Map.ofEntries(
186+
187+
private TypeCheckBuilder argon2IDTypeChecker = null;
188+
private final CallValidator argon2Type = new ArgumentValidator(
189+
0, "type", (ctx, argument) -> {
190+
if (argon2IDTypeChecker.check(argument.expression().typeV2()) == TriBool.FALSE) {
191+
ctx.addIssue(argument, "Use Argon2ID to improve the security of the passwords.");
192+
}
193+
});
194+
private TypeCheckBuilder argon2VersionTypeChecker = null;
195+
private final CallValidator argon2Version = new ArgumentValidator(
196+
1, "version", (ctx, argument) -> {
197+
var typeCheck = argon2VersionTypeChecker.check(argument.expression().typeV2());
198+
if (typeCheck == TriBool.TRUE) {
199+
return;
200+
}
201+
if (!isEqualTo(argument.expression(), 19)) {
202+
ctx.addIssue(argument, "Use the latest version of Argon2 ID.");
203+
}
204+
});
205+
206+
private final Map<String, Collection<CallValidator>> callExpressionValidators = Map.ofEntries(
187207
Map.entry("scrypt.hash", List.of(SCRYPT_R, SCRYPT_BUFLEN, SCRYPT_N)),
188208
Map.entry("hashlib.scrypt", List.of(HASHLIB_R, HASHLIB_N, HASHLIB_DKLEN)),
189209
Map.entry("hashlib.pbkdf2_hmac", List.of(HASHLIB_PBKDF2)),
190210
Map.entry("cryptography.hazmat.primitives.kdf.scrypt.Scrypt", List.of(CRYPTOGRAPHY_R, CRYPTOGRAPHY_N, CRYPTOGRAPHY_LENGTH)),
191211
Map.entry("cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC", List.of(CRYPTOGRAPHY_PBKDF2)),
192212
Map.entry("passlib.handlers.scrypt.scrypt.using", List.of(PASSLIB_BLOCK_SIZE, PASSLIB_ROUNDS)),
193213
Map.entry("argon2.PasswordHasher", List.of(new Argon2PasswordHasherValidator(0, 1, 2))),
194-
Map.entry("argon2.Parameters", List.of(new Argon2PasswordHasherValidator(4, 5, 6))),
214+
Map.entry("argon2.Parameters", List.of(new Argon2PasswordHasherValidator(4, 5, 6), argon2Type, argon2Version)),
195215
Map.entry("argon2.low_level.hash_secret", List.of(new Argon2PasswordHasherValidator(2, 3, 4))),
196216
Map.entry("argon2.low_level.hash_secret_raw", List.of(new Argon2PasswordHasherValidator(2, 3, 4))),
197217
Map.entry("passlib.handlers.argon2._Argon2Common.using", List.of(new Argon2PasswordHasherValidator(3, 4, 5))),
@@ -254,8 +274,10 @@ private static void checkDjangoHasher(SubscriptionContext subscriptionContext) {
254274
private void registerTypeCheckers(SubscriptionContext subscriptionContext) {
255275
argon2CheapestProfileTypeChecker = subscriptionContext.typeChecker().typeCheckBuilder().isTypeWithFqn("argon2.profiles.CHEAPEST");
256276
flaskConfigTypeChecker = subscriptionContext.typeChecker().typeCheckBuilder().isInstanceOf("flask.config.Config");
277+
argon2IDTypeChecker = subscriptionContext.typeChecker().typeCheckBuilder().isTypeWithFqn("argon2.low_level.Type.ID");
278+
argon2VersionTypeChecker = subscriptionContext.typeChecker().typeCheckBuilder().isTypeWithFqn("argon2.low_level.ARGON2_VERSION");
257279
typeCheckMap = new TypeCheckMap<>();
258-
CALL_EXPRESSION_VALIDATORS.forEach((key, value) -> {
280+
callExpressionValidators.forEach((key, value) -> {
259281
var typeCheckBuilder = subscriptionContext.typeChecker().typeCheckBuilder().isTypeWithFqn(key);
260282
typeCheckMap.put(typeCheckBuilder, value);
261283
});

python-checks/src/test/resources/checks/fastHashingOrPlainText/fastHashingOrPlainText.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,19 @@ def manual_unsafe():
266266
parallelism=1,
267267
)
268268

269-
Parameters(type, version, salt_len, hash_len, 1, 1, 1) # Noncompliant
269+
from argon2.low_level import Type, ARGON2_VERSION
270+
Parameters(Type.ID, ARGON2_VERSION, salt_len, hash_len, 1, 1, 1) # Noncompliant
271+
272+
Parameters(Type.D, ARGON2_VERSION, salt_len, hash_len, smth, smth, smth) # Noncompliant {{Use Argon2ID to improve the security of the passwords.}}
273+
# ^^^^^^
274+
Parameters(Type.I, ARGON2_VERSION, salt_len, hash_len, smth, smth, smth) # Noncompliant
275+
Parameters(Type.ID, ARGON2_VERSION, salt_len, hash_len, smth, smth, smth)
276+
277+
Parameters(Type.ID, 18, salt_len, hash_len, smth, smth, smth) # Noncompliant {{Use the latest version of Argon2 ID.}}
278+
# ^^
279+
Parameters(Type.ID, 20, salt_len, hash_len, smth, smth, smth) # Noncompliant
280+
Parameters(Type.ID, 19, salt_len, hash_len, smth, smth, smth)
281+
Parameters(Type.ID, ARGON2_VERSION, salt_len, hash_len, smth, smth, smth)
270282

271283
from argon2.low_level import hash_secret, hash_secret_raw
272284
hash_secret( # Noncompliant

0 commit comments

Comments
 (0)