Skip to content

Commit 4b7099f

Browse files
thomas-serre-sonarsourcesonartech
authored andcommitted
SONARPY-1681 Symmetric cryptography (#202)
GitOrigin-RevId: 81dae175fd49be15a7f1c5fd573585010203ecfb
1 parent fb6aa23 commit 4b7099f

2 files changed

Lines changed: 28 additions & 5 deletions

File tree

python-checks/src/main/java/org/sonar/python/checks/RobustCipherAlgorithmCheck.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
public class RobustCipherAlgorithmCheck extends PythonSubscriptionCheck {
4545

4646
private static final String MESSAGE = "Use a strong cipher algorithm.";
47-
47+
private static final Set<String> INSECURE_CIPHERS_PREFIXES = Set.of("cryptography.hazmat.decrepit.ciphers.");
4848
private static final Set<String> INSECURE_CIPHERS = Set.of(
4949
"NULL",
5050
"aNULL",
@@ -75,21 +75,28 @@ public class RobustCipherAlgorithmCheck extends PythonSubscriptionCheck {
7575
"Crypto.Cipher.ARC2.new",
7676
"Crypto.Cipher.ARC4.new",
7777
"Crypto.Cipher.Blowfish.new",
78+
"Crypto.Cipher.XOR.new",
79+
"Crypto.Cipher.CAST.new",
7880
"Crypto.Cipher.DES.new",
7981
"Crypto.Cipher.DES3.new",
8082
"Cryptodome.Cipher.ARC2.new",
8183
"Cryptodome.Cipher.ARC4.new",
8284
"Cryptodome.Cipher.Blowfish.new",
85+
"Cryptodome.Cipher.XOR.new",
86+
"Cryptodome.Cipher.CAST.new",
8387
"Cryptodome.Cipher.DES.new",
8488
"Cryptodome.Cipher.DES3.new",
8589
"cryptography.hazmat.primitives.ciphers.algorithms.ARC4",
8690
"cryptography.hazmat.primitives.ciphers.algorithms.Blowfish",
8791
"cryptography.hazmat.primitives.ciphers.algorithms.IDEA",
92+
"cryptography.hazmat.primitives.ciphers.algorithms.CAST5",
8893
"cryptography.hazmat.primitives.ciphers.algorithms.TripleDES",
8994
"pyDes.des",
9095
"pyDes.triple_des"
9196
);
9297

98+
99+
93100
@Override
94101
public void initialize(Context context) {
95102
context.registerSyntaxNodeConsumer(Tree.Kind.CALL_EXPR, RobustCipherAlgorithmCheck::checkCallExpression);
@@ -101,7 +108,7 @@ private static void checkCallExpression(SubscriptionContext subscriptionContext)
101108
.map(CallExpression::calleeSymbol)
102109
.map(Symbol::fullyQualifiedName)
103110
.ifPresent(fullyQualifiedName -> {
104-
if (SENSITIVE_CALLEE_FQNS.contains(fullyQualifiedName)) {
111+
if (SENSITIVE_CALLEE_FQNS.contains(fullyQualifiedName) || INSECURE_CIPHERS_PREFIXES.stream().anyMatch(fullyQualifiedName::startsWith)) {
105112
subscriptionContext.addIssue(callExpr.callee(), MESSAGE);
106113
} else if (SSL_SET_CIPHERS_FQN.equals(fullyQualifiedName)) {
107114
checkForInsecureCiphers(subscriptionContext, callExpr);

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
21
def pycryptodomex_examples():
3-
from Cryptodome.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES
2+
from Cryptodome.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES, CAST
43
from Cryptodome.Random import get_random_bytes
54

65
key = b'-8B key-'
@@ -23,6 +22,10 @@ def pycryptodomex_examples():
2322
cipher = Blowfish.new(key, Blowfish.MODE_CBC) # Noncompliant {{Use a strong cipher algorithm.}}
2423
# ^^^^^^^^^^^^
2524

25+
key = os.urandom(16)
26+
cipher = CAST.new(key, CAST.MODE_OPENPGP) # Noncompliant {{Use a strong cipher algorithm.}}
27+
# ^^^^^^^^
28+
2629
key = b'Sixteen byte key'
2730
cipher = AES.new(key, AES.MODE_CCM) # Compliant
2831

@@ -35,7 +38,7 @@ def pycryptodomex_examples():
3538

3639
# pycryptodome is a drop-in replacement for pycrpypto, currently those two libraries are not differentiated
3740
def pycroptodome_examples():
38-
from Crypto.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES
41+
from Crypto.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES, CAST, XOR
3942
from Crypto.Random import get_random_bytes
4043

4144
key = b'-8B key-'
@@ -55,9 +58,18 @@ def pycroptodome_examples():
5558
cipher = Blowfish.new(key, Blowfish.MODE_CBC) # Noncompliant {{Use a strong cipher algorithm.}}
5659
# ^^^^^^^^^^^^
5760

61+
key = os.urandom(16)
62+
cipher = CAST.new(key, CAST.MODE_OPENPGP) # Noncompliant {{Use a strong cipher algorithm.}}
63+
# ^^^^^^^^
64+
65+
key = os.urandom(16)
66+
cipher = XOR.new(key) # Noncompliant {{Use a strong cipher algorithm.}}
67+
# ^^^^^^^
68+
5869
def pyca_examples():
5970
import os
6071
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
72+
from cryptography.hazmat.decrepit.ciphers.algorithms import AnyAlgoFromDeprecitModule
6173
from cryptography.hazmat.backends import default_backend
6274

6375
key = os.urandom(16)
@@ -69,6 +81,10 @@ def pyca_examples():
6981
# ^^^^^^^^^^^^^^^^^^^
7082
rc42 = Cipher(algorithms.ARC4(key), mode=None, backend=default_backend()) # Noncompliant {{Use a strong cipher algorithm.}}
7183
# ^^^^^^^^^^^^^^^
84+
casts5 = Cipher(algorithms.CAST5(key), mode=None, backend=default_backend()) # Noncompliant {{Use a strong cipher algorithm.}}
85+
# ^^^^^^^^^^^^^^^^
86+
deprecit = Cipher(AnyAlgoFromDeprecitModule(key), mode=None, backend=default_backend()) # Noncompliant {{Use a strong cipher algorithm.}}
87+
# ^^^^^^^^^^^^^^^^^^^^^^^^^
7288

7389
def pydes_examples():
7490
import pyDes;

0 commit comments

Comments
 (0)