From 5b5065f49941ed564636117dcae9927734a79b8a Mon Sep 17 00:00:00 2001 From: san-zrl Date: Sat, 18 Jul 2026 09:07:48 +0200 Subject: [PATCH 1/9] python crypto/cryptodome detections rules, translations and tests Signed-off-by: san-zrl --- .../mapper/mapper/pyca/PycaCipherMapper.java | 10 +- .../mapper/mapper/pyca/PycaCurveMapper.java | 105 ++++ .../mapper/mapper/pyca/PycaDigestMapper.java | 19 + .../ibm/mapper/mapper/pyca/PycaMacMapper.java | 10 + .../ibm/mapper/model/algorithms/RIPEMD.java | 5 + .../rules/SignatureReorganizer.java | 17 +- .../rules/detection/PythonDetectionRules.java | 16 +- .../detection/crypto/PythonCryptoCipher.java | 247 ++++++++ .../detection/crypto/PythonCryptoHash.java | 85 +++ .../detection/crypto/PythonCryptoKDF.java | 164 +++++ .../crypto/PythonCryptoKeyAgreement.java | 105 ++++ .../detection/crypto/PythonCryptoMac.java | 82 +++ .../crypto/PythonCryptoPublicKey.java | 263 ++++++++ .../crypto/PythonCryptoSignature.java | 215 +++++++ .../reorganizer/PythonReorganizerRules.java | 10 + .../translator/PythonTranslator.java | 12 +- .../contexts/PycaCipherContextTranslator.java | 56 +- .../contexts/PycaDigestContextTranslator.java | 3 +- .../PycaKeyAgreementContextTranslator.java | 7 +- .../contexts/PycaKeyContextTranslator.java | 89 +++ .../PycaKeyDerivationContextTranslator.java | 34 +- .../contexts/PycaMacContextTranslator.java | 3 +- .../PycaPrivateKeyContextTranslator.java | 63 +- .../PycaPublicKeyContextTranslator.java | 17 + .../PycaSignatureContextTranslator.java | 6 + .../crypto/PythonCryptoCipher3DESTestFile.py | 4 + .../crypto/PythonCryptoCipherAESTestFile.py | 5 + .../PythonCryptoCipherBlowfishTestFile.py | 4 + .../crypto/PythonCryptoCipherCAST5TestFile.py | 4 + ...honCryptoCipherChaCha20Poly1305TestFile.py | 7 + .../PythonCryptoCipherChaCha20TestFile.py | 5 + .../crypto/PythonCryptoCipherDESTestFile.py | 5 + .../PythonCryptoCipherPKCS1OAEPTestFile.py | 6 + .../PythonCryptoCipherPKCS1v15TestFile.py | 5 + .../crypto/PythonCryptoCipherRC2TestFile.py | 4 + .../crypto/PythonCryptoCipherRC4TestFile.py | 4 + .../PythonCryptoCipherSalsa20TestFile.py | 5 + .../PythonCryptoEdDSAPureSignTestFile.py | 7 + .../PythonCryptoEdDSAPureVerifyTestFile.py | 13 + .../crypto/PythonCryptoHashBLAKE2bTestFile.py | 3 + .../crypto/PythonCryptoHashBLAKE2sTestFile.py | 3 + .../crypto/PythonCryptoHashMD2TestFile.py | 3 + .../crypto/PythonCryptoHashMD5TestFile.py | 3 + .../PythonCryptoHashRIPEMD160TestFile.py | 3 + .../crypto/PythonCryptoHashSHA1TestFile.py | 3 + .../crypto/PythonCryptoHashSHA224TestFile.py | 3 + .../crypto/PythonCryptoHashSHA256TestFile.py | 3 + .../crypto/PythonCryptoHashSHA384TestFile.py | 3 + .../PythonCryptoHashSHA3_224TestFile.py | 3 + .../PythonCryptoHashSHA3_256TestFile.py | 3 + .../PythonCryptoHashSHA3_384TestFile.py | 3 + .../PythonCryptoHashSHA3_512TestFile.py | 3 + .../crypto/PythonCryptoHashSHA512TestFile.py | 3 + .../PythonCryptoHashTupleHash128TestFile.py | 3 + .../PythonCryptoHashcSHAKE256TestFile.py | 3 + .../crypto/PythonCryptoKDFBcryptTestFile.py | 6 + .../crypto/PythonCryptoKDFHKDFTestFile.py | 7 + .../crypto/PythonCryptoKDFPBKDF1TestFile.py | 7 + .../crypto/PythonCryptoKDFPBKDF2TestFile.py | 7 + .../crypto/PythonCryptoKDFScryptTestFile.py | 6 + .../crypto/PythonCryptoKDFTestFile.py | 37 ++ .../PythonCryptoKeyAgreementDHTestFile.py | 3 + .../PythonCryptoKeyAgreementTestFile.py | 22 + ...ptoKeyAgreementX25519PrivateKeyTestFile.py | 3 + ...yptoKeyAgreementX25519PublicKeyTestFile.py | 3 + ...ryptoKeyAgreementX448PrivateKeyTestFile.py | 3 + ...CryptoKeyAgreementX448PublicKeyTestFile.py | 3 + .../crypto/PythonCryptoMacCMACTestFile.py | 5 + .../crypto/PythonCryptoMacHMACTestFile.py | 4 + .../crypto/PythonCryptoMacTestFile.py | 10 + .../PythonCryptoPublicKeyDSATestFile.py | 6 + .../PythonCryptoPublicKeyECCTestFile.py | 6 + .../PythonCryptoPublicKeyElGamalTestFile.py | 5 + .../PythonCryptoPublicKeyRSATestFile.py | 6 + .../PythonCryptoSignatureDSSSignTestFile.py | 9 + .../PythonCryptoSignatureDSSVerifyTestFile.py | 15 + .../PythonCryptoSignatureECDSASignTestFile.py | 9 + ...ythonCryptoSignatureECDSAVerifyTestFile.py | 15 + .../PythonCryptoSignatureEdDSASignTestFile.py | 9 + ...ythonCryptoSignatureEdDSAVerifyTestFile.py | 15 + ...thonCryptoSignaturePKCS1v15SignTestFile.py | 9 + ...onCryptoSignaturePKCS1v15VerifyTestFile.py | 15 + .../PythonCryptoSignaturePSSSignTestFile.py | 9 + .../PythonCryptoSignaturePSSVerifyTestFile.py | 16 + .../crypto/PythonCryptoCipherTest.java | 543 +++++++++++++++++ .../crypto/PythonCryptoHashTest.java | 563 ++++++++++++++++++ .../detection/crypto/PythonCryptoKDFTest.java | 347 +++++++++++ .../crypto/PythonCryptoKeyAgreementTest.java | 235 ++++++++ .../detection/crypto/PythonCryptoMacTest.java | 177 ++++++ .../crypto/PythonCryptoPublicKeyTest.java | 514 ++++++++++++++++ .../crypto/PythonCryptoSignatureTest.java | 431 ++++++++++++++ .../detection/hash/PycaHashDirectTest.java | 2 +- 92 files changed, 4761 insertions(+), 90 deletions(-) create mode 100644 mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCurveMapper.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java create mode 100644 python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyContextTranslator.java create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKDFTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoMacTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSASignTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSAVerifyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py create mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java index 5461d068d..f0b616838 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java @@ -26,12 +26,15 @@ import com.ibm.mapper.model.algorithms.Camellia; import com.ibm.mapper.model.algorithms.ChaCha20; import com.ibm.mapper.model.algorithms.ChaCha20Poly1305; +import com.ibm.mapper.model.algorithms.DES; import com.ibm.mapper.model.algorithms.Fernet; import com.ibm.mapper.model.algorithms.IDEA; +import com.ibm.mapper.model.algorithms.RC2; import com.ibm.mapper.model.algorithms.RC4; import com.ibm.mapper.model.algorithms.RSA; import com.ibm.mapper.model.algorithms.SEED; import com.ibm.mapper.model.algorithms.SM4; +import com.ibm.mapper.model.algorithms.Salsa20; import com.ibm.mapper.model.algorithms.TripleDES; import com.ibm.mapper.model.algorithms.cast.CAST128; import com.ibm.mapper.utils.DetectionLocation; @@ -53,14 +56,17 @@ public final class PycaCipherMapper implements IMapper { case "AES128" -> Optional.of(new AES(128, detectionLocation)); case "AES256" -> Optional.of(new AES(256, detectionLocation)); case "CAMELLIA" -> Optional.of(new Camellia(detectionLocation)); - case "TRIPLEDES" -> Optional.of(new TripleDES(detectionLocation)); + case "TRIPLEDES", "3DES" -> Optional.of(new TripleDES(detectionLocation)); + case "DES" -> Optional.of(new DES(detectionLocation)); case "CAST5" -> Optional.of(new CAST128(detectionLocation)); case "SEED" -> Optional.of(new SEED(detectionLocation)); case "SM4" -> Optional.of(new SM4(detectionLocation)); case "BLOWFISH" -> Optional.of(new Blowfish(detectionLocation)); case "IDEA" -> Optional.of(new IDEA(detectionLocation)); case "CHACHA20" -> Optional.of(new ChaCha20(detectionLocation)); - case "ARC4" -> Optional.of(new RC4(detectionLocation)); + case "SALSA20" -> Optional.of(new Salsa20(detectionLocation)); + case "ARC4", "RC4" -> Optional.of(new RC4(detectionLocation)); + case "RC2" -> Optional.of(new RC2(detectionLocation)); case "FERNET" -> Optional.of(new Fernet(detectionLocation)); case "RSA" -> Optional.of(new RSA(detectionLocation)); case "CHACHA20POLY1305" -> Optional.of(new ChaCha20Poly1305(detectionLocation)); diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCurveMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCurveMapper.java new file mode 100644 index 000000000..11b3fec9f --- /dev/null +++ b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCurveMapper.java @@ -0,0 +1,105 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.mapper.mapper.pyca; + +import com.ibm.mapper.mapper.IMapper; +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.EllipticCurveAlgorithm; +import com.ibm.mapper.model.curves.Brainpoolp256r1; +import com.ibm.mapper.model.curves.Brainpoolp384r1; +import com.ibm.mapper.model.curves.Brainpoolp512r1; +import com.ibm.mapper.model.curves.Curve25519; +import com.ibm.mapper.model.curves.Curve448; +import com.ibm.mapper.model.curves.Secp192r1; +import com.ibm.mapper.model.curves.Secp224r1; +import com.ibm.mapper.model.curves.Secp256r1; +import com.ibm.mapper.model.curves.Secp384r1; +import com.ibm.mapper.model.curves.Secp521r1; +import com.ibm.mapper.model.curves.Sect163k1; +import com.ibm.mapper.model.curves.Sect163r2; +import com.ibm.mapper.model.curves.Sect233k1; +import com.ibm.mapper.model.curves.Sect233r1; +import com.ibm.mapper.model.curves.Sect283k1; +import com.ibm.mapper.model.curves.Sect283r1; +import com.ibm.mapper.model.curves.Sect409k1; +import com.ibm.mapper.model.curves.Sect409r1; +import com.ibm.mapper.model.curves.Sect571k1; +import com.ibm.mapper.model.curves.Sect571r1; +import com.ibm.mapper.utils.DetectionLocation; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public final class PycaCurveMapper implements IMapper { + + @Nonnull + @Override + public Optional parse( + @Nullable String str, @Nonnull DetectionLocation detectionLocation) { + if (str == null) { + return Optional.empty(); + } + + @Nonnull String curve = str; + return switch (curve.toUpperCase().trim()) { + case "SECP192R1", "PRIME192V1", "P-192", "P192", "NIST P-192" -> + Optional.of(new EllipticCurveAlgorithm(new Secp192r1(detectionLocation))); + case "SECP224R1", "PRIME224V1", "P-224", "P224", "NIST P-224" -> + Optional.of(new EllipticCurveAlgorithm(new Secp224r1(detectionLocation))); + case "SECP256R1", "PRIME256V1", "P-256", "P256", "NIST P-256" -> + Optional.of(new EllipticCurveAlgorithm(new Secp256r1(detectionLocation))); + case "SECP384R1", "PRIME384V1", "P-384", "P384", "NIST P-384" -> + Optional.of(new EllipticCurveAlgorithm(new Secp384r1(detectionLocation))); + case "SECP512R1", "PRIME512V1", "P-512", "P512", "NIST P-512" -> + Optional.of(new EllipticCurveAlgorithm(new Secp521r1(detectionLocation))); + case "ED25519", "CURVE25519" -> + Optional.of(new EllipticCurveAlgorithm(new Curve25519(detectionLocation))); + case "ED448", "CURVE448" -> + Optional.of(new EllipticCurveAlgorithm(new Curve448(detectionLocation))); + case "BRAINPOOLP256R1" -> + Optional.of(new EllipticCurveAlgorithm(new Brainpoolp256r1(detectionLocation))); + case "BRAINPOOLP384R1" -> + Optional.of(new EllipticCurveAlgorithm(new Brainpoolp384r1(detectionLocation))); + case "BRAINPOOLP512R1" -> + Optional.of(new EllipticCurveAlgorithm(new Brainpoolp512r1(detectionLocation))); + case "SECT571K1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect571k1(detectionLocation))); + case "SECT409K1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect409k1(detectionLocation))); + case "SECT283K1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect283k1(detectionLocation))); + case "SECT233K1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect233k1(detectionLocation))); + case "SECT163K1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect163k1(detectionLocation))); + case "SECT571R1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect571r1(detectionLocation))); + case "SECT409R1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect409r1(detectionLocation))); + case "SECT283R1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect283r1(detectionLocation))); + case "SECT233R1" -> + Optional.of(new EllipticCurveAlgorithm(new Sect233r1(detectionLocation))); + case "SECT163R2" -> + Optional.of(new EllipticCurveAlgorithm(new Sect163r2(detectionLocation))); + default -> Optional.empty(); + }; + } +} diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaDigestMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaDigestMapper.java index 8e2a1ca3e..b213ba7fa 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaDigestMapper.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaDigestMapper.java @@ -21,14 +21,22 @@ import com.ibm.mapper.mapper.IMapper; import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.algorithms.KMAC; +import com.ibm.mapper.model.algorithms.KangarooTwelve; +import com.ibm.mapper.model.algorithms.Keccak; +import com.ibm.mapper.model.algorithms.MD2; +import com.ibm.mapper.model.algorithms.MD4; import com.ibm.mapper.model.algorithms.MD5; import com.ibm.mapper.model.algorithms.Poly1305; +import com.ibm.mapper.model.algorithms.RIPEMD; import com.ibm.mapper.model.algorithms.SHA; import com.ibm.mapper.model.algorithms.SHA2; import com.ibm.mapper.model.algorithms.SHA3; import com.ibm.mapper.model.algorithms.SM3; +import com.ibm.mapper.model.algorithms.TupleHash; import com.ibm.mapper.model.algorithms.blake.BLAKE2b; import com.ibm.mapper.model.algorithms.blake.BLAKE2s; +import com.ibm.mapper.model.algorithms.shake.CSHAKE; import com.ibm.mapper.model.algorithms.shake.SHAKE; import com.ibm.mapper.utils.DetectionLocation; import java.util.Optional; @@ -59,11 +67,22 @@ public final class PycaDigestMapper implements IMapper { case "SHA3_512" -> Optional.of(new SHA3(512, detectionLocation)); case "SHAKE128" -> Optional.of(new SHAKE(128, detectionLocation)); case "SHAKE256" -> Optional.of(new SHAKE(256, detectionLocation)); + case "MD2" -> Optional.of(new MD2(detectionLocation)); + case "MD4" -> Optional.of(new MD4(detectionLocation)); case "MD5" -> Optional.of(new MD5(detectionLocation)); case "BLAKE2B" -> Optional.of(new BLAKE2b(false, detectionLocation)); case "BLAKE2S" -> Optional.of(new BLAKE2s(false, detectionLocation)); case "SM3" -> Optional.of(new SM3(detectionLocation)); case "POLY1305" -> Optional.of(new Poly1305(detectionLocation)); + case "RIPEMD160" -> Optional.of(new RIPEMD(160, detectionLocation)); + case "TUPLEHASH128" -> Optional.of(new TupleHash(128, detectionLocation)); + case "TUPLEHASH256" -> Optional.of(new TupleHash(256, detectionLocation)); + case "KMAC128" -> Optional.of(new KMAC(128, detectionLocation)); + case "KMAC256" -> Optional.of(new KMAC(256, detectionLocation)); + case "KECCAK" -> Optional.of(new Keccak(detectionLocation)); + case "CSHAKE128" -> Optional.of(new CSHAKE(128, detectionLocation)); + case "CSHAKE256" -> Optional.of(new CSHAKE(256, detectionLocation)); + case "KANGAROOTWELVE" -> Optional.of(new KangarooTwelve(detectionLocation)); default -> Optional.empty(); }; } diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaMacMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaMacMapper.java index 777eca70b..20cc3e60b 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaMacMapper.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaMacMapper.java @@ -28,9 +28,11 @@ import com.ibm.mapper.model.algorithms.ChaCha20; import com.ibm.mapper.model.algorithms.Fernet; import com.ibm.mapper.model.algorithms.IDEA; +import com.ibm.mapper.model.algorithms.MD2; import com.ibm.mapper.model.algorithms.MD5; import com.ibm.mapper.model.algorithms.Poly1305; import com.ibm.mapper.model.algorithms.RC4; +import com.ibm.mapper.model.algorithms.RIPEMD; import com.ibm.mapper.model.algorithms.RSA; import com.ibm.mapper.model.algorithms.SEED; import com.ibm.mapper.model.algorithms.SHA; @@ -42,6 +44,7 @@ import com.ibm.mapper.model.algorithms.blake.BLAKE2b; import com.ibm.mapper.model.algorithms.blake.BLAKE2s; import com.ibm.mapper.model.algorithms.cast.CAST128; +import com.ibm.mapper.model.algorithms.shake.CSHAKE; import com.ibm.mapper.model.algorithms.shake.SHAKE; import com.ibm.mapper.utils.DetectionLocation; import java.util.Optional; @@ -104,6 +107,7 @@ public class PycaMacMapper implements IMapper { case "SHAKE128" -> Optional.of(new SHAKE(Mac.class, new SHAKE(128, detectionLocation))); case "SHAKE256" -> Optional.of(new SHAKE(Mac.class, new SHAKE(256, detectionLocation))); case "MD5" -> Optional.of(new MD5(Mac.class, detectionLocation)); + case "MD2" -> Optional.of(new MD2(Mac.class, detectionLocation)); case "BLAKE2B" -> Optional.of(new BLAKE2b(Mac.class, new BLAKE2b(false, detectionLocation))); case "BLAKE2S" -> @@ -111,6 +115,12 @@ public class PycaMacMapper implements IMapper { case "SM3" -> Optional.of(new SM3(Mac.class, new SM3(detectionLocation))); case "POLY1305" -> Optional.of(new Poly1305(Mac.class, new Poly1305(detectionLocation))); + case "RIPEMD160" -> + Optional.of(new RIPEMD(Mac.class, new RIPEMD(160, detectionLocation))); + case "CSHAKE128" -> + Optional.of(new CSHAKE(Mac.class, new CSHAKE(128, detectionLocation))); + case "CSHAKE256" -> + Optional.of(new CSHAKE(Mac.class, new CSHAKE(256, detectionLocation))); default -> Optional.empty(); }; } diff --git a/mapper/src/main/java/com/ibm/mapper/model/algorithms/RIPEMD.java b/mapper/src/main/java/com/ibm/mapper/model/algorithms/RIPEMD.java index 4ed5f0860..15766ae7d 100644 --- a/mapper/src/main/java/com/ibm/mapper/model/algorithms/RIPEMD.java +++ b/mapper/src/main/java/com/ibm/mapper/model/algorithms/RIPEMD.java @@ -22,6 +22,7 @@ import com.ibm.mapper.model.Algorithm; import com.ibm.mapper.model.DigestSize; import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.IPrimitive; import com.ibm.mapper.model.MessageDigest; import com.ibm.mapper.utils.DetectionLocation; import java.util.Optional; @@ -72,4 +73,8 @@ public RIPEMD(int digestSize, @Nonnull DetectionLocation detectionLocation) { this(detectionLocation); this.put(new DigestSize(digestSize, detectionLocation)); } + + public RIPEMD(@Nonnull final Class asKind, @Nonnull RIPEMD ripemd) { + super(ripemd, asKind); + } } diff --git a/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java b/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java index 5a4708993..4e434e932 100644 --- a/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java +++ b/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java @@ -252,12 +252,17 @@ public static IReorganizerRule moveNodesFromUnderFunctionalityUnderParent( Optional.ofNullable(parent) .ifPresent( p -> { - for (Map.Entry, INode> - childKeyValue : - node.getChildren().entrySet()) { - p.put(childKeyValue.getValue()); - node.removeChildOfType(childKeyValue.getKey()); - } + // Avoids java.util.ConcurrentModificationException + // thrown by original code + node.getChildren().values().forEach(p::put); + node.getChildren().clear(); + // for (Map.Entry, INode> + // childKeyValue : + // node.getChildren().entrySet()) { + // p.put(childKeyValue.getValue()); + // + // node.removeChildOfType(childKeyValue.getKey()); + // } }); return null; }); diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java b/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java index b6453be38..4d774d79d 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java @@ -27,6 +27,13 @@ import com.ibm.plugin.rules.detection.asymmetric.PycaEllipticCurve; import com.ibm.plugin.rules.detection.asymmetric.PycaRSA; import com.ibm.plugin.rules.detection.asymmetric.PycaSign; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoCipher; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoHash; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoKDF; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoKeyAgreement; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoMac; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoPublicKey; +import com.ibm.plugin.rules.detection.crypto.PythonCryptoSignature; import com.ibm.plugin.rules.detection.fernet.PycaFernet; import com.ibm.plugin.rules.detection.hash.PycaHash; import com.ibm.plugin.rules.detection.kdf.PycaKDF; @@ -70,7 +77,14 @@ private static List> buildRules() { PycaMAC.rules().stream(), PycaWrapping.rules().stream(), PycaKDF.rules().stream(), - PycaFernet.rules().stream()) + PycaFernet.rules().stream(), + PythonCryptoHash.rules().stream(), + PythonCryptoMac.rules().stream(), + PythonCryptoCipher.rules().stream(), + PythonCryptoPublicKey.rules().stream(), + PythonCryptoSignature.rules().stream(), + PythonCryptoKDF.rules().stream(), + PythonCryptoKeyAgreement.rules().stream()) .flatMap(i -> i) .toList(); } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java new file mode 100644 index 000000000..4394e1f59 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java @@ -0,0 +1,247 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static com.ibm.engine.detection.MethodMatcher.ANY; + +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.CipherActionFactory; +import com.ibm.engine.model.factory.ModeFactory; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoCipher { + + private PythonCryptoCipher() { + // private + } + + private static final IDetectionRule ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("encrypt") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.ENCRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("decrypt") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.DECRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.AES") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("AES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.AES.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.DES") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("DES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.DES.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES3_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.DES3") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("3DES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.DES3.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule BLOWFISH_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.Blowfish") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("Blowfish")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.Blowfish.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule CAST_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.CAST") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.CAST.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule ARC2_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ARC2") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.ARC2.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule ARC4_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ARC4") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4")) + .withAnyParameters() + .buildForContext(new CipherContext(Map.of("algorithm", "RC4"))) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule CHACHA20_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ChaCha20") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule CHACHA20_POLY1305_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ChaCha20_Poly1305") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20Poly1305")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule SALSA20_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.Salsa20") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("Salsa20")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule PKCS1_OAEP_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) + .withAnyParameters() // This must be changed if the rule below is enabled. + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + +// // Variant with hash algo. This detects the hash but it won't be mapped. +// private static final IDetectionRule PKCS1_OAEP_NEW_WITH_HASH = +// new DetectionRuleBuilder() +// .createDetectionRule() +// .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") +// .forMethods("new") +// .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) +// .withMethodParameter(ANY) // key +// .withMethodParameter("Crypto.Hash.*") +// .shouldBeDetectedAs(new AlgorithmFactory<>()) +// .asChildOfParameterWithId(-1) +// .buildForContext(new CipherContext()) +// .inBundle(() -> "PyCrypto") +// .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule PKCS1_V1_5_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectExactTypes("Crypto.Cipher.PKCS1_v1_5") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_v1_5")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + @Nonnull + public static List> rules() { + return List.of( + AES_NEW, + DES_NEW, + DES3_NEW, + BLOWFISH_NEW, + CAST_NEW, + ARC2_NEW, + ARC4_NEW, + CHACHA20_NEW, + CHACHA20_POLY1305_NEW, + SALSA20_NEW, + PKCS1_OAEP_NEW, + // PKCS1_OAEP_NEW_WITH_HASH, + PKCS1_V1_5_NEW); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java new file mode 100644 index 000000000..29a2d6673 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java @@ -0,0 +1,85 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import com.ibm.engine.model.context.DigestContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoHash { + + private PythonCryptoHash() { + // private + } + + public static final List hashes = + Arrays.asList( + "MD2", + "MD4", + "MD5", + "SHA1", + "SHA224", + "SHA256", + "SHA384", + "SHA512", + "SHA3_224", + "SHA3_256", + "SHA3_384", + "SHA3_512", + "RIPEMD160", + "keccak", + "TupleHash128", + "TupleHash256", + "SHAKE128", + "SHAKE256", + "cSHAKE128", + "cSHAKE256", + "KMAC128", + "KMAC256", + "KangarooTwelve", + "Poly1305", + "BLAKE2b", + "BLAKE2s"); + + @Nonnull + public static List> rules() { + LinkedList> rules = new LinkedList<>(); + for (final String hash : PythonCryptoHash.hashes) { + rules.add( + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Hash." + hash) + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>(hash)) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules()); + } + return rules; + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java new file mode 100644 index 000000000..c841d624f --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java @@ -0,0 +1,164 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static com.ibm.engine.detection.MethodMatcher.ANY; + +import com.ibm.engine.model.AlgorithmParameter; +import com.ibm.engine.model.Size; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.engine.model.factory.AlgorithmFactory; +import com.ibm.engine.model.factory.AlgorithmParameterFactory; +import com.ibm.engine.model.factory.KeySizeFactory; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoKDF { + + private PythonCryptoKDF() { + // private + } + + // PBKDF1 - module function call + private static final IDetectionRule PBKDF1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.KDF") + .forMethods("PBKDF1") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF1")) + .withMethodParameter(ANY) // password + .withMethodParameter(ANY) // salt + .withMethodParameter("int") // dkLen + .shouldBeDetectedAs(new KeySizeFactory<>(Size.UnitType.BYTE)) + .asChildOfParameterWithId(-1) + .withMethodParameter("int") // count + .shouldBeDetectedAs( + new AlgorithmParameterFactory<>(AlgorithmParameter.Kind.ITERATIONS)) + .asChildOfParameterWithId(-1) + .withMethodParameter("Crypto.Hash.*") // hashAlgo + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext( + new KeyDerivationFunctionContext(Map.of("kind", "pycrypto-pbkdf1"))) + .inBundle(() -> "PyCa") + .withoutDependingDetectionRules(); + + // PBKDF2 - module function call + private static final IDetectionRule PBKDF2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.KDF") + .forMethods("PBKDF2") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2")) + .withMethodParameter(ANY) // password + .withMethodParameter(ANY) // salt + .withMethodParameter("int") // dkLen + .shouldBeDetectedAs(new KeySizeFactory<>(Size.UnitType.BYTE)) + .asChildOfParameterWithId(-1) + .withMethodParameter("int") // count + .shouldBeDetectedAs( + new AlgorithmParameterFactory<>(AlgorithmParameter.Kind.ITERATIONS)) + .withMethodParameter("Crypto.Hash.*") // hashAlgo + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext( + new KeyDerivationFunctionContext(Map.of("kind", "pycrypto-pbkdf2"))) + .inBundle(() -> "PyCa") + .withoutDependingDetectionRules(); + + // scrypt - module function call + private static final IDetectionRule SCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.KDF") + .forMethods("scrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("scrypt")) + .withMethodParameter(ANY) // password + .withMethodParameter(ANY) // salt + .withMethodParameter("int") // key_len + .shouldBeDetectedAs(new KeySizeFactory<>(Size.UnitType.BYTE)) + .asChildOfParameterWithId(-1) + .withMethodParameter("int") // N + .withMethodParameter("int") // r + .withMethodParameter("int") // p + .withMethodParameter("int") // num_keys + .buildForContext(new KeyDerivationFunctionContext(Map.of("kind", "scrypt"))) + .inBundle(() -> "PyCa") + .withoutDependingDetectionRules(); + + // bcrypt - module function call + private static final IDetectionRule BCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.KDF") + .forMethods("bcrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("bcrypt")) + .withMethodParameter(ANY) // password + .withMethodParameter("int") // cost + .shouldBeDetectedAs( + new AlgorithmParameterFactory<>(AlgorithmParameter.Kind.ITERATIONS)) + .withMethodParameter(ANY) // salt + .buildForContext(new KeyDerivationFunctionContext(Map.of("kind", "bcrypt"))) + .inBundle(() -> "PyCa") + .withoutDependingDetectionRules(); + + // bcrypt_check - module function call + private static final IDetectionRule BCRYPT_CHECK = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.KDF") + .forMethods("bcrypt_check") + .shouldBeDetectedAs(new ValueActionFactory<>("bcrypt")) + .withMethodParameter(ANY) // password + .withMethodParameter(ANY) // bcrypt_hash + .buildForContext(new KeyDerivationFunctionContext(Map.of("kind", "bcrypt"))) + .inBundle(() -> "PyCa") + .withoutDependingDetectionRules(); + + private static final IDetectionRule HKDF = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.KDF") + .forMethods("HKDF") + .shouldBeDetectedAs(new ValueActionFactory<>("HKDF")) + .withMethodParameter(ANY) // master + .withMethodParameter("int") // keylen + .shouldBeDetectedAs(new KeySizeFactory<>(Size.UnitType.BYTE)) + .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // salt + .withMethodParameter("Crypto.Hash.*") // hash_mod + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext( + new KeyDerivationFunctionContext(Map.of("kind", "pycrypto-hkdf"))) + .inBundle(() -> "PyCa") + .withoutDependingDetectionRules(); + + @Nonnull + public static List> rules() { + return List.of(PBKDF1, PBKDF2, SCRYPT, BCRYPT, BCRYPT_CHECK, HKDF); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java new file mode 100644 index 000000000..6135770b3 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java @@ -0,0 +1,105 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.engine.model.factory.KeyActionFactory; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoKeyAgreement { + + private PythonCryptoKeyAgreement() { + // private + } + + // DH.key_agreement - module function call + private static final IDetectionRule DH_KEY_AGREEMENT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.DH") + .forMethods("key_agreement") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule IMPORT_X25519_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.DH") + .forMethods("import_x25519_public_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyAgreementContext(Map.of("algorithm", "x25519"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule IMPORT_X25519_PRIVATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.DH") + .forMethods("import_x25519_private_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyAgreementContext(Map.of("algorithm", "x25519"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule IMPORT_X448_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.DH") + .forMethods("import_x448_public_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyAgreementContext(Map.of("algorithm", "x448"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule IMPORT_X448_PRIVATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Protocol.DH") + .forMethods("import_x448_private_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyAgreementContext(Map.of("algorithm", "x448"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + @Nonnull + public static List> rules() { + return List.of( + DH_KEY_AGREEMENT, + IMPORT_X25519_PUBLIC_KEY, + IMPORT_X25519_PRIVATE_KEY, + IMPORT_X448_PUBLIC_KEY, + IMPORT_X448_PRIVATE_KEY); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java new file mode 100644 index 000000000..58b3af4c4 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java @@ -0,0 +1,82 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static com.ibm.engine.detection.MethodMatcher.ANY; + +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.factory.AlgorithmFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoMac { + + private PythonCryptoMac() { + // private + } + + private static final IDetectionRule NEW_CMAC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Hash.CMAC") + .forMethods("new") + .withMethodParameter(ANY) // key + .withMethodParameter("Crypto.Cipher.*") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .buildForContext(new MacContext(Map.of("kind", "cmac"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule NEW_HMAC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Hash.HMAC") + .forMethods("new") + .withMethodParameter(ANY) // secret + .withMethodParameter("Crypto.Hash.*") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .buildForContext(new MacContext(Map.of("kind", "hmac"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // Crypto Poly1305 is the old algorithm that requires a cipher parameter. + // Our Poly1305 class represents the modern IETF standard (RFC 7539 / RFC 8439). + // private static final IDetectionRule NEW_POLY1305 = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectTypes("Crypto.Hash.Poly1305") + // .forMethods("new") + // .withMethodParameter(ANY) // key + // .withMethodParameter("Crypto.Cipher.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .buildForContext(new MacContext(Map.of("kind", "poly1305"))) + // .inBundle(() -> "PyCrypto") + // .withoutDependingDetectionRules(); + + @Nonnull + public static List> rules() { + return List.of(NEW_CMAC, NEW_HMAC); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java new file mode 100644 index 000000000..b06a2819c --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java @@ -0,0 +1,263 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.Size; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.engine.model.context.PublicKeyContext; +import com.ibm.engine.model.factory.CurveFactory; +import com.ibm.engine.model.factory.KeyActionFactory; +import com.ibm.engine.model.factory.KeySizeFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoPublicKey { + + private PythonCryptoPublicKey() { + // private + } + + // RSA generate -> private key + private static final IDetectionRule RSA_GENERATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.RSA") + .forMethods("generate") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PRIVATE_KEY_GENERATION)) + .withMethodParameter("int") // keylen + .shouldBeDetectedAs(new KeySizeFactory<>(Size.UnitType.BIT)) + .asChildOfParameterWithId(-1) + .buildForContext(new PrivateKeyContext(Map.of("algorithm", "RSA"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // RSA construct and import_key -> public or private key + private static final IDetectionRule RSA_CONSTRUCT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.RSA") + .forMethods("construct", "import_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyContext(Map.of("algorithm", "RSA"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // RsaKey public_key -> public key + private static final IDetectionRule RSA_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.RSA.RsaKey") + .forMethods("public_key") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PUBLIC_KEY_GENERATION)) + .withoutParameters() + .buildForContext(new PublicKeyContext(Map.of("algorithm", "RSA"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // DSA generate -> private key + private static final IDetectionRule DSA_GENERATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.DSA") + .forMethods("generate") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PRIVATE_KEY_GENERATION)) + .withMethodParameter("int") // keylen + .shouldBeDetectedAs(new KeySizeFactory<>(Size.UnitType.BIT)) + .asChildOfParameterWithId(-1) + .buildForContext(new PrivateKeyContext(Map.of("algorithm", "DSA"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // DSA construct and import_key -> public or private key + private static final IDetectionRule DSA_CONSTRUCT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.DSA") + .forMethods("construct", "import_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyContext(Map.of("algorithm", "DSA"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // DsaKey public_key -> public key + private static final IDetectionRule DSA_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.DSA.DsaKey") + .forMethods("public_key") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PUBLIC_KEY_GENERATION)) + .withoutParameters() + .buildForContext(new PublicKeyContext(Map.of("algorithm", "DSA"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // ECC key generation + private static final IDetectionRule ECC_GENERATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.ECC") + .forMethods("generate") + // .shouldBeDetectedAs(new + // KeyActionFactory<>(KeyAction.Action.PRIVATE_KEY_GENERATION)) + .withMethodParameter("str") + .shouldBeDetectedAs(new CurveFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new PrivateKeyContext(Map.of("algorithm", "EC"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // ECC key construction + private static final IDetectionRule ECC_CONSTRUCT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.ECC") + .forMethods("construct") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withMethodParameter("str") + .shouldBeDetectedAs(new CurveFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new KeyContext(Map.of("algorithm", "EC"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // ECC import + private static final IDetectionRule ECC_IMPORT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.ECC") + .forMethods("import_key") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyContext(Map.of("algorithm", "EC_IMPORT"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // EccKey public_key -> public key + private static final IDetectionRule ECC_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.ECC.EccKey") + .forMethods("public_key") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PUBLIC_KEY_GENERATION)) + .withoutParameters() + .buildForContext(new PublicKeyContext(Map.of("algorithm", "ECC"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // ElGamal + private static final IDetectionRule ELGAMAL_GENERATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.ElGamal") + .forMethods("generate") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PRIVATE_KEY_GENERATION)) + .withAnyParameters() + .buildForContext(new PrivateKeyContext(Map.of("algorithm", "ElGamal"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // ElGamal + private static final IDetectionRule ELGAMAL_CONSTRUCT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.PublicKey.ElGamal") + .forMethods("construct") + .shouldBeDetectedAs(new KeyActionFactory<>(KeyAction.Action.GENERATION)) + .withAnyParameters() + .buildForContext(new KeyContext(Map.of("algorithm", "ElGamal"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + public static List> RSAPublicKeyRules() { + return List.of(RSA_CONSTRUCT, RSA_PUBLIC_KEY); + } + + @Nonnull + public static List> RSAPrivateKeyRules() { + return List.of(RSA_CONSTRUCT, RSA_GENERATE); + } + + @Nonnull + public static List> RSARules() { + return List.of(RSA_CONSTRUCT, RSA_GENERATE, RSA_PUBLIC_KEY); + } + + @Nonnull + public static List> DSAPublicKeyRules() { + return List.of(DSA_CONSTRUCT, DSA_PUBLIC_KEY); + } + + @Nonnull + public static List> DSAPrivateKeyRules() { + return List.of(DSA_CONSTRUCT, DSA_GENERATE); + } + + @Nonnull + public static List> DSARules() { + return List.of(DSA_CONSTRUCT, DSA_GENERATE, DSA_PUBLIC_KEY); + } + + @Nonnull + public static List> ECCPublicKeyRules() { + return List.of(ECC_CONSTRUCT, ECC_PUBLIC_KEY); + } + + @Nonnull + public static List> ECCPrivateKeyRules() { + return List.of(ECC_CONSTRUCT, ECC_GENERATE); + } + + @Nonnull + public static List> ECCRules() { + return List.of(ECC_CONSTRUCT, ECC_GENERATE, ECC_PUBLIC_KEY); + } + + @Nonnull + public static List> rules() { + return List.of( + RSA_CONSTRUCT, + RSA_GENERATE, + DSA_CONSTRUCT, + DSA_GENERATE, + ECC_CONSTRUCT, + ECC_GENERATE, + ECC_IMPORT, + ELGAMAL_CONSTRUCT, + ELGAMAL_GENERATE); + // return Stream.of(RSA_rules(), DSA_rules(), ECC_rules(), List.of(ELGAMAL_KEY_GEN)) + // .flatMap(Collection::stream) + // .collect(Collectors.toList()); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java new file mode 100644 index 000000000..bcd719cc0 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java @@ -0,0 +1,215 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static com.ibm.engine.detection.MethodMatcher.ANY; + +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.model.factory.AlgorithmFactory; +import com.ibm.engine.model.factory.SignatureActionFactory; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoSignature { + + private PythonCryptoSignature() { + // private + } + + private static final IDetectionRule SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("sign") + .shouldBeDetectedAs(new SignatureActionFactory<>(SignatureAction.Action.SIGN)) + .withMethodParameter("Crypto.Hash.*") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoHash.rules()) + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("verify") + .shouldBeDetectedAs(new SignatureActionFactory<>(SignatureAction.Action.VERIFY)) + .withMethodParameter("Crypto.Hash.*") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoHash.rules()) + .withMethodParameter(ANY) // the signature to be verified + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // PSS signature scheme - sign and verify methods (called on the result of .new()) + private static final IDetectionRule PKCS1V15 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.pkcs1_15") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withMethodParameter("Crypto.PublicKey.RSA") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoPublicKey.RSARules()) + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SIGN, VERIFY)); + + // PSS signature scheme - sign and verify methods (called on the result of .new()) + private static final IDetectionRule PSS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.pss") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS")) + .withMethodParameter("Crypto.PublicKey.RSA") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoPublicKey.RSARules()) + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SIGN, VERIFY)); + + // private static final IDetectionRule DSS_SIGN = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectTypes("Crypto.Signature.DSS.DssSigScheme") + // .forMethods("sign") + // .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + // .withMethodParameter("Crypto.Hash.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .asChildOfParameterWithId(-1) + // .addDependingDetectionRules(PythonCryptoHash.rules()) + // .buildForContext(new SignatureContext(Map.of("kind", "SIGN", "algorithm", + // "EC"))) + // .inBundle(() -> "PyCrypto") + // .withoutDependingDetectionRules(); + + // private static final IDetectionRule DSS_VERIFY = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectTypes("Crypto.Signature.DSS.DssSigScheme") + // .forMethods("verify") + // .shouldBeDetectedAs(new + // SignatureActionFactory<>(SignatureAction.Action.VERIFY)) + // .withMethodParameter("Crypto.Hash.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .asChildOfParameterWithId(-1) + // .addDependingDetectionRules(PythonCryptoHash.rules()) + // .withMethodParameter(ANY) // the signature to be verified + // .buildForContext(new SignatureContext(Map.of("algorithm", "EC"))) + // .inBundle(() -> "PyCrypto") + // .withoutDependingDetectionRules(); + + // DSS signature scheme - sign and verify methods (called on the result of .new()) + private static final IDetectionRule DSS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.DSS") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("DSS")) + .withMethodParameter("Crypto.PublicKey.DSA") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoPublicKey.DSARules()) + .withMethodParameter(ANY) // the mode parameter + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SIGN, VERIFY)); + + // DSS signature scheme - sign and verify methods (called on the result of .new()) + private static final IDetectionRule ECDSA = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.DSS") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA")) + .withMethodParameter("Crypto.PublicKey.ECC") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoPublicKey.ECCRules()) + .withMethodParameter(ANY) // the mode parameter + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SIGN, VERIFY)); + + // private static final IDetectionRule EDDSA_SIGN = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectTypes("Crypto.Signature.eddsa.EdDSASigScheme") + // .forMethods("sign") + // .shouldBeDetectedAs(new + // SignatureActionFactory<>(SignatureAction.Action.SIGN)) + // .withMethodParameter("Crypto.Hash.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .asChildOfParameterWithId(-1) + // .addDependingDetectionRules(PythonCryptoHash.rules()) + // .buildForContext(new SignatureContext(Map.of("algorithm", "EC"))) + // .inBundle(() -> "PyCrypto") + // .withoutDependingDetectionRules(); + + // private static final IDetectionRule EDDSA_VERIFY = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectTypes("Crypto.Signature.eddsa.EdDSASigScheme") + // .forMethods("verify") + // .shouldBeDetectedAs(new + // SignatureActionFactory<>(SignatureAction.Action.VERIFY)) + // .withMethodParameter("Crypto.Hash.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .asChildOfParameterWithId(-1) + // .addDependingDetectionRules(PythonCryptoHash.rules()) + // .withMethodParameter(ANY) // the signature to be verified + // .buildForContext(new SignatureContext(Map.of("algorithm", "EC"))) + // .inBundle(() -> "PyCrypto") + // .withoutDependingDetectionRules(); + + // EdDSA signature scheme - sign and verify methods (called on the result of .new()) + private static final IDetectionRule EDDSA = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.eddsa") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("EDDSA")) + .withMethodParameter("Crypto.PublicKey.ECC") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .addDependingDetectionRules(PythonCryptoPublicKey.ECCRules()) + .withMethodParameter(ANY) // the mode parameter + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SIGN, VERIFY)); + + @Nonnull + public static List> rules() { + return List.of(PKCS1V15, PSS, DSS, ECDSA, EDDSA); + } +} diff --git a/python/src/main/java/com/ibm/plugin/translation/reorganizer/PythonReorganizerRules.java b/python/src/main/java/com/ibm/plugin/translation/reorganizer/PythonReorganizerRules.java index 6bb880f0e..ca3155eb1 100644 --- a/python/src/main/java/com/ibm/plugin/translation/reorganizer/PythonReorganizerRules.java +++ b/python/src/main/java/com/ibm/plugin/translation/reorganizer/PythonReorganizerRules.java @@ -21,9 +21,11 @@ import com.ibm.mapper.model.BlockCipher; import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.ProbabilisticSignatureScheme; import com.ibm.mapper.model.PublicKeyEncryption; import com.ibm.mapper.model.Signature; import com.ibm.mapper.model.functionality.Sign; +import com.ibm.mapper.model.functionality.Verify; import com.ibm.mapper.reorganizer.IReorganizerRule; import com.ibm.mapper.reorganizer.rules.KeyAgreementReorganizer; import com.ibm.mapper.reorganizer.rules.KeyDerivationReorganizer; @@ -42,6 +44,14 @@ private PythonReorganizerRules() { @Nonnull public static List rules() { return Stream.of( + SignatureReorganizer.moveNodesFromUnderFunctionalityUnderParent( + Verify.class, ProbabilisticSignatureScheme.class), + SignatureReorganizer.moveNodesFromUnderFunctionalityUnderParent( + Verify.class, Signature.class), + SignatureReorganizer.moveNodesFromUnderFunctionalityUnderParent( + Sign.class, ProbabilisticSignatureScheme.class), + SignatureReorganizer.moveNodesFromUnderFunctionalityUnderParent( + Sign.class, Signature.class), SignatureReorganizer.moveNodesFromUnderFunctionalityUnderNode( Sign.class, PublicKeyEncryption.class), SignatureReorganizer.moveNodesFromUnderFunctionalityUnderNode( diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java index 4a22bb4a2..a3e41e7a9 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java @@ -38,11 +38,11 @@ import com.ibm.plugin.translation.translator.contexts.PycaCipherContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaDigestContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaKeyAgreementContextTranslator; +import com.ibm.plugin.translation.translator.contexts.PycaKeyContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaKeyDerivationContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaMacContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaPrivateKeyContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaPublicKeyContextTranslator; -import com.ibm.plugin.translation.translator.contexts.PycaSecretContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaSecretKeyContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaSignatureContextTranslator; import java.util.List; @@ -86,11 +86,6 @@ public Optional translate( new PycaKeyDerivationContextTranslator(); return pycaKeyDerivationContextTranslator.translate( bundleIdentifier, value, detectionValueContext, detectionLocation); - } else if (detectionValueContext.is(KeyContext.class)) { - final PycaSecretContextTranslator pycaSecretContextTranslator = - new PycaSecretContextTranslator(); - return pycaSecretContextTranslator.translate( - bundleIdentifier, value, detectionValueContext, detectionLocation); } else if (detectionValueContext.is(PrivateKeyContext.class)) { final PycaPrivateKeyContextTranslator pycaPrivateKeyContextTranslator = new PycaPrivateKeyContextTranslator(); @@ -106,6 +101,11 @@ public Optional translate( new PycaPublicKeyContextTranslator(); return pycaPublicKeyContextTranslator.translate( bundleIdentifier, value, detectionValueContext, detectionLocation); + } else if (detectionValueContext.is(KeyContext.class)) { + final PycaKeyContextTranslator pycaKeyContextTranslator = + new PycaKeyContextTranslator(); + return pycaKeyContextTranslator.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); } else if (detectionValueContext.is(DigestContext.class)) { final PycaDigestContextTranslator pycaDigestContextTranslator = new PycaDigestContextTranslator(); diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java index eec44d2aa..97830c76f 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java @@ -33,7 +33,9 @@ import com.ibm.mapper.model.INode; import com.ibm.mapper.model.KeyLength; import com.ibm.mapper.model.KeyWrap; +import com.ibm.mapper.model.PublicKeyEncryption; import com.ibm.mapper.model.algorithms.AES; +import com.ibm.mapper.model.algorithms.RSA; import com.ibm.mapper.model.functionality.Decrypt; import com.ibm.mapper.model.functionality.Encapsulate; import com.ibm.mapper.model.functionality.Encrypt; @@ -41,15 +43,19 @@ import com.ibm.mapper.model.mode.CCM; import com.ibm.mapper.model.mode.CFB; import com.ibm.mapper.model.mode.CTR; +import com.ibm.mapper.model.mode.EAX; import com.ibm.mapper.model.mode.ECB; import com.ibm.mapper.model.mode.GCM; import com.ibm.mapper.model.mode.GCMSIV; +import com.ibm.mapper.model.mode.KW; +import com.ibm.mapper.model.mode.KWP; import com.ibm.mapper.model.mode.OCB; import com.ibm.mapper.model.mode.OFB; import com.ibm.mapper.model.mode.SIV; import com.ibm.mapper.model.mode.XTS; import com.ibm.mapper.model.padding.ANSIX923; import com.ibm.mapper.model.padding.OAEP; +import com.ibm.mapper.model.padding.PKCS1; import com.ibm.mapper.model.padding.PKCS7; import com.ibm.mapper.utils.DetectionLocation; import java.util.Optional; @@ -85,25 +91,47 @@ public final class PycaCipherContextTranslator implements IContextTranslation i); } else if (value instanceof ValueAction - && detectionContext instanceof DetectionContext context - && context.get("kind").map(k -> k.equals("padding")).orElse(false) // padding case - ) { - return switch (value.asString().toUpperCase().trim()) { - case "PKCS7" -> Optional.of(new PKCS7(detectionLocation)); - case "ANSIX923" -> Optional.of(new ANSIX923(detectionLocation)); - case "OAEP" -> Optional.of(new OAEP(detectionLocation)); - default -> Optional.empty(); + && detectionContext instanceof DetectionContext context) { + if (context.get("kind").map(k -> k.equals("padding")).orElse(false)) { // padding case + return switch (value.asString().toUpperCase().trim()) { + case "PKCS7" -> Optional.of(new PKCS7(detectionLocation)); + case "ANSIX923" -> Optional.of(new ANSIX923(detectionLocation)); + case "OAEP" -> Optional.of(new OAEP(detectionLocation)); + default -> Optional.empty(); + }; + } + + // Handle ValueAction with algorithm name (e.g., "AES", "DES", "DES3") + // Get the algorithm name from the ValueAction + String algorithmName = value.asString(); + return switch (algorithmName) { + case "PKCS1_OAEP" -> { + RSA rsaOaep = new RSA(PublicKeyEncryption.class, detectionLocation); + rsaOaep.put(new OAEP(detectionLocation)); + yield Optional.of((INode) rsaOaep); + } + case "PKCS1_v1_5" -> { + RSA rsaPkcs1 = new RSA(PublicKeyEncryption.class, detectionLocation); + rsaPkcs1.put(new PKCS1(detectionLocation)); + yield Optional.of((INode) rsaPkcs1); + } + default -> pycaCipherMapper.parse(algorithmName, detectionLocation).map(i -> i); }; } else if (value instanceof Mode mode) { return switch (mode.asString().toUpperCase().trim()) { - case "CBC" -> Optional.of(new CBC(detectionLocation)); - case "CTR" -> Optional.of(new CTR(detectionLocation)); - case "OFB" -> Optional.of(new OFB(detectionLocation)); - case "CFB" -> Optional.of(new CFB(detectionLocation)); + case "CBC", "MODE_CBC" -> Optional.of(new CBC(detectionLocation)); + case "CTR", "MODE_CTR" -> Optional.of(new CTR(detectionLocation)); + case "OFB", "MODE_OFB" -> Optional.of(new OFB(detectionLocation)); + case "CFB", "MODE_CFB" -> Optional.of(new CFB(detectionLocation)); case "CFB8" -> Optional.of(new CFB(8, detectionLocation)); - case "GCM" -> Optional.of(new GCM(detectionLocation)); + case "GCM", "MODE_GCM" -> Optional.of(new GCM(detectionLocation)); case "XTS" -> Optional.of(new XTS(detectionLocation)); - case "ECB" -> Optional.of(new ECB(detectionLocation)); + case "ECB", "MODE_ECB" -> Optional.of(new ECB(detectionLocation)); + case "MODE_EAX" -> Optional.of(new EAX(detectionLocation)); + case "CCM", "MODE_CCM" -> Optional.of(new CCM(detectionLocation)); + case "MODE_SIV" -> Optional.of(new SIV(detectionLocation)); + case "MODE_KW" -> Optional.of(new KW(detectionLocation)); + case "MODE_KWP" -> Optional.of(new KWP(detectionLocation)); default -> Optional.empty(); }; } else if (value instanceof CipherAction cipherAction diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaDigestContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaDigestContextTranslator.java index face8bc21..6333c5cc8 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaDigestContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaDigestContextTranslator.java @@ -19,6 +19,7 @@ */ package com.ibm.plugin.translation.translator.contexts; +import com.ibm.engine.model.Algorithm; import com.ibm.engine.model.IValue; import com.ibm.engine.model.ValueAction; import com.ibm.engine.model.context.IDetectionContext; @@ -41,7 +42,7 @@ public final class PycaDigestContextTranslator implements IContextTranslation value, @Nonnull IDetectionContext detectionContext, @Nonnull DetectionLocation detectionLocation) { - if (value instanceof ValueAction || value instanceof com.ibm.engine.model.Algorithm) { + if (value instanceof ValueAction || value instanceof Algorithm) { final PycaDigestMapper pycaDigestMapper = new PycaDigestMapper(); return pycaDigestMapper .parse(value.asString(), detectionLocation) diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyAgreementContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyAgreementContextTranslator.java index 89b68213b..4362d2370 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyAgreementContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyAgreementContextTranslator.java @@ -22,6 +22,7 @@ import com.ibm.engine.model.Algorithm; import com.ibm.engine.model.IValue; import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.ValueAction; import com.ibm.engine.model.context.DetectionContext; import com.ibm.engine.model.context.IDetectionContext; import com.ibm.engine.rule.IBundle; @@ -46,11 +47,11 @@ public class PycaKeyAgreementContextTranslator implements IContextTranslation value, @Nonnull IDetectionContext detectionContext, @Nonnull DetectionLocation detectionLocation) { - if (value instanceof Algorithm algorithm) { - return Optional.of(algorithm) + if (value instanceof ValueAction || value instanceof Algorithm) { + return Optional.of(value.asString().toUpperCase().trim()) .map( algo -> - switch (algo.asString().toUpperCase().trim()) { + switch (algo) { case "ECDH" -> new ECDH(detectionLocation); case "EC" -> new EllipticCurveAlgorithm( diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyContextTranslator.java new file mode 100644 index 000000000..43e24c78c --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyContextTranslator.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.Curve; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.DetectionContext; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.mapper.pyca.PycaCurveMapper; +import com.ibm.mapper.model.EllipticCurveAlgorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.algorithms.DSA; +import com.ibm.mapper.model.algorithms.ElGamal; +import com.ibm.mapper.model.algorithms.Fernet; +import com.ibm.mapper.model.algorithms.RSA; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.utils.DetectionLocation; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +public final class PycaKeyContextTranslator implements IContextTranslation { + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + if (value instanceof KeyAction + && detectionContext instanceof DetectionContext context) { + // action is always "generate" + return context.get("algorithm") + .map( + str -> + switch (str.toUpperCase().trim()) { + case "RSA" -> new RSA(detectionLocation); + case "DSA" -> new DSA(detectionLocation); + case "EC_IMPORT" -> + new EllipticCurveAlgorithm(detectionLocation); + case "ELGAMAL" -> new ElGamal(detectionLocation); + case "FERNET" -> new Fernet(detectionLocation); + default -> null; + }) + .map( + algo -> { + final Key key = new Key(algo); + key.put(new KeyGeneration(detectionLocation)); + return key; + }); + } else if (value instanceof Curve curve + && detectionContext instanceof DetectionContext context + && context.get("algorithm").map(a -> a.equalsIgnoreCase("EC")).orElse(false)) { + final PycaCurveMapper mapper = new PycaCurveMapper(); + return mapper.parse(curve.asString(), detectionLocation) + .map( + ec -> { + Key key = new Key((PublicKeyEncryption) ec); + key.put(new KeyGeneration(detectionLocation)); + // currently only GENERATE is + // used as key action is this + // context + return key; + }); + } + return Optional.empty(); + } +} diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyDerivationContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyDerivationContextTranslator.java index 72ed5115d..1ddc88217 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyDerivationContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaKeyDerivationContextTranslator.java @@ -21,8 +21,10 @@ import com.ibm.engine.model.Algorithm; import com.ibm.engine.model.IValue; +import com.ibm.engine.model.IterationCount; import com.ibm.engine.model.KeySize; import com.ibm.engine.model.Mode; +import com.ibm.engine.model.SaltSize; import com.ibm.engine.model.ValueAction; import com.ibm.engine.model.context.DetectionContext; import com.ibm.engine.model.context.IDetectionContext; @@ -33,11 +35,14 @@ import com.ibm.mapper.model.Cipher; import com.ibm.mapper.model.INode; import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.NumberOfIterations; +import com.ibm.mapper.model.SaltLength; import com.ibm.mapper.model.algorithms.ANSIX963; import com.ibm.mapper.model.algorithms.CMAC; import com.ibm.mapper.model.algorithms.ConcatenationKDF; import com.ibm.mapper.model.algorithms.HKDF; import com.ibm.mapper.model.algorithms.HMAC; +import com.ibm.mapper.model.algorithms.PBKDF1; import com.ibm.mapper.model.algorithms.PBKDF2; import com.ibm.mapper.model.algorithms.Scrypt; import com.ibm.mapper.model.functionality.KeyDerivation; @@ -101,6 +106,17 @@ public class PycaKeyDerivationContextTranslator implements IContextTranslation { + final PycaDigestMapper digestMapper = new PycaDigestMapper(); + yield digestMapper + .parse(algorithm.asString(), detectionLocation) + .map( + kdf -> { + final PBKDF1 pbkdf1 = new PBKDF1(kdf); + pbkdf1.put(new KeyDerivation(detectionLocation)); + return pbkdf1; + }); + } case "pbkdf2" -> { final PycaDigestMapper digestMapper = new PycaDigestMapper(); yield digestMapper @@ -112,6 +128,14 @@ public class PycaKeyDerivationContextTranslator implements IContextTranslation { + // ValueAction already creates the root KDF node for these rules; + // the Algorithm child should contribute only the digest. + final PycaDigestMapper digestMapper = new PycaDigestMapper(); + yield digestMapper + .parse(algorithm.asString(), detectionLocation) + .map(digest -> (INode) digest); + } case "concatkdf" -> { final PycaDigestMapper digestMapper = new PycaDigestMapper(); yield digestMapper @@ -146,11 +170,19 @@ public class PycaKeyDerivationContextTranslator implements IContextTranslation keySize) { return Optional.of(new KeyLength(keySize.getValue(), detectionLocation)); + } else if (value instanceof IterationCount iterationCount) { + return Optional.of( + new NumberOfIterations(iterationCount.getValue(), detectionLocation)); + } else if (value instanceof SaltSize saltSize) { + return Optional.of(new SaltLength(saltSize.getValue(), detectionLocation)); } else if (value instanceof ValueAction action) { return Optional.of(action.asString().toUpperCase().trim()) .map( str -> - switch (action.asString().toUpperCase().trim()) { + switch (str) { + case "PBKDF1" -> new PBKDF1(detectionLocation); + case "PBKDF2" -> new PBKDF2(detectionLocation); + case "HKDF" -> new HKDF(detectionLocation); case "SCRYPT" -> new Scrypt(detectionLocation); default -> null; }) diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaMacContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaMacContextTranslator.java index 8f9e14618..47940b9aa 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaMacContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaMacContextTranslator.java @@ -19,6 +19,7 @@ */ package com.ibm.plugin.translation.translator.contexts; +import com.ibm.engine.model.Algorithm; import com.ibm.engine.model.IValue; import com.ibm.engine.model.ValueAction; import com.ibm.engine.model.context.DetectionContext; @@ -47,7 +48,7 @@ public final class PycaMacContextTranslator implements IContextTranslation @Nonnull IDetectionContext detectionContext, @Nonnull DetectionLocation detectionLocation) { - if (value instanceof com.ibm.engine.model.Algorithm algorithm + if (value instanceof Algorithm algorithm && detectionContext instanceof DetectionContext context) { // hash algorithm Optional possibleKind = context.get("kind"); diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPrivateKeyContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPrivateKeyContextTranslator.java index b82629bd7..8a3478df0 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPrivateKeyContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPrivateKeyContextTranslator.java @@ -27,6 +27,7 @@ import com.ibm.engine.model.context.IDetectionContext; import com.ibm.engine.rule.IBundle; import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.mapper.pyca.PycaCurveMapper; import com.ibm.mapper.model.EllipticCurveAlgorithm; import com.ibm.mapper.model.INode; import com.ibm.mapper.model.KeyLength; @@ -36,26 +37,8 @@ import com.ibm.mapper.model.algorithms.DSA; import com.ibm.mapper.model.algorithms.Ed25519; import com.ibm.mapper.model.algorithms.Ed448; +import com.ibm.mapper.model.algorithms.ElGamal; import com.ibm.mapper.model.algorithms.RSA; -import com.ibm.mapper.model.curves.Brainpoolp256r1; -import com.ibm.mapper.model.curves.Brainpoolp384r1; -import com.ibm.mapper.model.curves.Brainpoolp512r1; -import com.ibm.mapper.model.curves.Secp192r1; -import com.ibm.mapper.model.curves.Secp224r1; -import com.ibm.mapper.model.curves.Secp256k1; -import com.ibm.mapper.model.curves.Secp256r1; -import com.ibm.mapper.model.curves.Secp384r1; -import com.ibm.mapper.model.curves.Secp521r1; -import com.ibm.mapper.model.curves.Sect163k1; -import com.ibm.mapper.model.curves.Sect163r2; -import com.ibm.mapper.model.curves.Sect233k1; -import com.ibm.mapper.model.curves.Sect233r1; -import com.ibm.mapper.model.curves.Sect283k1; -import com.ibm.mapper.model.curves.Sect283r1; -import com.ibm.mapper.model.curves.Sect409k1; -import com.ibm.mapper.model.curves.Sect409r1; -import com.ibm.mapper.model.curves.Sect571k1; -import com.ibm.mapper.model.curves.Sect571r1; import com.ibm.mapper.model.functionality.KeyGeneration; import com.ibm.mapper.utils.DetectionLocation; import java.util.Optional; @@ -84,41 +67,13 @@ public final class PycaPrivateKeyContextTranslator implements IContextTranslatio } else if (value instanceof Curve curve && detectionContext instanceof DetectionContext context && context.get("algorithm").map(a -> a.equalsIgnoreCase("EC")).orElse(false)) { - return Optional.of(curve.asString()) - .map( - str -> - switch (str.toUpperCase().trim()) { - case "SECP256R1" -> new Secp256r1(detectionLocation); - case "SECP384R1" -> new Secp384r1(detectionLocation); - case "SECP521R1" -> new Secp521r1(detectionLocation); - case "SECP224R1" -> new Secp224r1(detectionLocation); - case "SECP192R1" -> new Secp192r1(detectionLocation); - case "SECP256K1" -> new Secp256k1(detectionLocation); - case "BRAINPOOLP256R1" -> - new Brainpoolp256r1(detectionLocation); - case "BRAINPOOLP384R1" -> - new Brainpoolp384r1(detectionLocation); - case "BRAINPOOLP512R1" -> - new Brainpoolp512r1(detectionLocation); - case "SECT571K1" -> new Sect571k1(detectionLocation); - case "SECT409K1" -> new Sect409k1(detectionLocation); - case "SECT283K1" -> new Sect283k1(detectionLocation); - case "SECT233K1" -> new Sect233k1(detectionLocation); - case "SECT163K1" -> new Sect163k1(detectionLocation); - case "SECT571R1" -> new Sect571r1(detectionLocation); - case "SECT409R1" -> new Sect409r1(detectionLocation); - case "SECT283R1" -> new Sect283r1(detectionLocation); - case "SECT233R1" -> new Sect233r1(detectionLocation); - case "SECT163R2" -> new Sect163r2(detectionLocation); - default -> null; - }) - .map(EllipticCurveAlgorithm::new) + final PycaCurveMapper mapper = new PycaCurveMapper(); + return mapper.parse(curve.asString(), detectionLocation) .map( ec -> { PrivateKey privateKey = new PrivateKey((PublicKeyEncryption) ec); - privateKey.put( - new KeyGeneration( - detectionLocation)); // currently only GENERATE is + privateKey.put(new KeyGeneration(detectionLocation)); + // currently only GENERATE is // used as key action is this // context return privateKey; @@ -141,14 +96,14 @@ public final class PycaPrivateKeyContextTranslator implements IContextTranslatio case "EC" -> new EllipticCurveAlgorithm(detectionLocation); case "ED25519" -> new Ed25519(detectionLocation); case "ED448" -> new Ed448(detectionLocation); + case "ELGAMAL" -> new ElGamal(detectionLocation); default -> null; }) .map( algorithm -> { PrivateKey privateKey = new PrivateKey(algorithm); - privateKey.put( - new KeyGeneration( - detectionLocation)); // currently only GENERATE is + privateKey.put(new KeyGeneration(detectionLocation)); + // currently only GENERATE is // used as key action is this // context return privateKey; diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPublicKeyContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPublicKeyContextTranslator.java index b0f14a52e..445e9efd5 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPublicKeyContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaPublicKeyContextTranslator.java @@ -19,16 +19,20 @@ */ package com.ibm.plugin.translation.translator.contexts; +import com.ibm.engine.model.Curve; import com.ibm.engine.model.IValue; import com.ibm.engine.model.KeyAction; import com.ibm.engine.model.context.DetectionContext; import com.ibm.engine.model.context.IDetectionContext; import com.ibm.engine.rule.IBundle; import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.mapper.pyca.PycaCurveMapper; import com.ibm.mapper.model.INode; import com.ibm.mapper.model.PublicKey; +import com.ibm.mapper.model.PublicKeyEncryption; import com.ibm.mapper.model.algorithms.DH; import com.ibm.mapper.model.algorithms.DSA; +import com.ibm.mapper.model.algorithms.ElGamal; import com.ibm.mapper.model.algorithms.RSA; import com.ibm.mapper.model.functionality.KeyGeneration; import com.ibm.mapper.utils.DetectionLocation; @@ -54,6 +58,7 @@ public final class PycaPublicKeyContextTranslator implements IContextTranslation case "DH" -> new DH(detectionLocation); case "RSA" -> new RSA(detectionLocation); case "DSA" -> new DSA(detectionLocation); + case "ELGAMAL" -> new ElGamal(detectionLocation); default -> null; }) .map( @@ -66,6 +71,18 @@ public final class PycaPublicKeyContextTranslator implements IContextTranslation // context return publicKey; }); + } else if (value instanceof Curve) { + final PycaCurveMapper mapper = new PycaCurveMapper(); + return mapper.parse(value.asString(), detectionLocation) + .map( + algo -> { + PublicKey publicKey = new PublicKey((PublicKeyEncryption) algo); + // currently only GENERATE is + // used as key action is this + // context + publicKey.put(new KeyGeneration(detectionLocation)); + return publicKey; + }); } return Optional.empty(); } diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaSignatureContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaSignatureContextTranslator.java index 363c68378..e3ca43789 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaSignatureContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaSignatureContextTranslator.java @@ -30,7 +30,9 @@ import com.ibm.mapper.model.INode; import com.ibm.mapper.model.ProbabilisticSignatureScheme; import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.algorithms.DSS; import com.ibm.mapper.model.algorithms.ECDSA; +import com.ibm.mapper.model.algorithms.EdDSA; import com.ibm.mapper.model.algorithms.MGF1; import com.ibm.mapper.model.algorithms.RSA; import com.ibm.mapper.model.algorithms.RSAssaPSS; @@ -82,6 +84,10 @@ public final class PycaSignatureContextTranslator implements IContextTranslation }; } else { return switch (value.asString().toUpperCase().trim()) { + case "RSA" -> Optional.of(new RSA(Signature.class, detectionLocation)); + case "DSS" -> Optional.of(new DSS(detectionLocation)); + case "ECDSA" -> Optional.of(new ECDSA(detectionLocation)); + case "EDDSA" -> Optional.of(new EdDSA(detectionLocation)); case "MGF1" -> Optional.of(new MGF1(detectionLocation)); case "RSA-PSS" -> Optional.of(new RSAssaPSS(detectionLocation)); default -> Optional.empty(); diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py new file mode 100644 index 000000000..e3b1f2483 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py @@ -0,0 +1,4 @@ +from Crypto.Cipher import DES3 + +key_3des = b"0123456789abcdef01234567" +cipher_3des = DES3.new(key_3des, DES3.MODE_CBC) # Noncompliant {{(BlockCipher) 3DES}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py new file mode 100644 index 000000000..5135bac9e --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py @@ -0,0 +1,5 @@ +from Crypto.Cipher import AES + +key_aes = b"0123456789abcdef" +cipher_aes = AES.new(key_aes, AES.MODE_CBC) # Noncompliant {{(BlockCipher) AES-CBC}} +cipher_aes.encrypt(b'some message') diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py new file mode 100644 index 000000000..876f81f8a --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py @@ -0,0 +1,4 @@ +from Crypto.Cipher import Blowfish + +key_blowfish = b"0123456789abcdef" +cipher_blowfish = Blowfish.new(key_blowfish, Blowfish.MODE_CBC) # Noncompliant {{(BlockCipher) Blowfish}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py new file mode 100644 index 000000000..60f3b6aaa --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py @@ -0,0 +1,4 @@ +from Crypto.Cipher import CAST + +key_cast = b"0123456789abcdef" +cipher_cast = CAST.new(key_cast, CAST.MODE_CBC) # Noncompliant {{(BlockCipher) CAST-128}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py new file mode 100644 index 000000000..34261dd56 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py @@ -0,0 +1,7 @@ +from Crypto.Cipher import ChaCha20_Poly1305 + +key_chacha20_poly1305 = b"0123456789abcdef0123456789abcdef" +nonce_chacha20_poly1305 = b"01234567" +cipher_chacha20_poly1305 = ChaCha20_Poly1305.new( # Noncompliant {{(AuthenticatedEncryption) ChaCha20Poly1305}} + key=key_chacha20_poly1305, + nonce=nonce_chacha20_poly1305) diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py new file mode 100644 index 000000000..be90c8ffb --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py @@ -0,0 +1,5 @@ +from Crypto.Cipher import ChaCha20 + +key_chacha20 = b"0123456789abcdef0123456789abcdef" +nonce_chacha20 = b"01234567" +cipher_chacha20 = ChaCha20.new(key=key_chacha20, nonce=nonce_chacha20) # Noncompliant {{(StreamCipher) ChaCha20}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py new file mode 100644 index 000000000..fd9402e6c --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py @@ -0,0 +1,5 @@ +from Crypto.Cipher import DES + +key_des = b"01234567" +cipher_des = DES.new(key_des, DES.MODE_ECB) # Noncompliant {{(BlockCipher) DES56-ECB}} +cipher_des.decrypt(b'some blob') diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py new file mode 100644 index 000000000..79229a17b --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py @@ -0,0 +1,6 @@ +from Crypto.Cipher import PKCS1_OAEP +from Crypto.PublicKey import RSA +from Crypto.Hash import SHA256 + +key = RSA.importKey(open('public.pem').read()) +cipher = PKCS1_OAEP.new(key, SHA256) # Noncompliant {{(PublicKeyEncryption) RSA-OAEP}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py new file mode 100644 index 000000000..adee56079 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py @@ -0,0 +1,5 @@ +from Crypto.Cipher import PKCS1_v1_5 +from Crypto.PublicKey import RSA + +key = RSA.importKey(open('public.pem').read()) +cipher = PKCS1_v1_5.new(key) # Noncompliant {{(PublicKeyEncryption) RSA}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py new file mode 100644 index 000000000..70bc03196 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py @@ -0,0 +1,4 @@ +from Crypto.Cipher import ARC2 + +key_arc2 = b"0123456789abcdef" +cipher_arc2 = ARC2.new(key_arc2, ARC2.MODE_CBC) # Noncompliant {{(BlockCipher) RC2}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py new file mode 100644 index 000000000..c1d08fd5f --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py @@ -0,0 +1,4 @@ +from Crypto.Cipher import ARC4 + +key_arc4 = b"0123456789abcdef" +cipher_arc4 = ARC4.new(key_arc4) # Noncompliant {{(StreamCipher) RC4}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py new file mode 100644 index 000000000..13d498ade --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py @@ -0,0 +1,5 @@ +from Crypto.Cipher import Salsa20 + +key_salsa20 = b"0123456789abcdef0123456789abcdef" +nonce_salsa20 = b"01234567" +cipher_salsa20 = Salsa20.new(key=key_salsa20, nonce=nonce_salsa20) # Noncompliant {{(StreamCipher) Salsa20}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py new file mode 100644 index 000000000..8dc9d1b53 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py @@ -0,0 +1,7 @@ +from Crypto.PublicKey import ECC +from Crypto.Signature import eddsa + +message = b'some message' +key = ECC.import_key(open("private_ed25519.pem").read()) # Noncompliant {{(PublicKey) EC}} +signer = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) ECDSA}} +signature = signer.sign(message) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py new file mode 100644 index 000000000..4d7093f36 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py @@ -0,0 +1,13 @@ +from Crypto.PublicKey import ECC +from Crypto.Signature import eddsa + +message = b'some message' +key = ECC.import_key(open("public_ed25519.pem").read()) # Noncompliant {{(PublicKey) EC}} +verifier = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) ECDSA}} +signature = b'some signature' + +try: + verifier.verify(h, signature) + print("The message is authentic") +except ValueError: + print("The message is not authentic") \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py new file mode 100644 index 000000000..190bcdf7f --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import BLAKE2b + +hash_blake2b = BLAKE2b.new() # Noncompliant {{(MessageDigest) BLAKE2b}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py new file mode 100644 index 000000000..5b5928fea --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import BLAKE2s + +hash_blake2s = BLAKE2s.new() # Noncompliant {{(MessageDigest) BLAKE2s}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py new file mode 100644 index 000000000..8c1894f04 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import MD2 + +hash_md2 = MD2.new() # Noncompliant {{(MessageDigest) MD2}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py new file mode 100644 index 000000000..4d830526b --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import MD5 + +hash_md5 = MD5.new() # Noncompliant {{(MessageDigest) MD5}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py new file mode 100644 index 000000000..8c5d05634 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import RIPEMD160 + +hash_ripemd160 = RIPEMD160.new() # Noncompliant {{(MessageDigest) RIPEMD-160}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py new file mode 100644 index 000000000..218735199 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA1 + +hash_sha1 = SHA1.new() # Noncompliant {{(MessageDigest) SHA1}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py new file mode 100644 index 000000000..fdbf255f7 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA224 + +hash_sha224 = SHA224.new() # Noncompliant {{(MessageDigest) SHA224}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py new file mode 100644 index 000000000..00ad62b9e --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA256 + +hash_sha256 = SHA256.new() # Noncompliant {{(MessageDigest) SHA256}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py new file mode 100644 index 000000000..98f1e69dd --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA384 + +hash_sha384 = SHA384.new() # Noncompliant {{(MessageDigest) SHA384}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py new file mode 100644 index 000000000..c539ca916 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA3_224 + +hash_sha3_224 = SHA3_224.new() # Noncompliant {{(MessageDigest) SHA3-224}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py new file mode 100644 index 000000000..c6975d0a1 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA3_256 + +hash_sha3_256 = SHA3_256.new() # Noncompliant {{(MessageDigest) SHA3-256}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py new file mode 100644 index 000000000..03b29d382 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA3_384 + +hash_sha3_384 = SHA3_384.new() # Noncompliant {{(MessageDigest) SHA3-384}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py new file mode 100644 index 000000000..338c5b305 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA3_512 + +hash_sha3_512 = SHA3_512.new() # Noncompliant {{(MessageDigest) SHA3-512}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py new file mode 100644 index 000000000..72a71a274 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import SHA512 + +hash_sha512 = SHA512.new() # Noncompliant {{(MessageDigest) SHA512}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py new file mode 100644 index 000000000..cfdb54d28 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import TupleHash128 + +hash_t128 = TupleHash128.new() # Noncompliant {{(ExtendableOutputFunction) TupleHash}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py new file mode 100644 index 000000000..dc8db14df --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py @@ -0,0 +1,3 @@ +from Crypto.Hash import cSHAKE256 + +hash_t128 = cSHAKE256.new() # Noncompliant {{(ExtendableOutputFunction) cSHAKE256}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py new file mode 100644 index 000000000..f99740baf --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py @@ -0,0 +1,6 @@ +from Crypto.Protocol.KDF import bcrypt + +def test_bcrypt(): + password = b"password" + salt = b"salt1234567890ab" + key = bcrypt(password, cost=10, salt=salt) # detected but not mapped diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py new file mode 100644 index 000000000..53bc9bc4f --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py @@ -0,0 +1,7 @@ +from Crypto.Protocol.KDF import HKDF +from Crypto.Hash import SHA512 + +def test_hkdf(): + secret = b"secret" + salt = b"salt1234567890ab" + key = HKDF(secret, 32, salt, SHA512) # Noncompliant {{(KeyDerivationFunction) HKDF-SHA512}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py new file mode 100644 index 000000000..3f191548b --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py @@ -0,0 +1,7 @@ +from Crypto.Protocol.KDF import PBKDF1 +from Crypto.Hash import SHA256 + +def test_pbkdf1(): + password = b"password" + salt = b"salt1234" + key = PBKDF1(password, salt, 16, 1000, SHA256) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF1-SHA256}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py new file mode 100644 index 000000000..614aa54cf --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py @@ -0,0 +1,7 @@ +from Crypto.Protocol.KDF import PBKDF2 +from Crypto.Hash import SHA512 + +def test_pbkdf2(): + password = b"password" + salt = b"salt1234" + key = PBKDF2(password, salt, dkLen=64, count=1, hmac_hash_module=SHA512) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA512}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py new file mode 100644 index 000000000..a22e8d2b6 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py @@ -0,0 +1,6 @@ +from Crypto.Protocol.KDF import scrypt + +def test_scrypt(): + password = b"password" + salt = b"salt1234" + key = scrypt(password, salt, key_len=32, N=2**14, r=8, p=1, num_keys=1) # Noncompliant {{(PasswordBasedKeyDerivationFunction) SCRYPT}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFTestFile.py new file mode 100644 index 000000000..a4dc93132 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKDFTestFile.py @@ -0,0 +1,37 @@ +from Crypto.Protocol.KDF import PBKDF1, PBKDF2, scrypt, bcrypt, HKDF +from Crypto.Hash import SHA256, SHA512 + +# PBKDF1 +def test_pbkdf1(): + password = b"password" + salt = b"salt1234" + key = PBKDF1(password, salt, 16, 1000, SHA256) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF1-SHA256}} + + +# PBKDF2 +def test_pbkdf2(): + password = b"password" + salt = b"salt1234" + key = PBKDF2(password, salt, dkLen=64, count=1, hmac_hash_module=SHA512) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA512}} + + +# scrypt +def test_scrypt(): + password = b"password" + salt = b"salt1234" + key2 = scrypt(password, salt, key_len=32, N=2**14, r=8, p=1, num_keys=1) # Noncompliant {{(PasswordBasedKeyDerivationFunction) SCRYPT}} + + +# bcrypt +def test_bcrypt(): + password = b"password" + salt = b"salt1234567890ab" + key2 = bcrypt(password, cost=10, salt=salt) # detected but not mapped + + +# HKDF +def test_hkdf(): + secret = b"secret" + salt = b"salt1234567890ab" + key = HKDF(secret, 32, salt, SHA512) # Noncompliant {{(KeyDerivationFunction) HKDF-SHA512}} + diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py new file mode 100644 index 000000000..07ec871fd --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Protocol.DH import key_agreement + +shared_key = key_agreement(static_priv=None, static_pub=None) # Noncompliant {{(KeyAgreement) ECDH}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementTestFile.py new file mode 100644 index 000000000..7d4f47217 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementTestFile.py @@ -0,0 +1,22 @@ +from Crypto.PublicKey import ECC +from Crypto.Hash import SHAKE128 +from Crypto.Protocol.DH import key_agreement, import_x25519_public_key, import_x25519_private_key, import_x448_public_key, import_x448_public_key + +def kdf(x): + return SHAKE128.new(x).read(32) # Noncompliant {{(ExtendableOutputFunction) SHAKE128}} + +U_static = ECC.generate(curve='p256') # Noncompliant {{(PrivateKey) EC-secp256r1}} + +V_static = U_static.public_key() + +session_key = key_agreement(static_priv=U_static, # Noncompliant {{(KeyAgreement) ECDH}} + static_pub=V_static, + kdf=kdf) + +pub_key = import_x25519_public_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x25519}} + +priv_key = import_x25519_private_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x25519}} + +pub_key = import_x448_public_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x448}} + +priv_key = import_x448_public_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x448}} \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py new file mode 100644 index 000000000..503745b60 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Protocol.DH import import_x25519_private_key + +priv = import_x25519_private_key(b'\x00' * 32) # Noncompliant {{(KeyAgreement) x25519}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py new file mode 100644 index 000000000..d9ed9e66f --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Protocol.DH import import_x25519_public_key + +pub = import_x25519_public_key(b'\x00' * 32) # Noncompliant {{(KeyAgreement) x25519}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py new file mode 100644 index 000000000..b5a936bad --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Protocol.DH import import_x448_private_key + +priv = import_x448_private_key(b'\x00' * 56) # Noncompliant {{(KeyAgreement) x448}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py new file mode 100644 index 000000000..617b6b617 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py @@ -0,0 +1,3 @@ +from Crypto.Protocol.DH import import_x448_public_key + +pub = import_x448_public_key(b'\x00' * 56) # Noncompliant {{(KeyAgreement) x448}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py new file mode 100644 index 000000000..41bbd2fdb --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py @@ -0,0 +1,5 @@ +from Crypto.Hash import CMAC +from Crypto.Cipher import AES + +key = b'some key' +cmac = CMAC.new(key, AES) # Noncompliant {{(Mac) AES-CMAC}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py new file mode 100644 index 000000000..46adbc216 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py @@ -0,0 +1,4 @@ +from Crypto.Hash import HMAC, SHA256 + +secret = b'some secret' +hmac = HMAC.new(secret, digestmod=SHA256) # Noncompliant {{(Mac) HMAC-SHA256}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoMacTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoMacTestFile.py new file mode 100644 index 000000000..f4fd4f244 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoMacTestFile.py @@ -0,0 +1,10 @@ +from Crypto.Hash import CMAC, HMAC, SHA256 +from Crypto.Cipher import AES + +# CMAC +key = b'some key' +cmac = CMAC.new(key, AES) # Noncompliant {{(Mac) AES-CMAC}} + +# HMAC +secret = b'some secret' +hmac = HMAC.new(secret, digestmod=SHA256) # Noncompliant {{(Mac) HMAC-SHA256}} \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py new file mode 100644 index 000000000..1d78c629c --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py @@ -0,0 +1,6 @@ +from Crypto.PublicKey import DSA + +def test_dsa(): + key1 = DSA.generate(bits=2048) # Noncompliant {{(PrivateKey) DSA}} + key2 = DSA.construct((2,3), True) # Noncompliant {{(Key) DSA}} + key3 = DSA.import_key("abcdef") # Noncompliant {{(Key) DSA}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py new file mode 100644 index 000000000..689c28638 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py @@ -0,0 +1,6 @@ +from Crypto.PublicKey import ECC + +def test_ecc(): + key1 = ECC.generate(curve="Ed25519") # Noncompliant {{(PrivateKey) EC-Curve25519}} + key2 = ECC.construct(curve="Ed25519") # Noncompliant {{(Key) EC-Curve25519}} + key3 = ECC.import_key("abcdef") # Noncompliant {{(Key) EC}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py new file mode 100644 index 000000000..1c9f52c14 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py @@ -0,0 +1,5 @@ +from Crypto.PublicKey import ElGamal + +def test_elgamal(): + key1 = ElGamal.generate() # Noncompliant {{(PrivateKey) ElGamal}} + key2 = ElGamal.construct((2,3)) # Noncompliant {{(Key) ElGamal}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py new file mode 100644 index 000000000..9699b98ad --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py @@ -0,0 +1,6 @@ +from Crypto.PublicKey import RSA + +def test_rsa(): + key1 = RSA.generate(bits=2048) # Noncompliant {{(PrivateKey) RSA}} + key2 = RSA.construct((2,3), True) # Noncompliant {{(Key) RSA}} + key3 = RSA.import_key("abcdef") # Noncompliant {{(Key) RSA}} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py new file mode 100644 index 000000000..a51220a25 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py @@ -0,0 +1,9 @@ +from Crypto.Hash import SHA256 +from Crypto.PublicKey import DSA +from Crypto.Signature import DSS + +message = b'some message' +key = DSA.import_key(open('privkey.der').read()) # Noncompliant {{(Key) DSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +signer = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withDSA}} +signature = signer.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py new file mode 100644 index 000000000..c59d15504 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py @@ -0,0 +1,15 @@ +from Crypto.Hash import SHA256 +from Crypto.PublicKey import DSA +from Crypto.Signature import DSS + +message = b'some message' +key = DSA.import_key(open('pubkey.der').read()) # Noncompliant {{(Key) DSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +verifier = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withDSA}} +signature = b'some signature' + +try: + verifier.verify(h, signature) + print("The message is authentic.") +except ValueError: + print("The message is not authentic.") \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSASignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSASignTestFile.py new file mode 100644 index 000000000..04c1fdff5 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSASignTestFile.py @@ -0,0 +1,9 @@ +from Crypto.Hash import SHA256 +from Crypto.PublicKey import ECC +from Crypto.Signature import DSS + +message = b'some message' +key = ECC.import_key(open('privkey.der').read()) # Noncompliant {{(Key) EC}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +signer = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withECDSA}} +signature = signer.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSAVerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSAVerifyTestFile.py new file mode 100644 index 000000000..d5d4d0773 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSAVerifyTestFile.py @@ -0,0 +1,15 @@ +from Crypto.Hash import SHA256 +from Crypto.PublicKey import ECC +from Crypto.Signature import DSS + +message = b'some message' +key = ECC.import_key(open('pubkey.der').read()) # Noncompliant {{(Key) EC}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +verifier = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withECDSA}} +signature = b'some signature' + +try: + verifier.verify(h, signature) + print("The message is authentic.") +except ValueError: + print("The message is not authentic.") \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py new file mode 100644 index 000000000..8fed3902a --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py @@ -0,0 +1,9 @@ +from Crypto.PublicKey import ECC +from Crypto.Signature import eddsa +from Crypto.Hash import SHA512 + +message = b'some message' +prehashed_message = SHA512.new(message) # Noncompliant {{(MessageDigest) SHA512}} +key = ECC.import_key(open("private_ed25519.pem").read()) # Noncompliant {{(Key) EC}} +signer = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) EdDSA}} +signature = signer.sign(prehashed_message) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py new file mode 100644 index 000000000..ef2736762 --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py @@ -0,0 +1,15 @@ +from Crypto.PublicKey import ECC +from Crypto.Signature import eddsa +from Crypto.Hash import SHA512 + +message = b'some message' +key = ECC.import_key(open("public_ed25519.pem").read()) # Noncompliant {{(Key) EC}} +h = SHA512.new(message) # Noncompliant {{(MessageDigest) SHA512}} +verifier = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) EdDSA}} +signature = b'some signature' + +try: + verifier.verify(h, signature) + print("The message is authentic") +except ValueError: + print("The message is not authentic") \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py new file mode 100644 index 000000000..39da6967d --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py @@ -0,0 +1,9 @@ +from Crypto.Signature import pkcs1_15 +from Crypto.Hash import SHA256 +from Crypto.PublicKey import RSA + +message = b'To be signed' +key = RSA.import_key(open('private_key.der').read()) # Noncompliant {{(Key) RSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +scheme = pkcs1_15.new(key) # Noncompliant {{(Signature) SHA256withRSA}} +signature = scheme.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py new file mode 100644 index 000000000..f394f306e --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py @@ -0,0 +1,15 @@ +from Crypto.Signature import pkcs1_15 +from Crypto.Hash import SHA256 +from Crypto.PublicKey import RSA + +message = b'To be signed' +key = RSA.import_key(open('private_key.der').read()) # Noncompliant {{(Key) RSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +scheme = pkcs1_15.new(key) # Noncompliant {{(Signature) SHA256withRSA}} +signature = b'some sginature' + +try: + scheme.verify(h, signature) + print("The signature is valid.") +except (ValueError, TypeError): + print("The signature is not valid.") \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py new file mode 100644 index 000000000..8270f842d --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py @@ -0,0 +1,9 @@ +from Crypto.Signature import pss +from Crypto.Hash import SHA256 +from Crypto.PublicKey import RSA + +message = b'To be signed' +key = RSA.import_key(open('private_key.der').read()) # Noncompliant {{(Key) RSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +scheme = pss.new(key) # Noncompliant {{(ProbabilisticSignatureScheme) RSASSA-PSS}} +signature = scheme.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py new file mode 100644 index 000000000..905ba9bcc --- /dev/null +++ b/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py @@ -0,0 +1,16 @@ +from Crypto.Signature import pss +from Crypto.Signature.pss import PSS_SigScheme +from Crypto.Hash import SHA256 +from Crypto.PublicKey import RSA + +message = b'To be signed' +key = RSA.import_key(open('pubkey.der', 'rb').read()) # Noncompliant {{(Key) RSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} +verifier = pss.new(key) # Noncompliant {{(ProbabilisticSignatureScheme) RSASSA-PSS}} +signature = b'some sginature' + +try: + verifier.verify(h, signature) + print("The signature is authentic.") +except (ValueError): + print("The signature is not authentic.") \ No newline at end of file diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java new file mode 100644 index 000000000..1b9518fde --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java @@ -0,0 +1,543 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.AuthenticatedEncryption; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Mode; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Padding; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.StreamCipher; +import com.ibm.mapper.model.functionality.Decrypt; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.Encrypt; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoCipherTest { + + // ------------------------------------------------------------------------- + // Shared detection-store helpers + // ------------------------------------------------------------------------- + + private static void assertRootValueAction( + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedAlgorithm) { + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo(expectedAlgorithm); + } + + private static void assertCipherActionChild( + @Nonnull DetectionStore detectionStore, + @Nonnull TestBase test) { + DetectionStore store = + test.getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (store == null) { + return; + } + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(CipherAction.class); + assertThat(value.asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + private static void assertModeChild( + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedMode, + @Nonnull TestBase test) { + DetectionStore store = + test.getStoreOfValueType( + com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(store).isNotNull(); + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(com.ibm.engine.model.Mode.class); + assertThat(value.asString()).isEqualTo(expectedMode); + } + + private static void assertImportKeyChild( + @Nonnull DetectionStore detectionStore, + @Nonnull TestBase test) { + DetectionStore store = + test.getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + if (store != null) { + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + } + } + + // ------------------------------------------------------------------------- + // Shared translation helpers + // ------------------------------------------------------------------------- + + private static INode assertTranslationRoot( + @Nonnull List nodes, + @Nonnull Class kind, + int childCount, + @Nonnull String expectedName) { + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(kind); + assertThat(cipher.getChildren()).hasSize(childCount); + assertThat(cipher.asString()).isEqualTo(expectedName); + return cipher; + } + + private static void assertLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).isEmpty(); + assertThat(node.asString()).isEqualTo(expectedValue); + } + + private static void assertOptionalLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node) + .satisfiesAnyOf( + n -> assertThat(n).isNull(), + n -> { + assertThat(n.getChildren()).isEmpty(); + assertThat(n.asString()).isEqualTo(expectedValue); + }); + } + + private static void assertFunctionalityNodes(@Nonnull INode parent) { + assertOptionalLeafNode(parent, Encrypt.class, "ENCRYPT"); + assertOptionalLeafNode(parent, Decrypt.class, "DECRYPT"); + } + + // ------------------------------------------------------------------------- + // AES + // ------------------------------------------------------------------------- + + static class AESTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "AES"); + assertCipherActionChild(detectionStore, this); + assertModeChild(detectionStore, "MODE_CBC", this); + + INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 4, "AES-CBC"); + assertLeafNode(cipher, Mode.class, "CBC"); + assertLeafNode(cipher, Oid.class, "2.16.840.1.101.3.4.1"); + assertLeafNode(cipher, BlockSize.class, "128"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // DES + // ------------------------------------------------------------------------- + + static class DESTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "DES"); + assertCipherActionChild(detectionStore, this); + assertModeChild(detectionStore, "MODE_ECB", this); + + INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 4, "DES56-ECB"); + assertLeafNode(cipher, Mode.class, "ECB"); + assertLeafNode(cipher, KeyLength.class, "56"); + assertLeafNode(cipher, BlockSize.class, "64"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // 3DES + // ------------------------------------------------------------------------- + + static class TripleDESTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "3DES"); + assertModeChild(detectionStore, "MODE_CBC", this); + + INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 2, "3DES"); + assertLeafNode(cipher, Mode.class, "CBC"); + assertLeafNode(cipher, BlockSize.class, "64"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // Blowfish + // ------------------------------------------------------------------------- + + static class BlowfishTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "Blowfish"); + assertCipherActionChild(detectionStore, this); + assertModeChild(detectionStore, "MODE_CBC", this); + + INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 1, "Blowfish"); + assertLeafNode(cipher, Mode.class, "CBC"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // CAST5 + // ------------------------------------------------------------------------- + + static class CAST5Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "CAST5"); + assertCipherActionChild(detectionStore, this); + assertModeChild(detectionStore, "MODE_CBC", this); + + INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 2, "CAST-128"); + assertLeafNode(cipher, Mode.class, "CBC"); + assertLeafNode(cipher, BlockSize.class, "64"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // RC2 + // ------------------------------------------------------------------------- + + static class RC2Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "RC2"); + assertCipherActionChild(detectionStore, this); + assertModeChild(detectionStore, "MODE_CBC", this); + + INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 1, "RC2"); + assertLeafNode(cipher, Mode.class, "CBC"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // RC4 + // ------------------------------------------------------------------------- + + static class RC4Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "RC4"); + assertCipherActionChild(detectionStore, this); + + INode cipher = assertTranslationRoot(nodes, StreamCipher.class, 0, "RC4"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // ChaCha20-Poly1305 + // ------------------------------------------------------------------------- + + static class ChaCha20Poly1305Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "ChaCha20Poly1305"); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode cipher = + assertTranslationRoot( + nodes, AuthenticatedEncryption.class, 1, "ChaCha20Poly1305"); + + INode messageDigest = cipher.getChildren().get(MessageDigest.class); + assertThat(messageDigest).isNotNull(); + assertThat(messageDigest.getChildren()).hasSize(1); + assertThat(messageDigest.asString()).isEqualTo("Poly1305"); + assertLeafNode(messageDigest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // ChaCha20 + // ------------------------------------------------------------------------- + + static class ChaCha20Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "ChaCha20"); + assertThat(detectionStore.getChildren()).isEmpty(); + + assertTranslationRoot(nodes, StreamCipher.class, 0, "ChaCha20"); + } + } + + // ------------------------------------------------------------------------- + // Salsa20 + // ------------------------------------------------------------------------- + + static class Salsa20Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "Salsa20"); + assertCipherActionChild(detectionStore, this); + + INode cipher = assertTranslationRoot(nodes, StreamCipher.class, 1, "Salsa20"); + assertLeafNode(cipher, KeyLength.class, "128"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // PKCS1-OAEP + // ------------------------------------------------------------------------- + + static class PKCS1OAEPTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "PKCS1_OAEP"); + assertCipherActionChild(detectionStore, this); + assertImportKeyChild(detectionStore, this); + + DetectionStore store = + getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + if (store != null) { + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + } + + INode cipher = assertTranslationRoot(nodes, PublicKeyEncryption.class, 2, "RSA-OAEP"); + assertLeafNode(cipher, Oid.class, "1.2.840.113549.1.1.7"); + assertLeafNode(cipher, Padding.class, "OAEP"); + assertFunctionalityNodes(cipher); + } + } + + // ------------------------------------------------------------------------- + // PKCS1-v1.5 + // ------------------------------------------------------------------------- + + static class PKCS1v15Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertRootValueAction(detectionStore, "PKCS1_v1_5"); + assertCipherActionChild(detectionStore, this); + + INode cipher = assertTranslationRoot(nodes, PublicKeyEncryption.class, 2, "RSA"); + assertLeafNode(cipher, Oid.class, "1.2.840.113549.1.1.1"); + assertLeafNode(cipher, Padding.class, "PKCS1"); + assertFunctionalityNodes(cipher); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java new file mode 100644 index 000000000..409ffa0f5 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java @@ -0,0 +1,563 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.ParameterSetIdentifier; +import com.ibm.mapper.model.SaltLength; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoHashTest { + + // ------------------------------------------------------------------------- + // Shared helpers (static so inner classes can access them) + // ------------------------------------------------------------------------- + + private static void assertHashDetection( + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedName) { + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo(expectedName); + } + + private static INode assertHashTranslation( + @Nonnull List nodes, int childCount, @Nonnull String expectedName) { + assertThat(nodes).hasSize(1); + INode digest = nodes.get(0); + assertThat(digest).isInstanceOf(MessageDigest.class); + assertThat(digest.getChildren()).hasSize(childCount); + assertThat(digest.asString()).isEqualTo(expectedName); + return digest; + } + + private static void assertLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).isEmpty(); + assertThat(node.asString()).isEqualTo(expectedValue); + } + + // ------------------------------------------------------------------------- + // MD5 + // ------------------------------------------------------------------------- + + static class MD5Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "MD5"); + + INode digest = assertHashTranslation(nodes, 3, "MD5"); + assertLeafNode(digest, BlockSize.class, "512"); + assertLeafNode(digest, DigestSize.class, "128"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA1 + // ------------------------------------------------------------------------- + + static class SHA1Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA1"); + + INode digest = assertHashTranslation(nodes, 4, "SHA1"); + assertLeafNode(digest, BlockSize.class, "512"); + assertLeafNode(digest, Oid.class, "1.3.14.3.2.26"); + assertLeafNode(digest, DigestSize.class, "160"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA224 + // ------------------------------------------------------------------------- + + static class SHA224Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA224"); + + INode digest = assertHashTranslation(nodes, 4, "SHA224"); + assertLeafNode(digest, BlockSize.class, "512"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.4"); + assertLeafNode(digest, DigestSize.class, "224"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA256 + // ------------------------------------------------------------------------- + + static class SHA256Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA256"); + + INode digest = assertHashTranslation(nodes, 4, "SHA256"); + assertLeafNode(digest, BlockSize.class, "512"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(digest, DigestSize.class, "256"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA384 + // ------------------------------------------------------------------------- + + static class SHA384Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA384"); + + INode digest = assertHashTranslation(nodes, 4, "SHA384"); + assertLeafNode(digest, BlockSize.class, "1024"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.2"); + assertLeafNode(digest, DigestSize.class, "384"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA512 + // ------------------------------------------------------------------------- + + static class SHA512Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA512"); + + INode digest = assertHashTranslation(nodes, 4, "SHA512"); + assertLeafNode(digest, BlockSize.class, "1024"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.3"); + assertLeafNode(digest, DigestSize.class, "512"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA3-224 + // ------------------------------------------------------------------------- + + static class SHA3_224Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA3_224"); + + INode digest = assertHashTranslation(nodes, 4, "SHA3-224"); + assertLeafNode(digest, BlockSize.class, "1152"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.7"); + assertLeafNode(digest, DigestSize.class, "224"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA3-256 + // ------------------------------------------------------------------------- + + static class SHA3_256Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA3_256"); + + INode digest = assertHashTranslation(nodes, 4, "SHA3-256"); + assertLeafNode(digest, BlockSize.class, "1088"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.8"); + assertLeafNode(digest, DigestSize.class, "256"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA3-384 + // ------------------------------------------------------------------------- + + static class SHA3_384Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA3_384"); + + INode digest = assertHashTranslation(nodes, 4, "SHA3-384"); + assertLeafNode(digest, BlockSize.class, "832"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.9"); + assertLeafNode(digest, DigestSize.class, "384"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // SHA3-512 + // ------------------------------------------------------------------------- + + static class SHA3_512Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "SHA3_512"); + + INode digest = assertHashTranslation(nodes, 4, "SHA3-512"); + assertLeafNode(digest, BlockSize.class, "576"); + assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.10"); + assertLeafNode(digest, DigestSize.class, "512"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // RIPEMD-160 + // ------------------------------------------------------------------------- + + static class RIPEMD160Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "RIPEMD160"); + + INode digest = assertHashTranslation(nodes, 2, "RIPEMD-160"); + assertLeafNode(digest, DigestSize.class, "160"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // BLAKE2b + // ------------------------------------------------------------------------- + + static class BLAKE2bTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "BLAKE2b"); + + INode digest = assertHashTranslation(nodes, 2, "BLAKE2b"); + assertLeafNode(digest, SaltLength.class, "128"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // BLAKE2s + // ------------------------------------------------------------------------- + + static class BLAKE2sTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "BLAKE2s"); + + INode digest = assertHashTranslation(nodes, 2, "BLAKE2s"); + assertLeafNode(digest, SaltLength.class, "64"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // MD2 + // ------------------------------------------------------------------------- + + static class MD2Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "MD2"); + + INode digest = assertHashTranslation(nodes, 3, "MD2"); + assertLeafNode(digest, BlockSize.class, "128"); + assertLeafNode(digest, DigestSize.class, "128"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // TupleHash128 + // ------------------------------------------------------------------------- + + static class TupleHash128Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "TupleHash128"); + + INode digest = assertHashTranslation(nodes, 2, "TupleHash"); + assertLeafNode(digest, DigestSize.class, "128"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } + + // ------------------------------------------------------------------------- + // cSHAKE256 + // ------------------------------------------------------------------------- + + static class cSHAKE256Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertHashDetection(detectionStore, "cSHAKE256"); + + INode digest = assertHashTranslation(nodes, 2, "cSHAKE256"); + assertLeafNode(digest, ParameterSetIdentifier.class, "256"); + assertLeafNode(digest, Digest.class, "DIGEST"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java new file mode 100644 index 000000000..fb671b9da --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java @@ -0,0 +1,347 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.AlgorithmParameter; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyDerivationFunction; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PasswordBasedKeyDerivationFunction; +import com.ibm.mapper.model.algorithms.HKDF; +import com.ibm.mapper.model.algorithms.PBKDF1; +import com.ibm.mapper.model.algorithms.PBKDF2; +import com.ibm.mapper.model.algorithms.Scrypt; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyDerivation; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoKDFTest { + + // ------------------------------------------------------------------------- + // Shared helpers (static so inner classes can access them) + // ------------------------------------------------------------------------- + + private static void assertRootValueAction( + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedName) { + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo(expectedName); + } + + private static void assertKeySizeChild( + @Nonnull TestBase test, + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedBits) { + DetectionStore store = + test.getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(store).isNotNull(); + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(KeySize.class); + assertThat(value.asString()).isEqualTo(expectedBits); + } + + private static void assertAlgorithmChild( + @Nonnull TestBase test, + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedAlgorithm) { + DetectionStore store = + test.getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + assertThat(store).isNotNull(); + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + assertThat(value.asString()).isEqualTo(expectedAlgorithm); + } + + @SuppressWarnings("unchecked") + private static void assertIterationsValue( + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedCount) { + IValue iterValue = + detectionStore.getDetectionValues().stream() + .filter(v -> v instanceof AlgorithmParameter) + .findFirst() + .orElse(null); + assertThat(iterValue).isNotNull(); + assertThat(((AlgorithmParameter) iterValue).getKind()) + .isEqualTo(AlgorithmParameter.Kind.ITERATIONS); + assertThat(iterValue.asString()).isEqualTo(expectedCount); + } + + private static INode assertTranslationRoot( + @Nonnull List nodes, + @Nonnull Class kind, + @Nonnull Class instanceOf, + int childCount, + @Nonnull String expectedName) { + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(kind); + assertThat(root).isInstanceOf(instanceOf); + assertThat(root.getChildren()).hasSize(childCount); + assertThat(root.asString()).isEqualTo(expectedName); + return root; + } + + private static void assertLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).isEmpty(); + assertThat(node.asString()).isEqualTo(expectedValue); + } + + private static INode assertChildNode( + @Nonnull INode parent, + @Nonnull Class type, + int childCount, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).hasSize(childCount); + assertThat(node.asString()).isEqualTo(expectedValue); + return node; + } + + private static void assertMessageDigestChild( + @Nonnull INode kdfNode, + @Nonnull String expectedDigestName, + @Nonnull String expectedDigestSize, + @Nonnull String expectedOid, + @Nonnull String expectedBlockSize) { + INode md = assertChildNode(kdfNode, MessageDigest.class, 4, expectedDigestName); + assertLeafNode(md, DigestSize.class, expectedDigestSize); + assertLeafNode(md, Oid.class, expectedOid); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(md, BlockSize.class, expectedBlockSize); + } + + // ------------------------------------------------------------------------- + // PBKDF1 + // ------------------------------------------------------------------------- + + static class PBKDF1Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertRootValueAction(detectionStore, "PBKDF1"); + assertKeySizeChild(this, detectionStore, "128"); + assertAlgorithmChild(this, detectionStore, "SHA256"); + + INode root = + assertTranslationRoot( + nodes, + PasswordBasedKeyDerivationFunction.class, + PBKDF1.class, + 3, + "PBKDF1-SHA256"); + assertMessageDigestChild(root, "SHA256", "256", "2.16.840.1.101.3.4.2.1", "512"); + assertLeafNode(root, KeyLength.class, "128"); + assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); + } + } + + // ------------------------------------------------------------------------- + // PBKDF2 + // ------------------------------------------------------------------------- + + static class PBKDF2Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(2); + assertRootValueAction(detectionStore, "PBKDF2"); + assertIterationsValue(detectionStore, "1"); + assertKeySizeChild(this, detectionStore, "512"); + assertAlgorithmChild(this, detectionStore, "SHA512"); + + INode root = + assertTranslationRoot( + nodes, + PasswordBasedKeyDerivationFunction.class, + PBKDF2.class, + 3, + "PBKDF2-SHA512"); + assertMessageDigestChild(root, "SHA512", "512", "2.16.840.1.101.3.4.2.3", "1024"); + assertLeafNode(root, KeyLength.class, "512"); + assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); + } + } + + // ------------------------------------------------------------------------- + // scrypt + // ------------------------------------------------------------------------- + + static class ScryptTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertRootValueAction(detectionStore, "scrypt"); + assertKeySizeChild(this, detectionStore, "256"); + + INode root = + assertTranslationRoot( + nodes, + PasswordBasedKeyDerivationFunction.class, + Scrypt.class, + 2, + "SCRYPT"); + assertLeafNode(root, KeyLength.class, "256"); + assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); + } + } + + // ------------------------------------------------------------------------- + // bcrypt + // ------------------------------------------------------------------------- + + static class BcryptTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verifyNoIssue( + "src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(2); + assertRootValueAction(detectionStore, "bcrypt"); + assertIterationsValue(detectionStore, "10"); + assertThat(detectionStore.getChildren()).isEmpty(); + + // no mapper for bcrypt yet + assertThat(nodes).isEmpty(); + } + } + + // ------------------------------------------------------------------------- + // HKDF + // ------------------------------------------------------------------------- + + static class HKDFTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertRootValueAction(detectionStore, "HKDF"); + assertKeySizeChild(this, detectionStore, "256"); + assertAlgorithmChild(this, detectionStore, "SHA512"); + + INode root = + assertTranslationRoot( + nodes, KeyDerivationFunction.class, HKDF.class, 3, "HKDF-SHA512"); + assertMessageDigestChild(root, "SHA512", "512", "2.16.840.1.101.3.4.2.3", "1024"); + assertLeafNode(root, KeyLength.class, "256"); + assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java new file mode 100644 index 000000000..6582f5e7f --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java @@ -0,0 +1,235 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.algorithms.ECDH; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoKeyAgreementTest { + + // ------------------------------------------------------------------------- + // Shared helpers + // ------------------------------------------------------------------------- + + @SuppressWarnings("rawtypes") + private static void assertDetection( + @Nonnull DetectionStore detectionStore, + @Nonnull Class valueType, + @Nonnull String expectedName) { + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyAgreementContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(valueType); + assertThat(value.asString()).isEqualTo(expectedName); + } + + private static INode assertTranslation( + @Nonnull List nodes, + @Nonnull Class instanceOf, + @Nonnull String expectedName) { + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyAgreement.class); + assertThat(root).isInstanceOf(instanceOf); + assertThat(root.asString()).isEqualTo(expectedName); + return root; + } + + private static INode assertLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.asString()).isEqualTo(expectedValue); + return node; + } + + // ------------------------------------------------------------------------- + // key_agreement (ECDH) + // ------------------------------------------------------------------------- + + static class DHTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertDetection(detectionStore, ValueAction.class, "ECDH"); + + INode root = assertTranslation(nodes, ECDH.class, "ECDH"); + assertLeafNode(root, Oid.class, "1.3.132.1.12"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + } + } + + // ------------------------------------------------------------------------- + // import_x25519_public_key + // ------------------------------------------------------------------------- + + static class X25519PublicKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertDetection(detectionStore, KeyAction.class, "GENERATION"); + + INode root = assertTranslation(nodes, KeyAgreement.class, "x25519"); + assertLeafNode(root, EllipticCurve.class, "Curve25519"); + assertLeafNode(root, Oid.class, "1.3.101.110"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + } + } + + // ------------------------------------------------------------------------- + // import_x25519_private_key + // ------------------------------------------------------------------------- + + static class X25519PrivateKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertDetection(detectionStore, KeyAction.class, "GENERATION"); + + INode root = assertTranslation(nodes, KeyAgreement.class, "x25519"); + assertLeafNode(root, EllipticCurve.class, "Curve25519"); + assertLeafNode(root, Oid.class, "1.3.101.110"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + } + } + + // ------------------------------------------------------------------------- + // import_x448_public_key + // ------------------------------------------------------------------------- + + static class X448PublicKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertDetection(detectionStore, KeyAction.class, "GENERATION"); + + INode root = assertTranslation(nodes, KeyAgreement.class, "x448"); + assertLeafNode(root, EllipticCurve.class, "Curve448"); + assertLeafNode(root, Oid.class, "1.3.101.111"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + } + } + + // ------------------------------------------------------------------------- + // import_x448_private_key + // ------------------------------------------------------------------------- + + static class X448PrivateKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + assertDetection(detectionStore, KeyAction.class, "GENERATION"); + + INode root = assertTranslation(nodes, KeyAgreement.class, "x448"); + assertLeafNode(root, EllipticCurve.class, "Curve448"); + assertLeafNode(root, Oid.class, "1.3.101.111"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java new file mode 100644 index 000000000..c4779222a --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java @@ -0,0 +1,177 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.context.MacContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mac; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoMacTest { + + // ------------------------------------------------------------------------- + // CMAC + // ------------------------------------------------------------------------- + + static class CMACTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(MacContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + assertThat(value.asString()).isEqualTo("AES"); + + /* + * Translation + */ + assertThat(nodes).hasSize(1); + + INode mac = nodes.get(0); + assertThat(mac).isInstanceOf(Mac.class); + assertThat(mac.asString()).isEqualTo("AES-CMAC"); + assertThat(mac.getChildren()).hasSize(2); + + INode cipher = mac.getChildren().get(BlockCipher.class); + assertThat(cipher).isNotNull(); + assertThat(cipher.asString()).isEqualTo("AES"); + + INode blockSize = cipher.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("128"); + + INode oid = cipher.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.1"); + } + } + + // ------------------------------------------------------------------------- + // HMAC + // ------------------------------------------------------------------------- + + static class HMACTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(MacContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + assertThat(value.asString()).isEqualTo("SHA256"); + + /* + * Translation + */ + assertThat(nodes).hasSize(1); + + INode mac = nodes.get(0); + assertThat(mac).isInstanceOf(Mac.class); + assertThat(mac.asString()).isEqualTo("HMAC-SHA256"); + assertThat(mac.getChildren()).hasSize(3); + + INode digest = mac.getChildren().get(MessageDigest.class); + assertThat(digest).isNotNull(); + assertThat(digest.asString()).isEqualTo("SHA256"); + assertThat(digest.getChildren()).hasSize(4); + + INode digestFunc = digest.getChildren().get(Digest.class); + assertThat(digestFunc).isNotNull(); + assertThat(digestFunc.getChildren()).isEmpty(); + assertThat(digestFunc.asString()).isEqualTo("DIGEST"); + + INode blockSize = digest.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + + INode digestOid = digest.getChildren().get(Oid.class); + assertThat(digestOid).isNotNull(); + assertThat(digestOid.getChildren()).isEmpty(); + assertThat(digestOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + + INode digestSize = digest.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + + INode macOid = mac.getChildren().get(Oid.class); + assertThat(macOid).isNotNull(); + assertThat(macOid.getChildren()).isEmpty(); + assertThat(macOid.asString()).isEqualTo("1.2.840.113549.2.9"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java new file mode 100644 index 000000000..ea9f916e8 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java @@ -0,0 +1,514 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Curve; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PrivateKey; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoPublicKeyTest { + + // ------------------------------------------------------------------------- + // Shared detection-store helpers + // ------------------------------------------------------------------------- + + /** + * Asserts a root store with a single KeyAction(PRIVATE_KEY_GENERATION) in a PrivateKeyContext. + */ + private static void assertGenerateDetection( + @Nonnull + DetectionStore + detectionStore) { + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(PrivateKeyContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) value).getAction()) + .isEqualTo(KeyAction.Action.PRIVATE_KEY_GENERATION); + } + + /** Asserts a root store with a single KeyAction(GENERATION) in a KeyContext. */ + private static void assertKeyContextDetection( + @Nonnull + DetectionStore + detectionStore) { + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(KeyContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) value).getAction()).isEqualTo(KeyAction.Action.GENERATION); + } + + /** Asserts the KeySize child store present on generate rules. */ + private static void assertKeySizeChild( + @Nonnull TestBase test, + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedBits) { + DetectionStore store = + test.getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(store).isNotNull(); + assertThat(store.getDetectionValues()).hasSize(1); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(KeySize.class); + assertThat(value.asString()).isEqualTo(expectedBits); + } + + /** Asserts the Curve child store present on ECC_CONSTRUCT. */ + private static void assertCurveChild( + @Nonnull TestBase test, + @Nonnull DetectionStore detectionStore, + @Nonnull String expectedCurve) { + DetectionStore store = + test.getStoreOfValueType(Curve.class, detectionStore.getChildren()); + assertThat(store).isNotNull(); + assertThat(store.getDetectionValues()).hasSize(1); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Curve.class); + assertThat(value.asString()).isEqualTo(expectedCurve); + } + + // ------------------------------------------------------------------------- + // Shared translation helpers + // ------------------------------------------------------------------------- + + private static INode assertTranslationRoot( + @Nonnull List nodes, + @Nonnull Class kind, + int childCount, + @Nonnull String expectedName) { + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(kind); + assertThat(root.getChildren()).hasSize(childCount); + assertThat(root.asString()).isEqualTo(expectedName); + return root; + } + + private static void assertLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).isEmpty(); + assertThat(node.asString()).isEqualTo(expectedValue); + } + + private static INode assertChildNode( + @Nonnull INode parent, + @Nonnull Class type, + int childCount, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).hasSize(childCount); + assertThat(node.asString()).isEqualTo(expectedValue); + return node; + } + + // ------------------------------------------------------------------------- + // RSA + // ------------------------------------------------------------------------- + + static class RSATest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> assertRSAGenerate(detectionStore, nodes); + case 1 -> assertRSAConstruct(detectionStore, nodes); + case 2 -> assertRSAImportKey(detectionStore, nodes); + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } + + // findingId == 0 (RSA.generate(bits=2048)) + private void assertRSAGenerate( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertGenerateDetection(detectionStore); + assertKeySizeChild(this, detectionStore, "2048"); + + /* + * Translation: PrivateKey(RSA) → KeyGeneration, PrivateKey(RSA), PublicKeyEncryption(RSA) + */ + INode root = assertTranslationRoot(nodes, PrivateKey.class, 3, "RSA"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + + INode innerKey = assertChildNode(root, PrivateKey.class, 3, "RSA"); + assertLeafNode(innerKey, KeyLength.class, "2048"); + assertLeafNode(innerKey, KeyGeneration.class, "KEYGENERATION"); + INode innerPke = assertChildNode(innerKey, PublicKeyEncryption.class, 1, "RSA"); + assertLeafNode(innerPke, Oid.class, "1.2.840.113549.1.1.1"); + + INode outerPke = assertChildNode(root, PublicKeyEncryption.class, 1, "RSA"); + assertLeafNode(outerPke, Oid.class, "1.2.840.113549.1.1.1"); + } + + // findingId == 1 (RSA.construct(...)) + private void assertRSAConstruct( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertKeyContextDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: Key(RSA) → KeyGeneration, PublicKeyEncryption(RSA) + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "RSA"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode pke = assertChildNode(root, PublicKeyEncryption.class, 1, "RSA"); + assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); + } + + // findingId == 2 (RSA.import_key(...)) + private void assertRSAImportKey( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store — identical structure to RSA.construct + */ + assertKeyContextDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation — identical to RSA.construct + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "RSA"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode pke = assertChildNode(root, PublicKeyEncryption.class, 1, "RSA"); + assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); + } + } + + // ------------------------------------------------------------------------- + // DSA + // ------------------------------------------------------------------------- + + static class DSATest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> assertDSAGenerate(detectionStore, nodes); + case 1 -> assertDSAConstruct(detectionStore, nodes); + case 2 -> assertDSAImportKey(detectionStore, nodes); + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } + + // findingId == 0 (DSA.generate(bits=2048)) + private void assertDSAGenerate( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertGenerateDetection(detectionStore); + assertKeySizeChild(this, detectionStore, "2048"); + + /* + * Translation: PrivateKey(DSA) → KeyGeneration, PrivateKey(DSA), Signature(DSA) + */ + INode root = assertTranslationRoot(nodes, PrivateKey.class, 3, "DSA"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + + INode innerKey = assertChildNode(root, PrivateKey.class, 3, "DSA"); + assertLeafNode(innerKey, KeyLength.class, "2048"); + assertLeafNode(innerKey, KeyGeneration.class, "KEYGENERATION"); + INode innerSig = assertChildNode(innerKey, Signature.class, 1, "DSA"); + assertLeafNode(innerSig, Oid.class, "1.2.840.10040.4.1"); + + INode outerSig = assertChildNode(root, Signature.class, 1, "DSA"); + assertLeafNode(outerSig, Oid.class, "1.2.840.10040.4.1"); + } + + // findingId == 1 (DSA.construct(...)) + private void assertDSAConstruct( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertKeyContextDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: Key(DSA) → KeyGeneration, Signature(DSA) + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "DSA"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode sig = assertChildNode(root, Signature.class, 1, "DSA"); + assertLeafNode(sig, Oid.class, "1.2.840.10040.4.1"); + } + + // findingId == 2 (DSA.import_key(...)) + private void assertDSAImportKey( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store — identical to DSA.construct + */ + assertKeyContextDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation — identical to DSA.construct + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "DSA"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode sig = assertChildNode(root, Signature.class, 1, "DSA"); + assertLeafNode(sig, Oid.class, "1.2.840.10040.4.1"); + } + } + + // ------------------------------------------------------------------------- + // ECC + // ------------------------------------------------------------------------- + + static class ECCTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> assertECCGenerate(detectionStore, nodes); + case 1 -> assertECCConstruct(detectionStore, nodes); + case 2 -> assertECCImportKey(detectionStore, nodes); + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } + + // findingId == 0 (ECC.generate(curve="Ed25519")) + private void assertECCGenerate( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store — curve is the root value; no children + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(PrivateKeyContext.class); + IValue curve = detectionStore.getDetectionValues().get(0); + assertThat(curve).isInstanceOf(Curve.class); + assertThat(curve.asString()).isEqualTo("Ed25519"); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: PrivateKey(EC-Curve25519) → KeyGeneration, PublicKeyEncryption(EC-Curve25519) + */ + INode root = assertTranslationRoot(nodes, PrivateKey.class, 2, "EC-Curve25519"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode pke = assertChildNode(root, PublicKeyEncryption.class, 2, "EC-Curve25519"); + assertLeafNode(pke, EllipticCurve.class, "Curve25519"); + assertLeafNode(pke, Oid.class, "1.2.840.10045.2.1"); + } + + // findingId == 1 (ECC.construct(curve="Ed25519")) + private void assertECCConstruct( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertKeyContextDetection(detectionStore); + assertCurveChild(this, detectionStore, "Ed25519"); + + /* + * Translation: Key(EC-Curve25519) → KeyGeneration, PublicKeyEncryption(EC-Curve25519) + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "EC-Curve25519"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode pke = assertChildNode(root, PublicKeyEncryption.class, 2, "EC-Curve25519"); + assertLeafNode(pke, EllipticCurve.class, "Curve25519"); + assertLeafNode(pke, Oid.class, "1.2.840.10045.2.1"); + } + + // findingId == 2 (ECC.import_key(...)) + private void assertECCImportKey( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertKeyContextDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: Key(EC) → KeyGeneration, PublicKeyEncryption(EC) + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "EC"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + INode pke = assertChildNode(root, PublicKeyEncryption.class, 1, "EC"); + assertLeafNode(pke, Oid.class, "1.2.840.10045.2.1"); + } + } + + // ------------------------------------------------------------------------- + // ElGamal + // ------------------------------------------------------------------------- + + static class ElGamalTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> assertElGamalGenerate(detectionStore, nodes); + case 1 -> assertElGamalConstruct(detectionStore, nodes); + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } + + // findingId == 0 (ElGamal.generate()) + private void assertElGamalGenerate( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertGenerateDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: PrivateKey(ElGamal) → KeyGeneration, PublicKeyEncryption(ElGamal) + */ + INode root = assertTranslationRoot(nodes, PrivateKey.class, 2, "ElGamal"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + assertChildNode(root, PublicKeyEncryption.class, 0, "ElGamal"); + } + + // findingId == 1 (ElGamal.construct(...)) + private void assertElGamalConstruct( + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertKeyContextDetection(detectionStore); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: Key(ElGamal) → KeyGeneration, PublicKeyEncryption(ElGamal) + */ + INode root = assertTranslationRoot(nodes, Key.class, 2, "ElGamal"); + assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); + assertChildNode(root, PublicKeyEncryption.class, 0, "ElGamal"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java new file mode 100644 index 000000000..88352e322 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java @@ -0,0 +1,431 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.crypto; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.ProbabilisticSignatureScheme; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.mapper.model.functionality.Verify; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PythonCryptoSignatureTest { + + // ------------------------------------------------------------------------- + // Shared detection-store helpers + // ------------------------------------------------------------------------- + + private static void assertRootValueAction( + @Nonnull DetectionStore detectionStore, + @Nonnull Class expectedContext, + @Nonnull String expectedValue) { + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(expectedContext); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo(expectedValue); + } + + private static void assertSignatureActionChild( + @Nonnull DetectionStore detectionStore, + @Nonnull TestBase test, + @Nonnull String expectedAction) { + DetectionStore store = + test.getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(store).isNotNull(); + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue value = store.getDetectionValues().get(0); + assertThat(value).isInstanceOf(SignatureAction.class); + assertThat(value.asString()).isEqualTo(expectedAction); + } + + // ------------------------------------------------------------------------- + // Shared translation helpers + // ------------------------------------------------------------------------- + + private static INode assertTranslationRoot( + @Nonnull List nodes, + @Nonnull Class kind, + int childCount, + @Nonnull String expectedName) { + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(kind); + assertThat(root.getChildren()).hasSize(childCount); + assertThat(root.asString()).isEqualTo(expectedName); + return root; + } + + private static void assertLeafNode( + @Nonnull INode parent, + @Nonnull Class type, + @Nonnull String expectedValue) { + INode node = parent.getChildren().get(type); + assertThat(node).isNotNull(); + assertThat(node.getChildren()).isEmpty(); + assertThat(node.asString()).isEqualTo(expectedValue); + } + + /** Asserts a MessageDigest child on parent, returning it for further inspection. */ + private static INode assertMessageDigestChild( + @Nonnull INode parent, @Nonnull String expectedName, int childCount) { + INode md = parent.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo(expectedName); + assertThat(md.getChildren()).hasSize(childCount); + return md; + } + + /** Asserts a Key child on parent, returning it for further inspection. */ + private static INode assertKeyChild( + @Nonnull INode parent, @Nonnull String expectedAlgorithm, int childCount) { + INode key = parent.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo(expectedAlgorithm); + assertThat(key.getChildren()).hasSize(childCount); + return key; + } + + // ------------------------------------------------------------------------- + // DSS + // ------------------------------------------------------------------------- + + static class DSSSignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // Signature SHA256withDSA + assertRootValueAction(detectionStore, SignatureContext.class, "DSS"); + assertSignatureActionChild(detectionStore, this, "SIGN"); + + INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withDSA"); + assertLeafNode(sig, Oid.class, "2.16.840.1.101.3.4.3.2"); + INode key = assertKeyChild(sig, "DSA", 2); + assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); + INode md = assertMessageDigestChild(sig, "SHA256", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(md, DigestSize.class, "256"); + assertLeafNode(md, BlockSize.class, "512"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(sig, Sign.class, "SIGN"); + } + } + } + + static class DSSVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + assertRootValueAction(detectionStore, SignatureContext.class, "DSS"); + assertSignatureActionChild(detectionStore, this, "VERIFY"); + + INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withDSA"); + assertLeafNode(sig, Oid.class, "2.16.840.1.101.3.4.3.2"); + INode key = assertKeyChild(sig, "DSA", 2); + assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); + INode md = assertMessageDigestChild(sig, "SHA256", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(md, DigestSize.class, "256"); + assertLeafNode(md, BlockSize.class, "512"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(sig, Verify.class, "VERIFY"); + } + } + } + + // ------------------------------------------------------------------------- + // EdDSA + // ------------------------------------------------------------------------- + + static class EdDSASignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // Signature EdDSA + assertRootValueAction(detectionStore, SignatureContext.class, "EDDSA"); + assertSignatureActionChild(detectionStore, this, "SIGN"); + + INode sig = assertTranslationRoot(nodes, Signature.class, 2, "EdDSA"); + INode md = assertMessageDigestChild(sig, "SHA512", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.3"); + assertLeafNode(md, DigestSize.class, "512"); + assertLeafNode(md, BlockSize.class, "1024"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(sig, Sign.class, "SIGN"); + } + } + } + + static class EdDSAVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + assertRootValueAction(detectionStore, SignatureContext.class, "EDDSA"); + assertSignatureActionChild(detectionStore, this, "VERIFY"); + + INode sig = assertTranslationRoot(nodes, Signature.class, 2, "EdDSA"); + INode md = assertMessageDigestChild(sig, "SHA512", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.3"); + assertLeafNode(md, DigestSize.class, "512"); + assertLeafNode(md, BlockSize.class, "1024"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(sig, Verify.class, "VERIFY"); + } + } + } + + // ------------------------------------------------------------------------- + // PKCS1v15 + // ------------------------------------------------------------------------- + + static class PKCS1v15SignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // Signature SHA256withRSA + assertRootValueAction(detectionStore, SignatureContext.class, "RSA"); + assertSignatureActionChild(detectionStore, this, "SIGN"); + + INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withRSA"); + assertLeafNode(sig, Oid.class, "1.2.840.113549.1.1.11"); + INode key = assertKeyChild(sig, "RSA", 2); + assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); + INode md = assertMessageDigestChild(sig, "SHA256", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(md, DigestSize.class, "256"); + assertLeafNode(md, BlockSize.class, "512"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(sig, Sign.class, "SIGN"); + } + } + } + + static class PKCS1v15VerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + assertRootValueAction(detectionStore, SignatureContext.class, "RSA"); + assertSignatureActionChild(detectionStore, this, "VERIFY"); + + INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withRSA"); + assertLeafNode(sig, Oid.class, "1.2.840.113549.1.1.11"); + INode key = assertKeyChild(sig, "RSA", 2); + assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); + INode md = assertMessageDigestChild(sig, "SHA256", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(md, DigestSize.class, "256"); + assertLeafNode(md, BlockSize.class, "512"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(sig, Verify.class, "VERIFY"); + } + } + } + + // ------------------------------------------------------------------------- + // PSS + // ------------------------------------------------------------------------- + + static class PSSSignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // ProbabilisticSignatureScheme RSASSA-PSS + assertRootValueAction(detectionStore, SignatureContext.class, "RSA-PSS"); + assertSignatureActionChild(detectionStore, this, "SIGN"); + + INode pss = + assertTranslationRoot( + nodes, ProbabilisticSignatureScheme.class, 4, "RSASSA-PSS"); + assertLeafNode(pss, Oid.class, "1.2.840.113549.1.1.10"); + INode key = assertKeyChild(pss, "RSA", 2); + assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); + INode md = assertMessageDigestChild(pss, "SHA256", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(md, DigestSize.class, "256"); + assertLeafNode(md, BlockSize.class, "512"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(pss, Sign.class, "SIGN"); + } + } + } + + static class PSSVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull + DetectionStore + detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + assertRootValueAction(detectionStore, SignatureContext.class, "RSA-PSS"); + assertSignatureActionChild(detectionStore, this, "VERIFY"); + + INode pss = + assertTranslationRoot( + nodes, ProbabilisticSignatureScheme.class, 4, "RSASSA-PSS"); + assertLeafNode(pss, Oid.class, "1.2.840.113549.1.1.10"); + INode key = assertKeyChild(pss, "RSA", 2); + assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); + INode md = assertMessageDigestChild(pss, "SHA256", 4); + assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); + assertLeafNode(md, DigestSize.class, "256"); + assertLeafNode(md, BlockSize.class, "512"); + assertLeafNode(md, Digest.class, "DIGEST"); + assertLeafNode(pss, Verify.class, "VERIFY"); + } + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java index 73cef79d4..dd1305ba6 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java @@ -1,6 +1,6 @@ /* * Sonar Cryptography Plugin - * Copyright (C) 2024 PQCA + * Copyright (C) 2026 PQCA * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with From 81c07020bc76f4c129117965a1f211b28ad3a5c8 Mon Sep 17 00:00:00 2001 From: san-zrl Date: Sat, 18 Jul 2026 09:11:39 +0200 Subject: [PATCH 2/9] spotless reformatting Signed-off-by: san-zrl --- .../detection/crypto/PythonCryptoCipher.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java index 4394e1f59..8f08681d1 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java @@ -196,25 +196,25 @@ private PythonCryptoCipher() { .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") .forMethods("new") .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) - .withAnyParameters() // This must be changed if the rule below is enabled. + .withAnyParameters() // This must be changed if the rule below is enabled. .buildForContext(new CipherContext()) .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); -// // Variant with hash algo. This detects the hash but it won't be mapped. -// private static final IDetectionRule PKCS1_OAEP_NEW_WITH_HASH = -// new DetectionRuleBuilder() -// .createDetectionRule() -// .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") -// .forMethods("new") -// .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) -// .withMethodParameter(ANY) // key -// .withMethodParameter("Crypto.Hash.*") -// .shouldBeDetectedAs(new AlgorithmFactory<>()) -// .asChildOfParameterWithId(-1) -// .buildForContext(new CipherContext()) -// .inBundle(() -> "PyCrypto") -// .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + // // Variant with hash algo. This detects the hash but it won't be mapped. + // private static final IDetectionRule PKCS1_OAEP_NEW_WITH_HASH = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") + // .forMethods("new") + // .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) + // .withMethodParameter(ANY) // key + // .withMethodParameter("Crypto.Hash.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .asChildOfParameterWithId(-1) + // .buildForContext(new CipherContext()) + // .inBundle(() -> "PyCrypto") + // .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); private static final IDetectionRule PKCS1_V1_5_NEW = new DetectionRuleBuilder() From e90c91fb8fb2f1d62611f5a20d1a5f75f0354ff0 Mon Sep 17 00:00:00 2001 From: san-zrl Date: Tue, 21 Jul 2026 14:50:17 +0200 Subject: [PATCH 3/9] Reorganized python detection rules, tests and test files Signed-off-by: san-zrl --- mapper/ciphersuites.json | 2 +- .../mapper/mapper/pyca/PycaCipherMapper.java | 8 +- .../mapper/ssl/json/JsonCipherSuites.java | 33 + .../rules/SignatureReorganizer.java | 18 +- .../rules/detection/PythonDetectionRules.java | 44 +- .../detection/crypto/PythonCryptoCipher.java | 41 +- .../detection/{ => pyca}/aead/PycaAEAD.java | 2 +- .../detection/{ => pyca}/aead/PycaAES.java | 2 +- .../{ => pyca}/asymmetric/PycaDSA.java | 0 .../asymmetric/PycaDiffieHellman.java | 2 +- .../asymmetric/PycaEllipticCurve.java | 0 .../{ => pyca}/asymmetric/PycaRSA.java | 0 .../{ => pyca}/asymmetric/PycaSign.java | 2 +- .../{ => pyca}/fernet/PycaFernet.java | 2 +- .../detection/{ => pyca}/hash/PycaHash.java | 2 +- .../detection/{ => pyca}/kdf/PycaKDF.java | 2 +- .../keyagreement/PycaKeyAgreement.java | 2 +- .../detection/{ => pyca}/mac/PycaMAC.java | 2 +- .../{ => pyca}/padding/PycaPadding.java | 0 .../{ => pyca}/symmetric/PycaCipher.java | 0 .../{ => pyca}/wrapping/PycaWrapping.java | 2 +- .../pycrypto/cipher/PythonCryptoCipher.java | 287 +++++++++ .../hash}/PythonCryptoHash.java | 2 +- .../kdf}/PythonCryptoKDF.java | 2 +- .../PythonCryptoKeyAgreement.java | 2 +- .../mac}/PythonCryptoMac.java | 2 +- .../publickey}/PythonCryptoPublicKey.java | 37 +- .../pycrypto/random/PythonCryptoRandom.java | 66 ++ .../signature}/PythonCryptoSignature.java | 82 +-- .../translator/PythonTranslator.java | 7 + .../contexts/PycaCipherContextTranslator.java | 5 +- .../contexts/PycaRandomContextTranslator.java | 57 ++ .../PythonCryptoEdDSAPureSignTestFile.py | 7 - .../PythonCryptoEdDSAPureVerifyTestFile.py | 13 - .../{ => pyca}/aead/PycaAESGCMTestFile.py | 0 .../aead/PycaChaCha20Poly1305TestFile.py | 0 .../asymmetric/DSA/PycaDSANumbersTestFile.py | 0 .../asymmetric/DSA/PycaDSASignTestFile.py | 0 .../PycaDiffieHellmanGenerateTestFile.py | 0 .../PycaDiffieHellmanNumbersTestFile.py | 0 .../PycaEllipticCurveDeriveTestFile.py | 0 .../PycaEllipticCurveKeyExchangeTestFile.py | 0 .../PycaEllipticCurveNumbersTestFile.py | 0 .../PycaEllipticCurveSign2TestFile.py | 0 .../PycaEllipticCurveSignTestFile.py | 0 .../PycaEllipticCurveVerifyTestFile.py | 0 .../asymmetric/RSA/PycaRSADecryptTestFile.py | 0 .../asymmetric/RSA/PycaRSANumbersTestFile.py | 0 .../asymmetric/RSA/PycaRSASign1TestFile.py | 0 .../asymmetric/RSA/PycaRSASign2TestFile.py | 0 .../fernet/PycaFernetDecryptTestFile.py | 0 .../fernet/PycaFernetEncryptTestFile.py | 0 .../fernet/PycaMultiFernetTestFile.py | 0 .../{ => pyca}/hash/PycaHashDirectTest.py | 0 .../kdf/PycaConcatKDFHMACTestFile.py | 0 .../kdf/PycaConcatKDFHashTestFile.py | 0 .../{ => pyca}/kdf/PycaHKDFExpandTestFile.py | 0 .../{ => pyca}/kdf/PycaHKDFTestFile.py | 0 .../{ => pyca}/kdf/PycaKBKDFCMACTestFile.py | 0 .../{ => pyca}/kdf/PycaKBKDFHMACTestFile.py | 0 .../{ => pyca}/kdf/PycaPBKDF2TestFile.py | 0 .../{ => pyca}/kdf/PycaScryptTestFile.py | 0 .../{ => pyca}/kdf/PycaX963KDFTestFile.py | 0 .../keyagreement/PycaKeyAgreementTestFile.py | 0 .../{ => pyca}/mac/PycaCMACTestFile.py | 0 .../{ => pyca}/mac/PycaHMACTestFile.py | 0 ...ycaMacDetectionInCustomFunctionTestFile.py | 0 .../{ => pyca}/mac/PycaPoly1305TestFile.py | 0 .../{ => pyca}/padding/PycaPaddingTestFile.py | 0 .../symmetric/PycaCipher1TestFile.py | 0 .../symmetric/PycaCipher2TestFile.py | 0 .../pyca/symmetric/PycaCipher3TestFile.py | 36 ++ .../symmetric/PycaStreamCipher1TestFile.py | 0 .../wrapping/PycaWrappingTestFile.py | 0 .../PycaWrappingWithPaddingTestFile.py | 0 .../cipher/AESTestFile.py} | 0 .../cipher/BlowfishTestFile.py} | 0 .../cipher/CAST5TestFile.py} | 0 .../cipher/ChaCha20Poly1305TestFile.py} | 0 .../cipher/ChaCha20TestFile.py} | 0 .../cipher/DESTestFile.py} | 0 .../detection/pycrypto/cipher/HPKETestFile.py | 10 + .../cipher/PKCS1OAEPTestFile.py} | 0 .../cipher/PKCS1v15TestFile.py} | 0 .../cipher/RC2TestFile.py} | 0 .../cipher/RC4TestFile.py} | 0 .../cipher/Salsa20TestFile.py} | 0 .../cipher/TripleDESTestFile.py} | 0 .../hash/BLAKE2bTestFile.py} | 0 .../hash/BLAKE2sTestFile.py} | 0 .../hash/MD2TestFile.py} | 0 .../hash/MD5TestFile.py} | 0 .../hash/RIPEMD160TestFile.py} | 0 .../hash/SHA1TestFile.py} | 0 .../hash/SHA224TestFile.py} | 0 .../hash/SHA256TestFile.py} | 0 .../hash/SHA384TestFile.py} | 0 .../hash/SHA3_224TestFile.py} | 0 .../hash/SHA3_256TestFile.py} | 0 .../hash/SHA3_384TestFile.py} | 0 .../hash/SHA3_512TestFile.py} | 0 .../hash/SHA512TestFile.py} | 0 .../hash/TupleHash128TestFile.py} | 0 .../hash/cSHAKE256TestFile.py} | 0 .../kdf/BcryptTestFile.py} | 0 .../kdf/HKDFTestFile.py} | 0 .../kdf/PBKDF1TestFile.py} | 0 .../kdf/PBKDF2TestFile.py} | 0 .../kdf/ScryptTestFile.py} | 0 .../kdf/TestFile.py} | 0 .../keyagreement/DHTestFile.py} | 0 .../keyagreement/TestFile.py} | 0 .../keyagreement/X25519PrivateKeyTestFile.py} | 0 .../keyagreement/X25519PublicKeyTestFile.py} | 0 .../keyagreement/X448PrivateKeyTestFile.py} | 0 .../keyagreement/X448PublicKeyTestFile.py} | 0 .../mac/CMACTestFile.py} | 0 .../mac/HMACTestFile.py} | 0 .../mac/TestFile.py} | 0 .../publickey/DSATestFile.py} | 0 .../publickey/ECCTestFile.py} | 0 .../publickey/ElGamalTestFile.py} | 0 .../publickey/RSATestFile.py} | 0 .../signature/DSSSignTestFile.py} | 0 .../signature/DSSVerifyTestFile.py} | 0 .../signature/ECDSASignTestFile.py} | 0 .../signature/ECDSAVerifyTestFile.py} | 0 .../signature/EdDSASignTestFile.py} | 0 .../signature/EdDSAVerifyTestFile.py} | 0 .../signature/PKCS1v15SignTestFile.py} | 0 .../signature/PKCS1v15VerifyTestFile.py} | 0 .../signature/PSSSignTestFile.py} | 0 .../signature/PSSVerifyTestFile.py} | 0 .../crypto/PythonCryptoCipherTest.java | 543 ----------------- .../crypto/PythonCryptoHashTest.java | 563 ------------------ .../detection/crypto/PythonCryptoKDFTest.java | 347 ----------- .../crypto/PythonCryptoKeyAgreementTest.java | 235 -------- .../detection/crypto/PythonCryptoMacTest.java | 177 ------ .../crypto/PythonCryptoPublicKeyTest.java | 514 ---------------- .../crypto/PythonCryptoSignatureTest.java | 431 -------------- .../{ => pyca}/aead/PycaAESGCMTest.java | 4 +- .../aead/PycaChaCha20Poly1305Test.java | 4 +- .../asymmetric/DSA/PycaDSANumbersTest.java | 5 +- .../asymmetric/DSA/PycaDSASignTest.java | 4 +- .../PycaDiffieHellmanGenerateTest.java | 4 +- .../PycaDiffieHellmanNumbersTest.java | 4 +- .../PycaEllipticCurveDeriveTest.java | 4 +- .../PycaEllipticCurveKeyExchangeTest.java | 4 +- .../PycaEllipticCurveNumbersTest.java | 4 +- .../PycaEllipticCurveSign2Test.java | 4 +- .../PycaEllipticCurveSignTest.java | 4 +- .../PycaEllipticCurveVerifyTest.java | 4 +- .../asymmetric/RSA/PycaRSADecryptTest.java | 5 +- .../asymmetric/RSA/PycaRSANumbersTest.java | 5 +- .../asymmetric/RSA/PycaRSASign1Test.java | 4 +- .../asymmetric/RSA/PycaRSASign2Test.java | 4 +- .../fernet/PycaFernetDecryptTest.java | 4 +- .../fernet/PycaFernetEncryptTest.java | 4 +- .../fernet/PycaMultiFernetTest.java | 4 +- .../{ => pyca}/hash/PycaHashDirectTest.java | 4 +- .../{ => pyca}/kdf/PycaConcatKDFHMACTest.java | 4 +- .../{ => pyca}/kdf/PycaConcatKDFHashTest.java | 4 +- .../{ => pyca}/kdf/PycaHKDFExpandTest.java | 4 +- .../{ => pyca}/kdf/PycaHKDFTest.java | 5 +- .../{ => pyca}/kdf/PycaKBKDFCMACTest.java | 4 +- .../{ => pyca}/kdf/PycaKBKDFHMACTest.java | 4 +- .../{ => pyca}/kdf/PycaPBKDF2Test.java | 4 +- .../{ => pyca}/kdf/PycaScryptTest.java | 4 +- .../{ => pyca}/kdf/PycaX963KDFTest.java | 4 +- .../keyagreement/PycaKeyAgreementTest.java | 5 +- .../{ => pyca}/mac/PycaCMACTest.java | 5 +- .../{ => pyca}/mac/PycaHMACTest.java | 5 +- .../PycaMacDetectionInCustomFunctionTest.java | 4 +- .../{ => pyca}/mac/PycaPoly1305Test.java | 4 +- .../{ => pyca}/padding/PycaPaddingTest.java | 4 +- .../{ => pyca}/symmetric/PycaCipher1Test.java | 4 +- .../{ => pyca}/symmetric/PycaCipher2Test.java | 4 +- .../pyca/symmetric/PycaCipher3Test.java | 115 ++++ .../symmetric/PycaStreamCipher1Test.java | 4 +- .../{ => pyca}/wrapping/PycaWrappingTest.java | 4 +- .../wrapping/PycaWrappingWithPaddingTest.java | 5 +- .../detection/pycrypto/cipher/AESTest.java | 100 ++++ .../pycrypto/cipher/BlowfishTest.java | 88 +++ .../detection/pycrypto/cipher/CAST5Test.java | 94 +++ .../pycrypto/cipher/ChaCha20Poly1305Test.java | 80 +++ .../pycrypto/cipher/ChaCha20Test.java | 68 +++ .../detection/pycrypto/cipher/DESTest.java | 100 ++++ .../pycrypto/cipher/PKCS1OAEPTest.java | 98 +++ .../pycrypto/cipher/PKCS1v15Test.java | 89 +++ .../pycrypto/cipher/PythonCryptoHPKETest.java | 195 ++++++ .../detection/pycrypto/cipher/RC2Test.java | 88 +++ .../detection/pycrypto/cipher/RC4Test.java | 77 +++ .../pycrypto/cipher/Salsa20Test.java | 83 +++ .../pycrypto/cipher/TripleDESTest.java | 84 +++ .../detection/pycrypto/hash/BLAKE2bTest.java | 80 +++ .../detection/pycrypto/hash/BLAKE2sTest.java | 80 +++ .../detection/pycrypto/hash/MD2Test.java | 86 +++ .../detection/pycrypto/hash/MD5Test.java | 86 +++ .../pycrypto/hash/RIPEMD160Test.java | 80 +++ .../detection/pycrypto/hash/SHA1Test.java | 92 +++ .../detection/pycrypto/hash/SHA224Test.java | 92 +++ .../detection/pycrypto/hash/SHA256Test.java | 92 +++ .../detection/pycrypto/hash/SHA384Test.java | 92 +++ .../detection/pycrypto/hash/SHA3_224Test.java | 92 +++ .../detection/pycrypto/hash/SHA3_256Test.java | 92 +++ .../detection/pycrypto/hash/SHA3_384Test.java | 92 +++ .../detection/pycrypto/hash/SHA3_512Test.java | 92 +++ .../detection/pycrypto/hash/SHA512Test.java | 92 +++ .../pycrypto/hash/TupleHash128Test.java | 80 +++ .../pycrypto/hash/cSHAKE256Test.java | 80 +++ .../detection/pycrypto/kdf/BcryptTest.java | 76 +++ .../detection/pycrypto/kdf/HKDFTest.java | 102 ++++ .../detection/pycrypto/kdf/PBKDF1Test.java | 117 ++++ .../detection/pycrypto/kdf/PBKDF2Test.java | 114 ++++ .../detection/pycrypto/kdf/ScryptTest.java | 82 +++ .../pycrypto/keyagreement/DHTest.java | 76 +++ .../keyagreement/X25519PrivateKeyTest.java | 78 +++ .../keyagreement/X25519PublicKeyTest.java | 78 +++ .../keyagreement/X448PrivateKeyTest.java | 78 +++ .../keyagreement/X448PublicKeyTest.java | 78 +++ .../detection/pycrypto/mac/CMACTest.java | 92 +++ .../detection/pycrypto/mac/HMACTest.java | 91 +++ .../detection/pycrypto/publickey/DSATest.java | 147 +++++ .../detection/pycrypto/publickey/ECCTest.java | 141 +++++ .../pycrypto/publickey/ElGamalTest.java | 101 ++++ .../detection/pycrypto/publickey/RSATest.java | 153 +++++ .../pycrypto/signature/DSSSignTest.java | 128 ++++ .../pycrypto/signature/DSSVerifyTest.java | 128 ++++ .../pycrypto/signature/EdDSASignTest.java | 112 ++++ .../pycrypto/signature/EdDSAVerifyTest.java | 112 ++++ .../pycrypto/signature/PKCS1v15SignTest.java | 135 +++++ .../signature/PKCS1v15VerifyTest.java | 136 +++++ .../pycrypto/signature/PSSSignTest.java | 135 +++++ .../pycrypto/signature/PSSVerifyTest.java | 135 +++++ 234 files changed, 6118 insertions(+), 3025 deletions(-) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/aead/PycaAEAD.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/aead/PycaAES.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/PycaDSA.java (100%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/PycaDiffieHellman.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/PycaEllipticCurve.java (100%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/PycaRSA.java (100%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/PycaSign.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/fernet/PycaFernet.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/hash/PycaHash.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaKDF.java (99%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/keyagreement/PycaKeyAgreement.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/mac/PycaMAC.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/padding/PycaPadding.java (100%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/symmetric/PycaCipher.java (100%) rename python/src/main/java/com/ibm/plugin/rules/detection/{ => pyca}/wrapping/PycaWrapping.java (98%) create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java rename python/src/main/java/com/ibm/plugin/rules/detection/{crypto => pycrypto/hash}/PythonCryptoHash.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{crypto => pycrypto/kdf}/PythonCryptoKDF.java (99%) rename python/src/main/java/com/ibm/plugin/rules/detection/{crypto => pycrypto/keyagreement}/PythonCryptoKeyAgreement.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{crypto => pycrypto/mac}/PythonCryptoMac.java (98%) rename python/src/main/java/com/ibm/plugin/rules/detection/{crypto => pycrypto/publickey}/PythonCryptoPublicKey.java (87%) create mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java rename python/src/main/java/com/ibm/plugin/rules/detection/{crypto => pycrypto/signature}/PythonCryptoSignature.java (66%) create mode 100644 python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaRandomContextTranslator.java delete mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py delete mode 100644 python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py rename python/src/test/files/rules/detection/{ => pyca}/aead/PycaAESGCMTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/aead/PycaChaCha20Poly1305TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/DSA/PycaDSANumbersTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/DSA/PycaDSASignTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSADecryptTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSANumbersTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSASign1TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSASign2TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/fernet/PycaFernetDecryptTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/fernet/PycaFernetEncryptTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/fernet/PycaMultiFernetTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/hash/PycaHashDirectTest.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaConcatKDFHMACTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaConcatKDFHashTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaHKDFExpandTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaHKDFTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaKBKDFCMACTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaKBKDFHMACTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaPBKDF2TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaScryptTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/kdf/PycaX963KDFTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/keyagreement/PycaKeyAgreementTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/mac/PycaCMACTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/mac/PycaHMACTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/mac/PycaMacDetectionInCustomFunctionTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/mac/PycaPoly1305TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/padding/PycaPaddingTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/symmetric/PycaCipher1TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/symmetric/PycaCipher2TestFile.py (100%) create mode 100644 python/src/test/files/rules/detection/pyca/symmetric/PycaCipher3TestFile.py rename python/src/test/files/rules/detection/{ => pyca}/symmetric/PycaStreamCipher1TestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/wrapping/PycaWrappingTestFile.py (100%) rename python/src/test/files/rules/detection/{ => pyca}/wrapping/PycaWrappingWithPaddingTestFile.py (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherAESTestFile.py => pycrypto/cipher/AESTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherBlowfishTestFile.py => pycrypto/cipher/BlowfishTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherCAST5TestFile.py => pycrypto/cipher/CAST5TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py => pycrypto/cipher/ChaCha20Poly1305TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherChaCha20TestFile.py => pycrypto/cipher/ChaCha20TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherDESTestFile.py => pycrypto/cipher/DESTestFile.py} (100%) create mode 100644 python/src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherPKCS1OAEPTestFile.py => pycrypto/cipher/PKCS1OAEPTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherPKCS1v15TestFile.py => pycrypto/cipher/PKCS1v15TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherRC2TestFile.py => pycrypto/cipher/RC2TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherRC4TestFile.py => pycrypto/cipher/RC4TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipherSalsa20TestFile.py => pycrypto/cipher/Salsa20TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoCipher3DESTestFile.py => pycrypto/cipher/TripleDESTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashBLAKE2bTestFile.py => pycrypto/hash/BLAKE2bTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashBLAKE2sTestFile.py => pycrypto/hash/BLAKE2sTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashMD2TestFile.py => pycrypto/hash/MD2TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashMD5TestFile.py => pycrypto/hash/MD5TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashRIPEMD160TestFile.py => pycrypto/hash/RIPEMD160TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA1TestFile.py => pycrypto/hash/SHA1TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA224TestFile.py => pycrypto/hash/SHA224TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA256TestFile.py => pycrypto/hash/SHA256TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA384TestFile.py => pycrypto/hash/SHA384TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA3_224TestFile.py => pycrypto/hash/SHA3_224TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA3_256TestFile.py => pycrypto/hash/SHA3_256TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA3_384TestFile.py => pycrypto/hash/SHA3_384TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA3_512TestFile.py => pycrypto/hash/SHA3_512TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashSHA512TestFile.py => pycrypto/hash/SHA512TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashTupleHash128TestFile.py => pycrypto/hash/TupleHash128TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoHashcSHAKE256TestFile.py => pycrypto/hash/cSHAKE256TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKDFBcryptTestFile.py => pycrypto/kdf/BcryptTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKDFHKDFTestFile.py => pycrypto/kdf/HKDFTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKDFPBKDF1TestFile.py => pycrypto/kdf/PBKDF1TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKDFPBKDF2TestFile.py => pycrypto/kdf/PBKDF2TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKDFScryptTestFile.py => pycrypto/kdf/ScryptTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKDFTestFile.py => pycrypto/kdf/TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKeyAgreementDHTestFile.py => pycrypto/keyagreement/DHTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKeyAgreementTestFile.py => pycrypto/keyagreement/TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py => pycrypto/keyagreement/X25519PrivateKeyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py => pycrypto/keyagreement/X25519PublicKeyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py => pycrypto/keyagreement/X448PrivateKeyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py => pycrypto/keyagreement/X448PublicKeyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoMacCMACTestFile.py => pycrypto/mac/CMACTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoMacHMACTestFile.py => pycrypto/mac/HMACTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoMacTestFile.py => pycrypto/mac/TestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoPublicKeyDSATestFile.py => pycrypto/publickey/DSATestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoPublicKeyECCTestFile.py => pycrypto/publickey/ECCTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoPublicKeyElGamalTestFile.py => pycrypto/publickey/ElGamalTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoPublicKeyRSATestFile.py => pycrypto/publickey/RSATestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignatureDSSSignTestFile.py => pycrypto/signature/DSSSignTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignatureDSSVerifyTestFile.py => pycrypto/signature/DSSVerifyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignatureECDSASignTestFile.py => pycrypto/signature/ECDSASignTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignatureECDSAVerifyTestFile.py => pycrypto/signature/ECDSAVerifyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignatureEdDSASignTestFile.py => pycrypto/signature/EdDSASignTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py => pycrypto/signature/EdDSAVerifyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py => pycrypto/signature/PKCS1v15SignTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py => pycrypto/signature/PKCS1v15VerifyTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignaturePSSSignTestFile.py => pycrypto/signature/PSSSignTestFile.py} (100%) rename python/src/test/files/rules/detection/{crypto/PythonCryptoSignaturePSSVerifyTestFile.py => pycrypto/signature/PSSVerifyTestFile.py} (100%) delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/aead/PycaAESGCMTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/aead/PycaChaCha20Poly1305Test.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/DSA/PycaDSANumbersTest.java (96%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/DSA/PycaDSASignTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java (95%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java (95%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java (95%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java (90%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java (91%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSADecryptTest.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSANumbersTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSASign1Test.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/asymmetric/RSA/PycaRSASign2Test.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/fernet/PycaFernetDecryptTest.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/fernet/PycaFernetEncryptTest.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/fernet/PycaMultiFernetTest.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/hash/PycaHashDirectTest.java (96%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaConcatKDFHMACTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaConcatKDFHashTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaHKDFExpandTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaHKDFTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaKBKDFCMACTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaKBKDFHMACTest.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaPBKDF2Test.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaScryptTest.java (96%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/kdf/PycaX963KDFTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/keyagreement/PycaKeyAgreementTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/mac/PycaCMACTest.java (95%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/mac/PycaHMACTest.java (96%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/mac/PycaMacDetectionInCustomFunctionTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/mac/PycaPoly1305Test.java (96%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/padding/PycaPaddingTest.java (97%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/symmetric/PycaCipher1Test.java (98%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/symmetric/PycaCipher2Test.java (96%) create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher3Test.java rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/symmetric/PycaStreamCipher1Test.java (95%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/wrapping/PycaWrappingTest.java (95%) rename python/src/test/java/com/ibm/plugin/rules/detection/{ => pyca}/wrapping/PycaWrappingWithPaddingTest.java (95%) create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/AESTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1OAEPTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1v15Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC4Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/Salsa20Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2bTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2sTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD2Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD5Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/RIPEMD160Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_224Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_256Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_384Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_512Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/TupleHash128Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/cSHAKE256Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/BcryptTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/DHTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PublicKeyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PrivateKeyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PublicKeyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/DSATest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ECCTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ElGamalTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/RSATest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java diff --git a/mapper/ciphersuites.json b/mapper/ciphersuites.json index 44542d946..9f4583301 100644 --- a/mapper/ciphersuites.json +++ b/mapper/ciphersuites.json @@ -1 +1 @@ -{"ciphersuites": [{"TLS_AES_128_CCM_8_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x13", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.3"]}}, {"TLS_AES_128_CCM_SHA256": {"gnutls_name": "", "openssl_name": "TLS_AES_128_CCM_SHA256", "hex_byte_1": "0x13", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.3"]}}, {"TLS_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "TLS_AES_128_GCM_SHA256", "hex_byte_1": "0x13", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "TLS_AES_256_GCM_SHA384", "hex_byte_1": "0x13", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_CHACHA20_POLY1305_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x13", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x19", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_EXPORT_WITH_RC4_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x17", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "RC4 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_3DES_EDE_CBC_SHA1", "openssl_name": "ADH-DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x1B", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_AES_128_CBC_SHA1", "openssl_name": "ADH-AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x34", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_AES_128_CBC_SHA256", "openssl_name": "ADH-AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6C", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DH_ANON_AES_128_GCM_SHA256", "openssl_name": "ADH-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xA6", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_AES_256_CBC_SHA1", "openssl_name": "ADH-AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x3A", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_AES_256_CBC_SHA256", "openssl_name": "ADH-AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6D", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DH_ANON_AES_256_GCM_SHA384", "openssl_name": "ADH-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xA7", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x46", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5A", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x47", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5B", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_128_CBC_SHA1", "openssl_name": "ADH-CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x46", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_128_CBC_SHA256", "openssl_name": "ADH-CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBF", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x84", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_256_CBC_SHA1", "openssl_name": "ADH-CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x89", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_256_CBC_SHA256", "openssl_name": "ADH-CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC5", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x85", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x1A", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_RC4_128_MD5": {"gnutls_name": "TLS_DH_ANON_ARCFOUR_128_MD5", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x18", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "RC4 128", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "ADH-SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x9B", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0B", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0D", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x30", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x3E", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA4", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x36", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x68", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA5", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3E", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x58", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x59", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x42", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xBB", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x82", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x85", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC1", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x83", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0C", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x97", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x11", "protocol_version": "TLS EXPORT", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_3DES_EDE_CBC_SHA1", "openssl_name": "DHE-DSS-DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x13", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_AES_128_CBC_SHA1", "openssl_name": "DHE-DSS-AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x32", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_AES_128_CBC_SHA256", "openssl_name": "DHE-DSS-AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x40", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_DSS_AES_128_GCM_SHA256", "openssl_name": "DHE-DSS-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xA2", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_AES_256_CBC_SHA1", "openssl_name": "DHE-DSS-AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x38", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_AES_256_CBC_SHA256", "openssl_name": "DHE-DSS-AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6A", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_DSS_AES_256_GCM_SHA384", "openssl_name": "DHE-DSS-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xA3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x42", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x56", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x43", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x57", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_128_CBC_SHA1", "openssl_name": "DHE-DSS-CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x44", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_128_CBC_SHA256", "openssl_name": "DHE-DSS-CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBD", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x80", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_256_CBC_SHA1", "openssl_name": "DHE-DSS-CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x87", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_256_CBC_SHA256", "openssl_name": "DHE-DSS-CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x81", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x12", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "DHE-DSS-SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x99", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DHE_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "DHE-PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8F", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DHE_PSK_AES_128_CBC_SHA1", "openssl_name": "DHE-PSK-AES128-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x90", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_PSK_AES_128_CBC_SHA256", "openssl_name": "DHE-PSK-AES128-CBC-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB2", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_CCM": {"gnutls_name": "TLS_DHE_PSK_AES_128_CCM", "openssl_name": "DHE-PSK-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA6", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_PSK_AES_128_GCM_SHA256", "openssl_name": "DHE-PSK-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xAA", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DHE_PSK_AES_256_CBC_SHA1", "openssl_name": "DHE-PSK-AES256-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x91", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_DHE_PSK_AES_256_CBC_SHA384", "openssl_name": "DHE-PSK-AES256-CBC-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_CCM": {"gnutls_name": "TLS_DHE_PSK_AES_256_CCM", "openssl_name": "DHE-PSK-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA7", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_PSK_AES_256_GCM_SHA384", "openssl_name": "DHE-PSK-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xAB", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x66", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6C", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x67", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6D", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "DHE-PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x96", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x90", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "DHE-PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x97", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x91", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_DHE_PSK_CHACHA20_POLY1305", "openssl_name": "DHE-PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAD", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_DHE_PSK_NULL_SHA1", "openssl_name": "DHE-PSK-NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2D", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_DHE_PSK_NULL_SHA256", "openssl_name": "DHE-PSK-NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB4", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_DHE_PSK_NULL_SHA384", "openssl_name": "DHE-PSK-NULL-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB5", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_DHE_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x8E", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x14", "protocol_version": "TLS EXPORT", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "DHE-RSA-DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x16", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_AES_128_CBC_SHA1", "openssl_name": "DHE-RSA-AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x33", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_AES_128_CBC_SHA256", "openssl_name": "DHE-RSA-AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x67", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CCM": {"gnutls_name": "TLS_DHE_RSA_AES_128_CCM", "openssl_name": "DHE-RSA-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9E", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_DHE_RSA_AES_128_CCM_8", "openssl_name": "DHE-RSA-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA2", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_RSA_AES_128_GCM_SHA256", "openssl_name": "DHE-RSA-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x9E", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_AES_256_CBC_SHA1", "openssl_name": "DHE-RSA-AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x39", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_AES_256_CBC_SHA256", "openssl_name": "DHE-RSA-AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6B", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CCM": {"gnutls_name": "TLS_DHE_RSA_AES_256_CCM", "openssl_name": "DHE-RSA-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9F", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_DHE_RSA_AES_256_CCM_8", "openssl_name": "DHE-RSA-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_RSA_AES_256_GCM_SHA384", "openssl_name": "DHE-RSA-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0x9F", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x44", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x52", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x45", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x53", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_128_CBC_SHA1", "openssl_name": "DHE-RSA-CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x45", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "DHE-RSA-CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBE", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7C", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_256_CBC_SHA1", "openssl_name": "DHE-RSA-CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x88", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_256_CBC_SHA256", "openssl_name": "DHE-RSA-CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC4", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7D", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_DHE_RSA_CHACHA20_POLY1305", "openssl_name": "DHE-RSA-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAA", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x15", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "DHE-RSA-SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x9A", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0E", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x10", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x31", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x3F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA0", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x37", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x69", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA1", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x40", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x54", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x41", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x55", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x43", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xBC", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7E", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x86", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC2", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x98", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_128_CCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB2", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB0", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_256_CCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB3", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB1", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDH_ANON_3DES_EDE_CBC_SHA1", "openssl_name": "AECDH-DES-CBC3-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x17", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDH_ANON_AES_128_CBC_SHA1", "openssl_name": "AECDH-AES128-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x18", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDH_ANON_AES_256_CBC_SHA1", "openssl_name": "AECDH-AES256-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x19", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDH_ANON_NULL_SHA1", "openssl_name": "AECDH-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x15", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDH_ANON_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x16", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x25", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x2D", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x26", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x2E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4A", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4B", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5F", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x74", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x88", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x75", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x89", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_NULL_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_RC4_128_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA1", "openssl_name": "ECDHE-ECDSA-DES-CBC3-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x08", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CBC_SHA1", "openssl_name": "ECDHE-ECDSA-AES128-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x09", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CBC_SHA256", "openssl_name": "ECDHE-ECDSA-AES128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x23", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CCM": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CCM", "openssl_name": "ECDHE-ECDSA-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xAC", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CCM_8", "openssl_name": "ECDHE-ECDSA-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAE", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_GCM_SHA256", "openssl_name": "ECDHE-ECDSA-AES128-GCM-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x2B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CBC_SHA1", "openssl_name": "ECDHE-ECDSA-AES256-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x0A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CBC_SHA384", "openssl_name": "ECDHE-ECDSA-AES256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x24", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CCM": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CCM", "openssl_name": "ECDHE-ECDSA-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xAD", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CCM_8", "openssl_name": "ECDHE-ECDSA-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAF", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_GCM_SHA384", "openssl_name": "ECDHE-ECDSA-AES256-GCM-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x2C", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x48", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5C", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x49", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5D", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "ECDHE-ECDSA-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x72", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x86", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_256_CBC_SHA384", "openssl_name": "ECDHE-ECDSA-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x73", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x87", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_CHACHA20_POLY1305", "openssl_name": "ECDHE-ECDSA-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xA9", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_NULL_SHA1", "openssl_name": "ECDHE-ECDSA-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x06", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x07", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDHE_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "ECDHE-PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x34", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDHE_PSK_AES_128_CBC_SHA1", "openssl_name": "ECDHE-PSK-AES128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x35", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_AES_128_CBC_SHA256", "openssl_name": "ECDHE-PSK-AES128-CBC-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x37", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDHE_PSK_AES_256_CBC_SHA1", "openssl_name": "ECDHE-PSK-AES256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x36", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_PSK_AES_256_CBC_SHA384", "openssl_name": "ECDHE-PSK-AES256-CBC-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x38", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x70", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x71", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "ECDHE-PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x9A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "ECDHE-PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x9B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_CHACHA20_POLY1305", "openssl_name": "ECDHE-PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAC", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDHE_PSK_NULL_SHA1", "openssl_name": "ECDHE-PSK-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x39", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_NULL_SHA256", "openssl_name": "ECDHE-PSK-NULL-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x3A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_ECDHE_PSK_NULL_SHA384", "openssl_name": "ECDHE-PSK-NULL-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x3B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDHE_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x33", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDHE_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "ECDHE-RSA-DES-CBC3-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x12", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDHE_RSA_AES_128_CBC_SHA1", "openssl_name": "ECDHE-RSA-AES128-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x13", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_AES_128_CBC_SHA256", "openssl_name": "ECDHE-RSA-AES128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x27", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_AES_128_GCM_SHA256", "openssl_name": "ECDHE-RSA-AES128-GCM-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x2F", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDHE_RSA_AES_256_CBC_SHA1", "openssl_name": "ECDHE-RSA-AES256-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x14", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_AES_256_CBC_SHA384", "openssl_name": "ECDHE-RSA-AES256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x28", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_AES_256_GCM_SHA384", "openssl_name": "ECDHE-RSA-AES256-GCM-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x30", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4C", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x60", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4D", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x61", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "ECDHE-RSA-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x76", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_256_CBC_SHA384", "openssl_name": "ECDHE-RSA-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x77", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_CHACHA20_POLY1305", "openssl_name": "ECDHE-RSA-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xA8", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDHE_RSA_NULL_SHA1", "openssl_name": "ECDHE-RSA-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x10", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDHE_RSA_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x11", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0D", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x29", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x31", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0F", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x2A", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x32", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x62", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4F", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x63", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x78", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8C", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x79", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8D", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_NULL_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0B", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_RC4_128_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0C", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_28147_CNT_IMIT": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "GOSTR341112 256", "auth_algorithm": "GOSTR341012", "enc_algorithm": "28147 CNT", "hash_algorithm": "GOSTR341112", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x00", "protocol_version": "TLS", "kex_algorithm": "GOSTR341112 256", "auth_algorithm": "GOSTR341012", "enc_algorithm": "KUZNYECHIK CTR", "hash_algorithm": "GOSTR341112", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "KUZNYECHIK MGM L", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "KUZNYECHIK MGM S", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "GOSTR341112 256", "auth_algorithm": "GOSTR341012", "enc_algorithm": "MAGMA CTR", "hash_algorithm": "GOSTR341112", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_MAGMA_MGM_L": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "MAGMA MGM L", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_MAGMA_MGM_S": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x06", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "MAGMA MGM S", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x29", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x26", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC 40", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x2A", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC2 CBC 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x27", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC2 CBC 40", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC4_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x2B", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC4_40_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x28", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 40", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_3DES_EDE_CBC_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x23", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x1F", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_DES_CBC_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x22", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x1E", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_IDEA_CBC_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x25", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "IDEA CBC", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_IDEA_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x21", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "IDEA CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_RC4_128_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x24", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 128", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_RC4_128_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x20", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_NULL_WITH_NULL_NULL": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x00", "protocol_version": "TLS", "kex_algorithm": "NULL", "auth_algorithm": "NULL", "enc_algorithm": "NULL", "hash_algorithm": "NULL", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_DHE_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_DHE_PSK_AES_128_CCM_8", "openssl_name": "DHE-PSK-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAA", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_DHE_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_DHE_PSK_AES_256_CCM_8", "openssl_name": "DHE-PSK-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAB", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8B", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_PSK_AES_128_CBC_SHA1", "openssl_name": "PSK-AES128-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8C", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_PSK_AES_128_CBC_SHA256", "openssl_name": "PSK-AES128-CBC-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xAE", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CCM": {"gnutls_name": "TLS_PSK_AES_128_CCM", "openssl_name": "PSK-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA4", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_PSK_AES_128_CCM_8", "openssl_name": "PSK-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA8", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_PSK_AES_128_GCM_SHA256", "openssl_name": "PSK-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xA8", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_PSK_AES_256_CBC_SHA1", "openssl_name": "PSK-AES256-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8D", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_PSK_AES_256_CBC_SHA384", "openssl_name": "PSK-AES256-CBC-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xAF", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CCM": {"gnutls_name": "TLS_PSK_AES_256_CCM", "openssl_name": "PSK-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA5", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_PSK_AES_256_CCM_8", "openssl_name": "PSK-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA9", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_PSK_AES_256_GCM_SHA384", "openssl_name": "PSK-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xA9", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x64", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6A", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x65", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6B", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x94", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_PSK_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8E", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x95", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_PSK_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8F", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_PSK_CHACHA20_POLY1305", "openssl_name": "PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAB", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_PSK_NULL_SHA1", "openssl_name": "PSK-NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2C", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_PSK_NULL_SHA256", "openssl_name": "PSK-NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB0", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_PSK_NULL_SHA384", "openssl_name": "PSK-NULL-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB1", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x8A", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x08", "protocol_version": "TLS EXPORT", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x06", "protocol_version": "TLS EXPORT", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC2 CBC 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_EXPORT_WITH_RC4_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x03", "protocol_version": "TLS EXPORT", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC4 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_RSA_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "RSA-PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x93", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_RSA_PSK_AES_128_CBC_SHA1", "openssl_name": "RSA-PSK-AES128-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x94", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_PSK_AES_128_CBC_SHA256", "openssl_name": "RSA-PSK-AES128-CBC-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB6", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_PSK_AES_128_GCM_SHA256", "openssl_name": "RSA-PSK-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xAC", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_RSA_PSK_AES_256_CBC_SHA1", "openssl_name": "RSA-PSK-AES256-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x95", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_RSA_PSK_AES_256_CBC_SHA384", "openssl_name": "RSA-PSK-AES256-CBC-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB7", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_PSK_AES_256_GCM_SHA384", "openssl_name": "RSA-PSK-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xAD", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x68", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6E", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x69", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6F", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "RSA-PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x98", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x92", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "RSA-PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x99", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x93", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_RSA_PSK_CHACHA20_POLY1305", "openssl_name": "RSA-PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAE", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_RSA_PSK_NULL_SHA1", "openssl_name": "RSA-PSK-NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2E", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_RSA_PSK_NULL_SHA256", "openssl_name": "RSA-PSK-NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB8", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_RSA_PSK_NULL_SHA384", "openssl_name": "RSA-PSK-NULL-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB9", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_RSA_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x92", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x0A", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_RSA_AES_128_CBC_SHA1", "openssl_name": "AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2F", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_AES_128_CBC_SHA256", "openssl_name": "AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x3C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CCM": {"gnutls_name": "TLS_RSA_AES_128_CCM", "openssl_name": "AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_RSA_AES_128_CCM_8", "openssl_name": "AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA0", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_AES_128_GCM_SHA256", "openssl_name": "AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x9C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_RSA_AES_256_CBC_SHA1", "openssl_name": "AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x35", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_RSA_AES_256_CBC_SHA256", "openssl_name": "AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x3D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CCM": {"gnutls_name": "TLS_RSA_AES_256_CCM", "openssl_name": "AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_RSA_AES_256_CCM_8", "openssl_name": "AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA1", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_AES_256_GCM_SHA384", "openssl_name": "AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0x9D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x50", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x51", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_RSA_CAMELLIA_128_CBC_SHA1", "openssl_name": "CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x41", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBA", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7A", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_RSA_CAMELLIA_256_CBC_SHA1", "openssl_name": "CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x84", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_RSA_CAMELLIA_256_CBC_SHA256", "openssl_name": "CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC0", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7B", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x09", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_IDEA_CBC_SHA": {"gnutls_name": "", "openssl_name": "IDEA-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x07", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "IDEA CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_NULL_MD5": {"gnutls_name": "TLS_RSA_NULL_MD5", "openssl_name": "NULL-MD5", "hex_byte_1": "0x00", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_NULL_SHA": {"gnutls_name": "TLS_RSA_NULL_SHA1", "openssl_name": "NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_NULL_SHA256": {"gnutls_name": "TLS_RSA_NULL_SHA256", "openssl_name": "NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x3B", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_RC4_128_MD5": {"gnutls_name": "TLS_RSA_ARCFOUR_128_MD5", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_RC4_128_SHA": {"gnutls_name": "TLS_RSA_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x96", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SHA256_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB4", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "SHA256", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SHA384_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB5", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "SHA384", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SM4_CCM_SM3": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC7", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "SM4 CCM", "hash_algorithm": "SM3", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SM4_GCM_SM3": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC6", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "SM4 GCM", "hash_algorithm": "SM3", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1", "openssl_name": "SRP-DSS-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1C", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA DSS", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_DSS_AES_128_CBC_SHA1", "openssl_name": "SRP-DSS-AES-128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1F", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_DSS_AES_256_CBC_SHA1", "openssl_name": "SRP-DSS-AES-256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x22", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "SRP-RSA-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1B", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_RSA_AES_128_CBC_SHA1", "openssl_name": "SRP-RSA-AES-128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1E", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_RSA_AES_256_CBC_SHA1", "openssl_name": "SRP-RSA-AES-256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x21", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_3DES_EDE_CBC_SHA1", "openssl_name": "SRP-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1A", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_AES_128_CBC_SHA1", "openssl_name": "SRP-AES-128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1D", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_AES_256_CBC_SHA1", "openssl_name": "SRP-AES-256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x20", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}]} \ No newline at end of file +{"ciphersuites": [{"TLS_AES_128_CCM_8_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x13", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.3"]}}, {"TLS_AES_128_CCM_ASCONHASH256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x71", "protocol_version": "TLS", "kex_algorithm": "AES", "auth_algorithm": "128 CCM ASCONHASH256", "enc_algorithm": "", "hash_algorithm": "", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_AES_128_CCM_SHA256": {"gnutls_name": "", "openssl_name": "TLS_AES_128_CCM_SHA256", "hex_byte_1": "0x13", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.3"]}}, {"TLS_AES_128_GCM_ASCONHASH256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x70", "protocol_version": "TLS", "kex_algorithm": "AES", "auth_algorithm": "128 GCM ASCONHASH256", "enc_algorithm": "", "hash_algorithm": "", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "TLS_AES_128_GCM_SHA256", "hex_byte_1": "0x13", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "TLS_AES_256_GCM_SHA384", "hex_byte_1": "0x13", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_ASCONAEAD128_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x6F", "protocol_version": "TLS", "kex_algorithm": "ASCONAEAD128", "auth_algorithm": "SHA256", "enc_algorithm": "", "hash_algorithm": "", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_CHACHA20_POLY1305_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x13", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.3"]}}, {"TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x19", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_EXPORT_WITH_RC4_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x17", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "RC4 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_3DES_EDE_CBC_SHA1", "openssl_name": "ADH-DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x1B", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_AES_128_CBC_SHA1", "openssl_name": "ADH-AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x34", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_AES_128_CBC_SHA256", "openssl_name": "ADH-AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6C", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DH_ANON_AES_128_GCM_SHA256", "openssl_name": "ADH-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xA6", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_AES_256_CBC_SHA1", "openssl_name": "ADH-AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x3A", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_AES_256_CBC_SHA256", "openssl_name": "ADH-AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6D", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DH_ANON_AES_256_GCM_SHA384", "openssl_name": "ADH-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xA7", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x46", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5A", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x47", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5B", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_128_CBC_SHA1", "openssl_name": "ADH-CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x46", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_128_CBC_SHA256", "openssl_name": "ADH-CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBF", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x84", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_256_CBC_SHA1", "openssl_name": "ADH-CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x89", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_256_CBC_SHA256", "openssl_name": "ADH-CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC5", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DH_ANON_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x85", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x1A", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_RC4_128_MD5": {"gnutls_name": "TLS_DH_ANON_ARCFOUR_128_MD5", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x18", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "RC4 128", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_anon_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "ADH-SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x9B", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "anon", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0B", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0D", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x30", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x3E", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA4", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x36", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x68", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA5", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3E", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x58", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x59", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x42", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xBB", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x82", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x85", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC1", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x83", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0C", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_DSS_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x97", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "DSS", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x11", "protocol_version": "TLS EXPORT", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_3DES_EDE_CBC_SHA1", "openssl_name": "DHE-DSS-DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x13", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_AES_128_CBC_SHA1", "openssl_name": "DHE-DSS-AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x32", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_AES_128_CBC_SHA256", "openssl_name": "DHE-DSS-AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x40", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_DSS_AES_128_GCM_SHA256", "openssl_name": "DHE-DSS-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xA2", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_AES_256_CBC_SHA1", "openssl_name": "DHE-DSS-AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x38", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_AES_256_CBC_SHA256", "openssl_name": "DHE-DSS-AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6A", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_DSS_AES_256_GCM_SHA384", "openssl_name": "DHE-DSS-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xA3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x42", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x56", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x43", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x57", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_128_CBC_SHA1", "openssl_name": "DHE-DSS-CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x44", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_128_CBC_SHA256", "openssl_name": "DHE-DSS-CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBD", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x80", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_256_CBC_SHA1", "openssl_name": "DHE-DSS-CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x87", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_256_CBC_SHA256", "openssl_name": "DHE-DSS-CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_DSS_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x81", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x12", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_DSS_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "DHE-DSS-SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x99", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "DSS", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DHE_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "DHE-PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8F", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DHE_PSK_AES_128_CBC_SHA1", "openssl_name": "DHE-PSK-AES128-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x90", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_PSK_AES_128_CBC_SHA256", "openssl_name": "DHE-PSK-AES128-CBC-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB2", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_CCM": {"gnutls_name": "TLS_DHE_PSK_AES_128_CCM", "openssl_name": "DHE-PSK-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA6", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_PSK_AES_128_GCM_SHA256", "openssl_name": "DHE-PSK-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xAA", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DHE_PSK_AES_256_CBC_SHA1", "openssl_name": "DHE-PSK-AES256-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x91", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_DHE_PSK_AES_256_CBC_SHA384", "openssl_name": "DHE-PSK-AES256-CBC-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_CCM": {"gnutls_name": "TLS_DHE_PSK_AES_256_CCM", "openssl_name": "DHE-PSK-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA7", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_PSK_AES_256_GCM_SHA384", "openssl_name": "DHE-PSK-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xAB", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x66", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6C", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x67", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6D", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "DHE-PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x96", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x90", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "DHE-PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x97", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_PSK_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x91", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_DHE_PSK_CHACHA20_POLY1305", "openssl_name": "DHE-PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAD", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_DHE_PSK_NULL_SHA1", "openssl_name": "DHE-PSK-NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2D", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_DHE_PSK_NULL_SHA256", "openssl_name": "DHE-PSK-NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB4", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_DHE_PSK_NULL_SHA384", "openssl_name": "DHE-PSK-NULL-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB5", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_DHE_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x8E", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x14", "protocol_version": "TLS EXPORT", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "DHE-RSA-DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x16", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_AES_128_CBC_SHA1", "openssl_name": "DHE-RSA-AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x33", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_AES_128_CBC_SHA256", "openssl_name": "DHE-RSA-AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x67", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CCM": {"gnutls_name": "TLS_DHE_RSA_AES_128_CCM", "openssl_name": "DHE-RSA-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9E", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_DHE_RSA_AES_128_CCM_8", "openssl_name": "DHE-RSA-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA2", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_RSA_AES_128_GCM_SHA256", "openssl_name": "DHE-RSA-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x9E", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_AES_256_CBC_SHA1", "openssl_name": "DHE-RSA-AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x39", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_AES_256_CBC_SHA256", "openssl_name": "DHE-RSA-AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x6B", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CCM": {"gnutls_name": "TLS_DHE_RSA_AES_256_CCM", "openssl_name": "DHE-RSA-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9F", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_DHE_RSA_AES_256_CCM_8", "openssl_name": "DHE-RSA-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA3", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_RSA_AES_256_GCM_SHA384", "openssl_name": "DHE-RSA-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0x9F", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x44", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x52", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x45", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x53", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_128_CBC_SHA1", "openssl_name": "DHE-RSA-CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x45", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "DHE-RSA-CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBE", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7C", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_256_CBC_SHA1", "openssl_name": "DHE-RSA-CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x88", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_256_CBC_SHA256", "openssl_name": "DHE-RSA-CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC4", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_DHE_RSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7D", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_DHE_RSA_CHACHA20_POLY1305", "openssl_name": "DHE-RSA-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAA", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x15", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DHE_RSA_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "DHE-RSA-SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x9A", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "RSA", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0E", "protocol_version": "TLS EXPORT", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x10", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x31", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x3F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA0", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x37", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x69", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xA1", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x40", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x54", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x41", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x55", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x43", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xBC", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7E", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x86", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC2", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x0F", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_DH_RSA_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x98", "protocol_version": "TLS", "kex_algorithm": "DH", "auth_algorithm": "RSA", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_128_CCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB2", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB0", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_256_CCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB3", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECCPWD_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB1", "protocol_version": "TLS", "kex_algorithm": "ECCPWD", "auth_algorithm": "ECCPWD", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDH_ANON_3DES_EDE_CBC_SHA1", "openssl_name": "AECDH-DES-CBC3-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x17", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDH_ANON_AES_128_CBC_SHA1", "openssl_name": "AECDH-AES128-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x18", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDH_ANON_AES_256_CBC_SHA1", "openssl_name": "AECDH-AES256-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x19", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDH_ANON_NULL_SHA1", "openssl_name": "AECDH-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x15", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_anon_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDH_ANON_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x16", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "anon", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x25", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x2D", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x26", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x2E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4A", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4B", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5F", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x74", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x88", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x75", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x89", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_NULL_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_ECDSA_WITH_RC4_128_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "ECDSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA1", "openssl_name": "ECDHE-ECDSA-DES-CBC3-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x08", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CBC_SHA1", "openssl_name": "ECDHE-ECDSA-AES128-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x09", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CBC_SHA256", "openssl_name": "ECDHE-ECDSA-AES128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x23", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CCM": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CCM", "openssl_name": "ECDHE-ECDSA-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xAC", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_CCM_8", "openssl_name": "ECDHE-ECDSA-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAE", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_128_GCM_SHA256", "openssl_name": "ECDHE-ECDSA-AES128-GCM-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x2B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CBC_SHA1", "openssl_name": "ECDHE-ECDSA-AES256-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x0A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CBC_SHA384", "openssl_name": "ECDHE-ECDSA-AES256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x24", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CCM": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CCM", "openssl_name": "ECDHE-ECDSA-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xAD", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_CCM_8", "openssl_name": "ECDHE-ECDSA-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAF", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_AES_256_GCM_SHA384", "openssl_name": "ECDHE-ECDSA-AES256-GCM-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x2C", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x48", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5C", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x49", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x5D", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "ECDHE-ECDSA-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x72", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x86", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_256_CBC_SHA384", "openssl_name": "ECDHE-ECDSA-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x73", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_ECDSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x87", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_ECDHE_ECDSA_CHACHA20_POLY1305", "openssl_name": "ECDHE-ECDSA-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xA9", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_NULL_SHA1", "openssl_name": "ECDHE-ECDSA-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x06", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDHE_ECDSA_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x07", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "ECDSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDHE_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "ECDHE-PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x34", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDHE_PSK_AES_128_CBC_SHA1", "openssl_name": "ECDHE-PSK-AES128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x35", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_AES_128_CBC_SHA256", "openssl_name": "ECDHE-PSK-AES128-CBC-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x37", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDHE_PSK_AES_256_CBC_SHA1", "openssl_name": "ECDHE-PSK-AES256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x36", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_PSK_AES_256_CBC_SHA384", "openssl_name": "ECDHE-PSK-AES256-CBC-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x38", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xD0", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x70", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x71", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "ECDHE-PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x9A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "ECDHE-PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x9B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_CHACHA20_POLY1305", "openssl_name": "ECDHE-PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAC", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "recommended", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDHE_PSK_NULL_SHA1", "openssl_name": "ECDHE-PSK-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x39", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_ECDHE_PSK_NULL_SHA256", "openssl_name": "ECDHE-PSK-NULL-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x3A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_ECDHE_PSK_NULL_SHA384", "openssl_name": "ECDHE-PSK-NULL-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x3B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDHE_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x33", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_ECDHE_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "ECDHE-RSA-DES-CBC3-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x12", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_ECDHE_RSA_AES_128_CBC_SHA1", "openssl_name": "ECDHE-RSA-AES128-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x13", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_AES_128_CBC_SHA256", "openssl_name": "ECDHE-RSA-AES128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x27", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_AES_128_GCM_SHA256", "openssl_name": "ECDHE-RSA-AES128-GCM-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x2F", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_ECDHE_RSA_AES_256_CBC_SHA1", "openssl_name": "ECDHE-RSA-AES256-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x14", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_AES_256_CBC_SHA384", "openssl_name": "ECDHE-RSA-AES256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x28", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_AES_256_GCM_SHA384", "openssl_name": "ECDHE-RSA-AES256-GCM-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x30", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4C", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x60", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4D", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x61", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "ECDHE-RSA-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x76", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8A", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_256_CBC_SHA384", "openssl_name": "ECDHE-RSA-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x77", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_ECDHE_RSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8B", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_ECDHE_RSA_CHACHA20_POLY1305", "openssl_name": "ECDHE-RSA-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xA8", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "secure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_NULL_SHA": {"gnutls_name": "TLS_ECDHE_RSA_NULL_SHA1", "openssl_name": "ECDHE-RSA-NULL-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x10", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDHE_RSA_WITH_RC4_128_SHA": {"gnutls_name": "TLS_ECDHE_RSA_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x11", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0D", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x29", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x31", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0F", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x2A", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x32", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4E", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x62", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x4F", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x63", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x78", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8C", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x79", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8D", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_NULL_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0B", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_ECDH_RSA_WITH_RC4_128_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x0C", "protocol_version": "TLS", "kex_algorithm": "ECDH", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_28147_CNT_IMIT": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "GOSTR341112 256", "auth_algorithm": "GOSTR341012", "enc_algorithm": "28147 CNT", "hash_algorithm": "GOSTR341112", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x00", "protocol_version": "TLS", "kex_algorithm": "GOSTR341112 256", "auth_algorithm": "GOSTR341012", "enc_algorithm": "KUZNYECHIK CTR", "hash_algorithm": "GOSTR341112", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x03", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "KUZNYECHIK MGM L", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "KUZNYECHIK MGM S", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "GOSTR341112 256", "auth_algorithm": "GOSTR341012", "enc_algorithm": "MAGMA CTR", "hash_algorithm": "GOSTR341112", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_MAGMA_MGM_L": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "MAGMA MGM L", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_GOSTR341112_256_WITH_MAGMA_MGM_S": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC1", "hex_byte_2": "0x06", "protocol_version": "TLS", "kex_algorithm": "ECDHE", "auth_algorithm": "-", "enc_algorithm": "MAGMA MGM S", "hash_algorithm": "-", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x29", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x26", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC 40", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x2A", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC2 CBC 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x27", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC2 CBC 40", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC4_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x2B", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_EXPORT_WITH_RC4_40_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x28", "protocol_version": "TLS EXPORT", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 40", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_3DES_EDE_CBC_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x23", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x1F", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_DES_CBC_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x22", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x1E", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_IDEA_CBC_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x25", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "IDEA CBC", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_IDEA_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x21", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "IDEA CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_RC4_128_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x24", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 128", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_KRB5_WITH_RC4_128_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x20", "protocol_version": "TLS", "kex_algorithm": "KRB5", "auth_algorithm": "KRB5", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_NULL_WITH_NULL_NULL": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x00", "protocol_version": "TLS", "kex_algorithm": "NULL", "auth_algorithm": "NULL", "enc_algorithm": "NULL", "hash_algorithm": "NULL", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_DHE_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_DHE_PSK_AES_128_CCM_8", "openssl_name": "DHE-PSK-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAA", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_DHE_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_DHE_PSK_AES_256_CCM_8", "openssl_name": "DHE-PSK-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xAB", "protocol_version": "TLS", "kex_algorithm": "DHE", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8B", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_PSK_AES_128_CBC_SHA1", "openssl_name": "PSK-AES128-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8C", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_PSK_AES_128_CBC_SHA256", "openssl_name": "PSK-AES128-CBC-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xAE", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CCM": {"gnutls_name": "TLS_PSK_AES_128_CCM", "openssl_name": "PSK-AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA4", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_PSK_AES_128_CCM_8", "openssl_name": "PSK-AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA8", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_PSK_AES_128_GCM_SHA256", "openssl_name": "PSK-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xA8", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_PSK_AES_256_CBC_SHA1", "openssl_name": "PSK-AES256-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x8D", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_PSK_AES_256_CBC_SHA384", "openssl_name": "PSK-AES256-CBC-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xAF", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CCM": {"gnutls_name": "TLS_PSK_AES_256_CCM", "openssl_name": "PSK-AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0xA5", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_PSK_AES_256_CCM_8", "openssl_name": "PSK-AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA9", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_PSK_AES_256_GCM_SHA384", "openssl_name": "PSK-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xA9", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x64", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6A", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x65", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6B", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x94", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_PSK_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8E", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x95", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_PSK_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x8F", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_PSK_CHACHA20_POLY1305", "openssl_name": "PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAB", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_PSK_NULL_SHA1", "openssl_name": "PSK-NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2C", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_PSK_NULL_SHA256", "openssl_name": "PSK-NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB0", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_PSK_NULL_SHA384", "openssl_name": "PSK-NULL-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB1", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x8A", "protocol_version": "TLS", "kex_algorithm": "PSK", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_EXPORT_WITH_DES40_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x08", "protocol_version": "TLS EXPORT", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "DES40 CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x06", "protocol_version": "TLS EXPORT", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC2 CBC 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_EXPORT_WITH_RC4_40_MD5": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x03", "protocol_version": "TLS EXPORT", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC4 40", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_RSA_PSK_3DES_EDE_CBC_SHA1", "openssl_name": "RSA-PSK-3DES-EDE-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x93", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_RSA_PSK_AES_128_CBC_SHA1", "openssl_name": "RSA-PSK-AES128-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x94", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_PSK_AES_128_CBC_SHA256", "openssl_name": "RSA-PSK-AES128-CBC-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB6", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_PSK_AES_128_GCM_SHA256", "openssl_name": "RSA-PSK-AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xAC", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_RSA_PSK_AES_256_CBC_SHA1", "openssl_name": "RSA-PSK-AES256-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x95", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_256_CBC_SHA384": {"gnutls_name": "TLS_RSA_PSK_AES_256_CBC_SHA384", "openssl_name": "RSA-PSK-AES256-CBC-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB7", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_PSK_AES_256_GCM_SHA384", "openssl_name": "RSA-PSK-AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xAD", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x68", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6E", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x69", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x6F", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_128_CBC_SHA256", "openssl_name": "RSA-PSK-CAMELLIA128-SHA256", "hex_byte_1": "0xC0", "hex_byte_2": "0x98", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x92", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_256_CBC_SHA384", "openssl_name": "RSA-PSK-CAMELLIA256-SHA384", "hex_byte_1": "0xC0", "hex_byte_2": "0x99", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_PSK_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x93", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256": {"gnutls_name": "TLS_RSA_PSK_CHACHA20_POLY1305", "openssl_name": "RSA-PSK-CHACHA20-POLY1305", "hex_byte_1": "0xCC", "hex_byte_2": "0xAE", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "CHACHA20 POLY1305", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_NULL_SHA": {"gnutls_name": "TLS_RSA_PSK_NULL_SHA1", "openssl_name": "RSA-PSK-NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2E", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_NULL_SHA256": {"gnutls_name": "TLS_RSA_PSK_NULL_SHA256", "openssl_name": "RSA-PSK-NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xB8", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_NULL_SHA384": {"gnutls_name": "TLS_RSA_PSK_NULL_SHA384", "openssl_name": "RSA-PSK-NULL-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0xB9", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_PSK_WITH_RC4_128_SHA": {"gnutls_name": "TLS_RSA_PSK_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x92", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "PSK", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "DES-CBC3-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x0A", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_RSA_AES_128_CBC_SHA1", "openssl_name": "AES128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x2F", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_AES_128_CBC_SHA256", "openssl_name": "AES128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x3C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CCM": {"gnutls_name": "TLS_RSA_AES_128_CCM", "openssl_name": "AES128-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_CCM_8": {"gnutls_name": "TLS_RSA_AES_128_CCM_8", "openssl_name": "AES128-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA0", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_AES_128_GCM_SHA256", "openssl_name": "AES128-GCM-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x9C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_RSA_AES_256_CBC_SHA1", "openssl_name": "AES256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x35", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CBC_SHA256": {"gnutls_name": "TLS_RSA_AES_256_CBC_SHA256", "openssl_name": "AES256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x3D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CCM": {"gnutls_name": "TLS_RSA_AES_256_CCM", "openssl_name": "AES256-CCM", "hex_byte_1": "0xC0", "hex_byte_2": "0x9D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_CCM_8": {"gnutls_name": "TLS_RSA_AES_256_CCM_8", "openssl_name": "AES256-CCM8", "hex_byte_1": "0xC0", "hex_byte_2": "0xA1", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 CCM 8", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_AES_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_AES_256_GCM_SHA384", "openssl_name": "AES256-GCM-SHA384", "hex_byte_1": "0x00", "hex_byte_2": "0x9D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "AES 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_128_CBC_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3C", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_128_GCM_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x50", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_256_CBC_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x3D", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 CBC", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_ARIA_256_GCM_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x51", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "ARIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA": {"gnutls_name": "TLS_RSA_CAMELLIA_128_CBC_SHA1", "openssl_name": "CAMELLIA128-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x41", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256": {"gnutls_name": "TLS_RSA_CAMELLIA_128_CBC_SHA256", "openssl_name": "CAMELLIA128-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xBA", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256": {"gnutls_name": "TLS_RSA_CAMELLIA_128_GCM_SHA256", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7A", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 128 GCM", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA": {"gnutls_name": "TLS_RSA_CAMELLIA_256_CBC_SHA1", "openssl_name": "CAMELLIA256-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x84", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256": {"gnutls_name": "TLS_RSA_CAMELLIA_256_CBC_SHA256", "openssl_name": "CAMELLIA256-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0xC0", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 CBC", "hash_algorithm": "SHA256", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384": {"gnutls_name": "TLS_RSA_CAMELLIA_256_GCM_SHA384", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0x7B", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "CAMELLIA 256 GCM", "hash_algorithm": "SHA384", "security": "weak", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_DES_CBC_SHA": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x09", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "DES CBC", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_IDEA_CBC_SHA": {"gnutls_name": "", "openssl_name": "IDEA-CBC-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x07", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "IDEA CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_NULL_MD5": {"gnutls_name": "TLS_RSA_NULL_MD5", "openssl_name": "NULL-MD5", "hex_byte_1": "0x00", "hex_byte_2": "0x01", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_NULL_SHA": {"gnutls_name": "TLS_RSA_NULL_SHA1", "openssl_name": "NULL-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x02", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_NULL_SHA256": {"gnutls_name": "TLS_RSA_NULL_SHA256", "openssl_name": "NULL-SHA256", "hex_byte_1": "0x00", "hex_byte_2": "0x3B", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_RC4_128_MD5": {"gnutls_name": "TLS_RSA_ARCFOUR_128_MD5", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x04", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "MD5", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_RC4_128_SHA": {"gnutls_name": "TLS_RSA_ARCFOUR_128_SHA1", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0x05", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "RC4 128", "hash_algorithm": "SHA", "security": "insecure", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_RSA_WITH_SEED_CBC_SHA": {"gnutls_name": "", "openssl_name": "SEED-SHA", "hex_byte_1": "0x00", "hex_byte_2": "0x96", "protocol_version": "TLS", "kex_algorithm": "RSA", "auth_algorithm": "RSA", "enc_algorithm": "SEED CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SHA256_SHA256": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB4", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "SHA256", "enc_algorithm": "NULL", "hash_algorithm": "SHA256", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SHA384_SHA384": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0xC0", "hex_byte_2": "0xB5", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "SHA384", "enc_algorithm": "NULL", "hash_algorithm": "SHA384", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SM4_CCM_SM3": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC7", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "SM4 CCM", "hash_algorithm": "SM3", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SM4_GCM_SM3": {"gnutls_name": "", "openssl_name": "", "hex_byte_1": "0x00", "hex_byte_2": "0xC6", "protocol_version": "TLS", "kex_algorithm": "-", "auth_algorithm": "-", "enc_algorithm": "SM4 GCM", "hash_algorithm": "SM3", "security": "insecure", "tls_version": ["TLS1.3"]}}, {"TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1", "openssl_name": "SRP-DSS-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1C", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA DSS", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_DSS_AES_128_CBC_SHA1", "openssl_name": "SRP-DSS-AES-128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1F", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA DSS", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_DSS_AES_256_CBC_SHA1", "openssl_name": "SRP-DSS-AES-256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x22", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA DSS", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1", "openssl_name": "SRP-RSA-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1B", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA RSA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_RSA_AES_128_CBC_SHA1", "openssl_name": "SRP-RSA-AES-128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1E", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA RSA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_RSA_AES_256_CBC_SHA1", "openssl_name": "SRP-RSA-AES-256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x21", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA RSA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_3DES_EDE_CBC_SHA1", "openssl_name": "SRP-3DES-EDE-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1A", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA", "enc_algorithm": "3DES EDE CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_WITH_AES_128_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_AES_128_CBC_SHA1", "openssl_name": "SRP-AES-128-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x1D", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA", "enc_algorithm": "AES 128 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}, {"TLS_SRP_SHA_WITH_AES_256_CBC_SHA": {"gnutls_name": "TLS_SRP_SHA_AES_256_CBC_SHA1", "openssl_name": "SRP-AES-256-CBC-SHA", "hex_byte_1": "0xC0", "hex_byte_2": "0x20", "protocol_version": "TLS", "kex_algorithm": "SRP", "auth_algorithm": "SHA", "enc_algorithm": "AES 256 CBC", "hash_algorithm": "SHA", "security": "weak", "tls_version": ["TLS1.0", "TLS1.1", "TLS1.2", "TLS1.3"]}}]} \ No newline at end of file diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java index f0b616838..738fd0e9b 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCipherMapper.java @@ -37,6 +37,7 @@ import com.ibm.mapper.model.algorithms.Salsa20; import com.ibm.mapper.model.algorithms.TripleDES; import com.ibm.mapper.model.algorithms.cast.CAST128; +import com.ibm.mapper.model.mode.GCM; import com.ibm.mapper.utils.DetectionLocation; import java.util.Optional; import javax.annotation.Nonnull; @@ -55,6 +56,10 @@ public final class PycaCipherMapper implements IMapper { case "AES" -> Optional.of(new AES(detectionLocation)); case "AES128" -> Optional.of(new AES(128, detectionLocation)); case "AES256" -> Optional.of(new AES(256, detectionLocation)); + case "AES128_GCM" -> + Optional.of(new AES(128, new GCM(detectionLocation), detectionLocation)); + case "AES256_GCM" -> + Optional.of(new AES(256, new GCM(detectionLocation), detectionLocation)); case "CAMELLIA" -> Optional.of(new Camellia(detectionLocation)); case "TRIPLEDES", "3DES" -> Optional.of(new TripleDES(detectionLocation)); case "DES" -> Optional.of(new DES(detectionLocation)); @@ -69,7 +74,8 @@ public final class PycaCipherMapper implements IMapper { case "RC2" -> Optional.of(new RC2(detectionLocation)); case "FERNET" -> Optional.of(new Fernet(detectionLocation)); case "RSA" -> Optional.of(new RSA(detectionLocation)); - case "CHACHA20POLY1305" -> Optional.of(new ChaCha20Poly1305(detectionLocation)); + case "CHACHA20POLY1305", "CHACHA20_POLY1305" -> + Optional.of(new ChaCha20Poly1305(detectionLocation)); default -> Optional.empty(); }; } diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/ssl/json/JsonCipherSuites.java b/mapper/src/main/java/com/ibm/mapper/mapper/ssl/json/JsonCipherSuites.java index b94d3d1a3..8bcc4a6bf 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/ssl/json/JsonCipherSuites.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/ssl/json/JsonCipherSuites.java @@ -41,6 +41,17 @@ private JsonCipherSuites() { null, "AES 128 CCM 8", "SHA256")), + Map.entry( + "TLS_AES_128_CCM_ASCONHASH256", + new JsonCipherSuite( + "TLS_AES_128_CCM_ASCONHASH256", + null, + null, + new String[] {"0x00", "0x71"}, + "AES", + "128 CCM ASCONHASH256", + null, + null)), Map.entry( "TLS_AES_128_CCM_SHA256", new JsonCipherSuite( @@ -52,6 +63,17 @@ private JsonCipherSuites() { null, "AES 128 CCM", "SHA256")), + Map.entry( + "TLS_AES_128_GCM_ASCONHASH256", + new JsonCipherSuite( + "TLS_AES_128_GCM_ASCONHASH256", + null, + null, + new String[] {"0x00", "0x70"}, + "AES", + "128 GCM ASCONHASH256", + null, + null)), Map.entry( "TLS_AES_128_GCM_SHA256", new JsonCipherSuite( @@ -74,6 +96,17 @@ private JsonCipherSuites() { null, "AES 256 GCM", "SHA384")), + Map.entry( + "TLS_ASCONAEAD128_SHA256", + new JsonCipherSuite( + "TLS_ASCONAEAD128_SHA256", + null, + null, + new String[] {"0x00", "0x6F"}, + "ASCONAEAD128", + "SHA256", + null, + null)), Map.entry( "TLS_CHACHA20_POLY1305_SHA256", new JsonCipherSuite( diff --git a/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java b/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java index 4e434e932..f59e8a204 100644 --- a/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java +++ b/mapper/src/main/java/com/ibm/mapper/reorganizer/rules/SignatureReorganizer.java @@ -35,7 +35,6 @@ import com.ibm.mapper.reorganizer.builder.ReorganizerRuleBuilder; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Optional; import javax.annotation.Nonnull; @@ -194,12 +193,17 @@ public static IReorganizerRule moveNodesFromUnderFunctionalityUnderNode( .flatMap(p -> p.hasChildOfType(underNodeClazz)) .ifPresent( n -> { - for (Map.Entry, INode> - childKeyValue : - node.getChildren().entrySet()) { - n.put(childKeyValue.getValue()); - node.removeChildOfType(childKeyValue.getKey()); - } + // Avoids java.util.ConcurrentModificationException + // thrown by original code + node.getChildren().values().forEach(n::put); + node.getChildren().clear(); + // for (Map.Entry, INode> + // childKeyValue : + // node.getChildren().entrySet()) { + // n.put(childKeyValue.getValue()); + // + // node.removeChildOfType(childKeyValue.getKey()); + // } }); return null; }); diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java b/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java index 4d774d79d..eeb3c16ce 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/PythonDetectionRules.java @@ -20,27 +20,28 @@ package com.ibm.plugin.rules.detection; import com.ibm.engine.rule.IDetectionRule; -import com.ibm.plugin.rules.detection.aead.PycaAEAD; -import com.ibm.plugin.rules.detection.aead.PycaAES; -import com.ibm.plugin.rules.detection.asymmetric.PycaDSA; -import com.ibm.plugin.rules.detection.asymmetric.PycaDiffieHellman; -import com.ibm.plugin.rules.detection.asymmetric.PycaEllipticCurve; -import com.ibm.plugin.rules.detection.asymmetric.PycaRSA; -import com.ibm.plugin.rules.detection.asymmetric.PycaSign; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoCipher; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoHash; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoKDF; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoKeyAgreement; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoMac; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoPublicKey; -import com.ibm.plugin.rules.detection.crypto.PythonCryptoSignature; -import com.ibm.plugin.rules.detection.fernet.PycaFernet; -import com.ibm.plugin.rules.detection.hash.PycaHash; -import com.ibm.plugin.rules.detection.kdf.PycaKDF; -import com.ibm.plugin.rules.detection.keyagreement.PycaKeyAgreement; -import com.ibm.plugin.rules.detection.mac.PycaMAC; -import com.ibm.plugin.rules.detection.symmetric.PycaCipher; -import com.ibm.plugin.rules.detection.wrapping.PycaWrapping; +import com.ibm.plugin.rules.detection.pyca.aead.PycaAEAD; +import com.ibm.plugin.rules.detection.pyca.aead.PycaAES; +import com.ibm.plugin.rules.detection.pyca.asymmetric.PycaDSA; +import com.ibm.plugin.rules.detection.pyca.asymmetric.PycaDiffieHellman; +import com.ibm.plugin.rules.detection.pyca.asymmetric.PycaEllipticCurve; +import com.ibm.plugin.rules.detection.pyca.asymmetric.PycaRSA; +import com.ibm.plugin.rules.detection.pyca.asymmetric.PycaSign; +import com.ibm.plugin.rules.detection.pyca.fernet.PycaFernet; +import com.ibm.plugin.rules.detection.pyca.hash.PycaHash; +import com.ibm.plugin.rules.detection.pyca.kdf.PycaKDF; +import com.ibm.plugin.rules.detection.pyca.keyagreement.PycaKeyAgreement; +import com.ibm.plugin.rules.detection.pyca.mac.PycaMAC; +import com.ibm.plugin.rules.detection.pyca.symmetric.PycaCipher; +import com.ibm.plugin.rules.detection.pyca.wrapping.PycaWrapping; +import com.ibm.plugin.rules.detection.pycrypto.cipher.PythonCryptoCipher; +import com.ibm.plugin.rules.detection.pycrypto.hash.PythonCryptoHash; +import com.ibm.plugin.rules.detection.pycrypto.kdf.PythonCryptoKDF; +import com.ibm.plugin.rules.detection.pycrypto.keyagreement.PythonCryptoKeyAgreement; +import com.ibm.plugin.rules.detection.pycrypto.mac.PythonCryptoMac; +import com.ibm.plugin.rules.detection.pycrypto.publickey.PythonCryptoPublicKey; +import com.ibm.plugin.rules.detection.pycrypto.random.PythonCryptoRandom; +import com.ibm.plugin.rules.detection.pycrypto.signature.PythonCryptoSignature; import java.util.List; import java.util.function.Supplier; import java.util.stream.Stream; @@ -80,6 +81,7 @@ private static List> buildRules() { PycaFernet.rules().stream(), PythonCryptoHash.rules().stream(), PythonCryptoMac.rules().stream(), + PythonCryptoRandom.rules().stream(), PythonCryptoCipher.rules().stream(), PythonCryptoPublicKey.rules().stream(), PythonCryptoSignature.rules().stream(), diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java index 8f08681d1..2190bca07 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java @@ -227,6 +227,44 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + private static final IDetectionRule SEAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("seal") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.ENCRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule UNSEAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("unseal") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.DECRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule HPKE_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectExactTypes("Crypto.Protocol.HPKE") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("HPKE")) + .withMethodParameter(ANY) + .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) + .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SEAL, UNSEAL)); + @Nonnull public static List> rules() { return List.of( @@ -242,6 +280,7 @@ public static List> rules() { SALSA20_NEW, PKCS1_OAEP_NEW, // PKCS1_OAEP_NEW_WITH_HASH, - PKCS1_V1_5_NEW); + PKCS1_V1_5_NEW, + HPKE_NEW); } } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/aead/PycaAEAD.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAEAD.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/aead/PycaAEAD.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAEAD.java index 1b1a9812a..5c15bc309 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/aead/PycaAEAD.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAEAD.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.aead; +package com.ibm.plugin.rules.detection.pyca.aead; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.KeyAction; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/aead/PycaAES.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAES.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/aead/PycaAES.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAES.java index 93d7dc0c5..85e16955f 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/aead/PycaAES.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAES.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.aead; +package com.ibm.plugin.rules.detection.pyca.aead; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.Size; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaDSA.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDSA.java similarity index 100% rename from python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaDSA.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDSA.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaDiffieHellman.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDiffieHellman.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaDiffieHellman.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDiffieHellman.java index ae1fef88d..cabfe6b03 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaDiffieHellman.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDiffieHellman.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric; +package com.ibm.plugin.rules.detection.pyca.asymmetric; import static com.ibm.engine.detection.MethodMatcher.ANY; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaEllipticCurve.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaEllipticCurve.java similarity index 100% rename from python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaEllipticCurve.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaEllipticCurve.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaRSA.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaRSA.java similarity index 100% rename from python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaRSA.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaRSA.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaSign.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaSign.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaSign.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaSign.java index 6b50bf24a..7e910e632 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/asymmetric/PycaSign.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaSign.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric; +package com.ibm.plugin.rules.detection.pyca.asymmetric; import com.ibm.engine.model.KeyAction; import com.ibm.engine.model.context.PrivateKeyContext; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/fernet/PycaFernet.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernet.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/fernet/PycaFernet.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernet.java index a1eb299f9..4a4fcf607 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/fernet/PycaFernet.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernet.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.fernet; +package com.ibm.plugin.rules.detection.pyca.fernet; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.KeyAction; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/hash/PycaHash.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/hash/PycaHash.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java index 27aead4c7..8d5238928 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/hash/PycaHash.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.hash; +package com.ibm.plugin.rules.detection.pyca.hash; import com.ibm.engine.model.context.DigestContext; import com.ibm.engine.model.factory.AlgorithmFactory; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/kdf/PycaKDF.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKDF.java similarity index 99% rename from python/src/main/java/com/ibm/plugin/rules/detection/kdf/PycaKDF.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKDF.java index 2c2dc8a3c..ae099981a 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/kdf/PycaKDF.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKDF.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static com.ibm.engine.detection.MethodMatcher.ANY; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/keyagreement/PycaKeyAgreement.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/keyagreement/PycaKeyAgreement.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/keyagreement/PycaKeyAgreement.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/keyagreement/PycaKeyAgreement.java index 127c0bca2..13d48c151 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/keyagreement/PycaKeyAgreement.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/keyagreement/PycaKeyAgreement.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.keyagreement; +package com.ibm.plugin.rules.detection.pyca.keyagreement; import com.ibm.engine.model.KeyAction; import com.ibm.engine.model.context.KeyAgreementContext; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/mac/PycaMAC.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/mac/PycaMAC.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/mac/PycaMAC.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/mac/PycaMAC.java index 4cbedf859..20b477869 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/mac/PycaMAC.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/mac/PycaMAC.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.mac; +package com.ibm.plugin.rules.detection.pyca.mac; import static com.ibm.engine.detection.MethodMatcher.ANY; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/padding/PycaPadding.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPadding.java similarity index 100% rename from python/src/main/java/com/ibm/plugin/rules/detection/padding/PycaPadding.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPadding.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher.java similarity index 100% rename from python/src/main/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/wrapping/PycaWrapping.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrapping.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/wrapping/PycaWrapping.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrapping.java index 7ffd52972..18f782847 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/wrapping/PycaWrapping.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrapping.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.wrapping; +package com.ibm.plugin.rules.detection.pyca.wrapping; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.context.CipherContext; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java new file mode 100644 index 000000000..1755e2517 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java @@ -0,0 +1,287 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static com.ibm.engine.detection.MethodMatcher.ANY; + +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.CipherActionFactory; +import com.ibm.engine.model.factory.ModeFactory; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoCipher { + + private PythonCryptoCipher() { + // private + } + + private static final IDetectionRule ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("encrypt") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.ENCRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("decrypt") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.DECRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.AES") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("AES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.AES.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.DES") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("DES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.DES.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES3_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.DES3") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("3DES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.DES3.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule BLOWFISH_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.Blowfish") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("Blowfish")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.Blowfish.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule CAST_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.CAST") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.CAST.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule ARC2_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ARC2") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.ARC2.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule ARC4_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ARC4") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4")) + .withAnyParameters() + .buildForContext(new CipherContext(Map.of("algorithm", "RC4"))) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule CHACHA20_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ChaCha20") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule CHACHA20_POLY1305_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ChaCha20_Poly1305") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20Poly1305")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule SALSA20_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.Salsa20") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("Salsa20")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule PKCS1_OAEP_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) + .withAnyParameters() // This must be changed if the rule below is enabled. + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + // // Variant with hash algo. This detects the hash but it won't be mapped. + // private static final IDetectionRule PKCS1_OAEP_NEW_WITH_HASH = + // new DetectionRuleBuilder() + // .createDetectionRule() + // .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") + // .forMethods("new") + // .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) + // .withMethodParameter(ANY) // key + // .withMethodParameter("Crypto.Hash.*") + // .shouldBeDetectedAs(new AlgorithmFactory<>()) + // .asChildOfParameterWithId(-1) + // .buildForContext(new CipherContext()) + // .inBundle(() -> "PyCrypto") + // .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule PKCS1_V1_5_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectExactTypes("Crypto.Cipher.PKCS1_v1_5") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_v1_5")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule SEAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("seal") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.ENCRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule UNSEAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes(ANY) + .forMethods("unseal") + .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.DECRYPT)) + .withMethodParameter(ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule HPKE_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectExactTypes("Crypto.Protocol.HPKE") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("HPKE")) + .withMethodParameter(ANY) + .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + // .addDependingDetectionRules(PythonCryptoPublicKey.ECCRules()) + .withMethodParameter(ANY) + .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SEAL, UNSEAL)); + + @Nonnull + public static List> rules() { + return List.of( + AES_NEW, + DES_NEW, + DES3_NEW, + BLOWFISH_NEW, + CAST_NEW, + ARC2_NEW, + ARC4_NEW, + CHACHA20_NEW, + CHACHA20_POLY1305_NEW, + SALSA20_NEW, + PKCS1_OAEP_NEW, + // PKCS1_OAEP_NEW_WITH_HASH, + PKCS1_V1_5_NEW, + HPKE_NEW); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java index 29a2d6673..56fec946e 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHash.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.crypto; +package com.ibm.plugin.rules.detection.pycrypto.hash; import com.ibm.engine.model.context.DigestContext; import com.ibm.engine.model.factory.ValueActionFactory; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java similarity index 99% rename from python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java index c841d624f..e665fa794 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDF.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.crypto; +package com.ibm.plugin.rules.detection.pycrypto.kdf; import static com.ibm.engine.detection.MethodMatcher.ANY; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java index 6135770b3..27ce1487f 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreement.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.crypto; +package com.ibm.plugin.rules.detection.pycrypto.keyagreement; import com.ibm.engine.model.KeyAction; import com.ibm.engine.model.context.KeyAgreementContext; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java similarity index 98% rename from python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java index 58b3af4c4..8eaa98d7d 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMac.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.crypto; +package com.ibm.plugin.rules.detection.pycrypto.mac; import static com.ibm.engine.detection.MethodMatcher.ANY; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java similarity index 87% rename from python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java index b06a2819c..37abb4456 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKey.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.crypto; +package com.ibm.plugin.rules.detection.pycrypto.publickey; import com.ibm.engine.model.KeyAction; import com.ibm.engine.model.Size; @@ -175,6 +175,32 @@ private PythonCryptoPublicKey() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); + // EdDSA import private key + private static final IDetectionRule EDDSA_IMPORT_PRIVATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.eddsa") + .forMethods("import_private_key") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PRIVATE_KEY_GENERATION)) + .withAnyParameters() + .buildForContext(new PrivateKeyContext(Map.of("algorithm", "ECC"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + // EdDSA import public key + private static final IDetectionRule EDDSA_IMPORT_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.eddsa") + .forMethods("import_public_key") + .shouldBeDetectedAs( + new KeyActionFactory<>(KeyAction.Action.PUBLIC_KEY_GENERATION)) + .withAnyParameters() + .buildForContext(new PublicKeyContext(Map.of("algorithm", "ECC"))) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + // ElGamal private static final IDetectionRule ELGAMAL_GENERATE = new DetectionRuleBuilder() @@ -231,12 +257,12 @@ public static List> DSARules() { @Nonnull public static List> ECCPublicKeyRules() { - return List.of(ECC_CONSTRUCT, ECC_PUBLIC_KEY); + return List.of(ECC_CONSTRUCT, ECC_PUBLIC_KEY, EDDSA_IMPORT_PUBLIC_KEY); } @Nonnull public static List> ECCPrivateKeyRules() { - return List.of(ECC_CONSTRUCT, ECC_GENERATE); + return List.of(ECC_CONSTRUCT, ECC_GENERATE, EDDSA_IMPORT_PRIVATE_KEY); } @Nonnull @@ -254,10 +280,9 @@ public static List> rules() { ECC_CONSTRUCT, ECC_GENERATE, ECC_IMPORT, + EDDSA_IMPORT_PRIVATE_KEY, + EDDSA_IMPORT_PUBLIC_KEY, ELGAMAL_CONSTRUCT, ELGAMAL_GENERATE); - // return Stream.of(RSA_rules(), DSA_rules(), ECC_rules(), List.of(ELGAMAL_KEY_GEN)) - // .flatMap(Collection::stream) - // .collect(Collectors.toList()); } } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java new file mode 100644 index 000000000..f88d889a8 --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java @@ -0,0 +1,66 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.random; + +import static com.ibm.engine.detection.MethodMatcher.ANY; + +import com.ibm.engine.model.context.PRNGContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1192") +public final class PythonCryptoRandom { + + private PythonCryptoRandom() { + // private + } + + private static final IDetectionRule RANDOM_GET_BYTES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Random") + .forMethods("get_random_bytes") + .shouldBeDetectedAs(new ValueActionFactory<>("PRNG")) + .withMethodParameter(ANY) + .buildForContext(new PRNGContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + private static final IDetectionRule RANDOM_FUNC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Random.random") + .forMethods( + "getrandbits", "randrange", "randint", "choice", "shuflle", "sample") + .shouldBeDetectedAs(new ValueActionFactory<>("PRNG")) + .withMethodParameter(ANY) + .buildForContext(new PRNGContext()) + .inBundle(() -> "PyCrypto") + .withoutDependingDetectionRules(); + + @Nonnull + public static List> rules() { + return List.of(RANDOM_GET_BYTES, RANDOM_FUNC); + } +} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java similarity index 66% rename from python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java rename to python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java index bcd719cc0..ac9a5c885 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignature.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.crypto; +package com.ibm.plugin.rules.detection.pycrypto.signature; import static com.ibm.engine.detection.MethodMatcher.ANY; @@ -28,6 +28,8 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.pycrypto.hash.PythonCryptoHash; +import com.ibm.plugin.rules.detection.pycrypto.publickey.PythonCryptoPublicKey; import java.util.List; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -98,36 +100,21 @@ private PythonCryptoSignature() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(SIGN, VERIFY)); - // private static final IDetectionRule DSS_SIGN = - // new DetectionRuleBuilder() - // .createDetectionRule() - // .forObjectTypes("Crypto.Signature.DSS.DssSigScheme") - // .forMethods("sign") - // .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) - // .withMethodParameter("Crypto.Hash.*") - // .shouldBeDetectedAs(new AlgorithmFactory<>()) - // .asChildOfParameterWithId(-1) - // .addDependingDetectionRules(PythonCryptoHash.rules()) - // .buildForContext(new SignatureContext(Map.of("kind", "SIGN", "algorithm", - // "EC"))) - // .inBundle(() -> "PyCrypto") - // .withoutDependingDetectionRules(); - - // private static final IDetectionRule DSS_VERIFY = - // new DetectionRuleBuilder() - // .createDetectionRule() - // .forObjectTypes("Crypto.Signature.DSS.DssSigScheme") - // .forMethods("verify") - // .shouldBeDetectedAs(new - // SignatureActionFactory<>(SignatureAction.Action.VERIFY)) - // .withMethodParameter("Crypto.Hash.*") - // .shouldBeDetectedAs(new AlgorithmFactory<>()) - // .asChildOfParameterWithId(-1) - // .addDependingDetectionRules(PythonCryptoHash.rules()) - // .withMethodParameter(ANY) // the signature to be verified - // .buildForContext(new SignatureContext(Map.of("algorithm", "EC"))) - // .inBundle(() -> "PyCrypto") - // .withoutDependingDetectionRules(); + // PSS signature scheme - sign and verify methods (called on the result of .new()) + private static final IDetectionRule PSS_MGF1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Signature.pss") + .forMethods("MGF1") + .shouldBeDetectedAs(new ValueActionFactory<>("MGF1")) + .withMethodParameter(ANY) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Hash.*") + .shouldBeDetectedAs(new AlgorithmFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new SignatureContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(SIGN, VERIFY)); // DSS signature scheme - sign and verify methods (called on the result of .new()) private static final IDetectionRule DSS = @@ -161,37 +148,6 @@ private PythonCryptoSignature() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(SIGN, VERIFY)); - // private static final IDetectionRule EDDSA_SIGN = - // new DetectionRuleBuilder() - // .createDetectionRule() - // .forObjectTypes("Crypto.Signature.eddsa.EdDSASigScheme") - // .forMethods("sign") - // .shouldBeDetectedAs(new - // SignatureActionFactory<>(SignatureAction.Action.SIGN)) - // .withMethodParameter("Crypto.Hash.*") - // .shouldBeDetectedAs(new AlgorithmFactory<>()) - // .asChildOfParameterWithId(-1) - // .addDependingDetectionRules(PythonCryptoHash.rules()) - // .buildForContext(new SignatureContext(Map.of("algorithm", "EC"))) - // .inBundle(() -> "PyCrypto") - // .withoutDependingDetectionRules(); - - // private static final IDetectionRule EDDSA_VERIFY = - // new DetectionRuleBuilder() - // .createDetectionRule() - // .forObjectTypes("Crypto.Signature.eddsa.EdDSASigScheme") - // .forMethods("verify") - // .shouldBeDetectedAs(new - // SignatureActionFactory<>(SignatureAction.Action.VERIFY)) - // .withMethodParameter("Crypto.Hash.*") - // .shouldBeDetectedAs(new AlgorithmFactory<>()) - // .asChildOfParameterWithId(-1) - // .addDependingDetectionRules(PythonCryptoHash.rules()) - // .withMethodParameter(ANY) // the signature to be verified - // .buildForContext(new SignatureContext(Map.of("algorithm", "EC"))) - // .inBundle(() -> "PyCrypto") - // .withoutDependingDetectionRules(); - // EdDSA signature scheme - sign and verify methods (called on the result of .new()) private static final IDetectionRule EDDSA = new DetectionRuleBuilder() @@ -210,6 +166,6 @@ private PythonCryptoSignature() { @Nonnull public static List> rules() { - return List.of(PKCS1V15, PSS, DSS, ECDSA, EDDSA); + return List.of(PKCS1V15, PSS, PSS_MGF1, DSS, ECDSA, EDDSA); } } diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java index a3e41e7a9..a349601c3 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/PythonTranslator.java @@ -27,6 +27,7 @@ import com.ibm.engine.model.context.KeyContext; import com.ibm.engine.model.context.KeyDerivationFunctionContext; import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.context.PRNGContext; import com.ibm.engine.model.context.PrivateKeyContext; import com.ibm.engine.model.context.PublicKeyContext; import com.ibm.engine.model.context.SecretKeyContext; @@ -43,6 +44,7 @@ import com.ibm.plugin.translation.translator.contexts.PycaMacContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaPrivateKeyContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaPublicKeyContextTranslator; +import com.ibm.plugin.translation.translator.contexts.PycaRandomContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaSecretKeyContextTranslator; import com.ibm.plugin.translation.translator.contexts.PycaSignatureContextTranslator; import java.util.List; @@ -126,6 +128,11 @@ public Optional translate( new PycaMacContextTranslator(); return pycaMacContextTranslator.translate( bundleIdentifier, value, detectionValueContext, detectionLocation); + } else if (detectionValueContext.is(PRNGContext.class)) { + final PycaRandomContextTranslator pycaRandomContextTranslator = + new PycaRandomContextTranslator(); + return pycaRandomContextTranslator.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); } return Optional.empty(); } diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java index 97830c76f..4cc5a94d5 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java @@ -19,6 +19,7 @@ */ package com.ibm.plugin.translation.translator.contexts; +import com.ibm.engine.model.Algorithm; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.IValue; import com.ibm.engine.model.KeySize; @@ -30,6 +31,7 @@ import com.ibm.mapper.IContextTranslation; import com.ibm.mapper.mapper.pyca.PycaCipherMapper; import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.EllipticCurveAlgorithm; import com.ibm.mapper.model.INode; import com.ibm.mapper.model.KeyLength; import com.ibm.mapper.model.KeyWrap; @@ -72,7 +74,7 @@ public final class PycaCipherContextTranslator implements IContextTranslation + if (value instanceof Algorithm && detectionContext instanceof DetectionContext context) { if (context.get("kind").map(k -> k.equals("AEAD")).orElse(false)) { return switch (value.asString().toUpperCase().trim()) { @@ -115,6 +117,7 @@ public final class PycaCipherContextTranslator implements IContextTranslation Optional.of(new EllipticCurveAlgorithm(detectionLocation)); default -> pycaCipherMapper.parse(algorithmName, detectionLocation).map(i -> i); }; } else if (value instanceof Mode mode) { diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaRandomContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaRandomContextTranslator.java new file mode 100644 index 000000000..4cd66fb3d --- /dev/null +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaRandomContextTranslator.java @@ -0,0 +1,57 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.PseudorandomNumberGenerator; +import com.ibm.mapper.utils.DetectionLocation; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.sonar.plugins.python.api.tree.Tree; + +@SuppressWarnings("java:S1301") +public final class PycaRandomContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + case "PRNG" -> + Optional.of( + new Algorithm( + "PRNG", + PseudorandomNumberGenerator.class, + detectionLocation)); + default -> Optional.empty(); + }; + } + return Optional.empty(); + } +} diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py deleted file mode 100644 index 8dc9d1b53..000000000 --- a/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureSignTestFile.py +++ /dev/null @@ -1,7 +0,0 @@ -from Crypto.PublicKey import ECC -from Crypto.Signature import eddsa - -message = b'some message' -key = ECC.import_key(open("private_ed25519.pem").read()) # Noncompliant {{(PublicKey) EC}} -signer = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) ECDSA}} -signature = signer.sign(message) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py b/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py deleted file mode 100644 index 4d7093f36..000000000 --- a/python/src/test/files/rules/detection/crypto/PythonCryptoEdDSAPureVerifyTestFile.py +++ /dev/null @@ -1,13 +0,0 @@ -from Crypto.PublicKey import ECC -from Crypto.Signature import eddsa - -message = b'some message' -key = ECC.import_key(open("public_ed25519.pem").read()) # Noncompliant {{(PublicKey) EC}} -verifier = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) ECDSA}} -signature = b'some signature' - -try: - verifier.verify(h, signature) - print("The message is authentic") -except ValueError: - print("The message is not authentic") \ No newline at end of file diff --git a/python/src/test/files/rules/detection/aead/PycaAESGCMTestFile.py b/python/src/test/files/rules/detection/pyca/aead/PycaAESGCMTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/aead/PycaAESGCMTestFile.py rename to python/src/test/files/rules/detection/pyca/aead/PycaAESGCMTestFile.py diff --git a/python/src/test/files/rules/detection/aead/PycaChaCha20Poly1305TestFile.py b/python/src/test/files/rules/detection/pyca/aead/PycaChaCha20Poly1305TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/aead/PycaChaCha20Poly1305TestFile.py rename to python/src/test/files/rules/detection/pyca/aead/PycaChaCha20Poly1305TestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/DSA/PycaDSANumbersTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/DSA/PycaDSANumbersTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/DSA/PycaDSANumbersTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/DSA/PycaDSANumbersTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/DSA/PycaDSASignTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/DSA/PycaDSASignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/DSA/PycaDSASignTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/DSA/PycaDSASignTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/RSA/PycaRSADecryptTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSADecryptTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/RSA/PycaRSADecryptTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSADecryptTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/RSA/PycaRSANumbersTestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSANumbersTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/RSA/PycaRSANumbersTestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSANumbersTestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/RSA/PycaRSASign1TestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSASign1TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/RSA/PycaRSASign1TestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSASign1TestFile.py diff --git a/python/src/test/files/rules/detection/asymmetric/RSA/PycaRSASign2TestFile.py b/python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSASign2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/asymmetric/RSA/PycaRSASign2TestFile.py rename to python/src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSASign2TestFile.py diff --git a/python/src/test/files/rules/detection/fernet/PycaFernetDecryptTestFile.py b/python/src/test/files/rules/detection/pyca/fernet/PycaFernetDecryptTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/fernet/PycaFernetDecryptTestFile.py rename to python/src/test/files/rules/detection/pyca/fernet/PycaFernetDecryptTestFile.py diff --git a/python/src/test/files/rules/detection/fernet/PycaFernetEncryptTestFile.py b/python/src/test/files/rules/detection/pyca/fernet/PycaFernetEncryptTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/fernet/PycaFernetEncryptTestFile.py rename to python/src/test/files/rules/detection/pyca/fernet/PycaFernetEncryptTestFile.py diff --git a/python/src/test/files/rules/detection/fernet/PycaMultiFernetTestFile.py b/python/src/test/files/rules/detection/pyca/fernet/PycaMultiFernetTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/fernet/PycaMultiFernetTestFile.py rename to python/src/test/files/rules/detection/pyca/fernet/PycaMultiFernetTestFile.py diff --git a/python/src/test/files/rules/detection/hash/PycaHashDirectTest.py b/python/src/test/files/rules/detection/pyca/hash/PycaHashDirectTest.py similarity index 100% rename from python/src/test/files/rules/detection/hash/PycaHashDirectTest.py rename to python/src/test/files/rules/detection/pyca/hash/PycaHashDirectTest.py diff --git a/python/src/test/files/rules/detection/kdf/PycaConcatKDFHMACTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaConcatKDFHMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaConcatKDFHMACTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaConcatKDFHMACTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaConcatKDFHashTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaConcatKDFHashTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaConcatKDFHashTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaConcatKDFHashTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaHKDFExpandTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaHKDFExpandTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaHKDFExpandTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaHKDFExpandTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaHKDFTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaHKDFTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaHKDFTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaHKDFTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaKBKDFCMACTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaKBKDFCMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaKBKDFCMACTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaKBKDFCMACTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaKBKDFHMACTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaKBKDFHMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaKBKDFHMACTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaKBKDFHMACTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaPBKDF2TestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaPBKDF2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaPBKDF2TestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaPBKDF2TestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaScryptTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaScryptTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaScryptTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaScryptTestFile.py diff --git a/python/src/test/files/rules/detection/kdf/PycaX963KDFTestFile.py b/python/src/test/files/rules/detection/pyca/kdf/PycaX963KDFTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/kdf/PycaX963KDFTestFile.py rename to python/src/test/files/rules/detection/pyca/kdf/PycaX963KDFTestFile.py diff --git a/python/src/test/files/rules/detection/keyagreement/PycaKeyAgreementTestFile.py b/python/src/test/files/rules/detection/pyca/keyagreement/PycaKeyAgreementTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/keyagreement/PycaKeyAgreementTestFile.py rename to python/src/test/files/rules/detection/pyca/keyagreement/PycaKeyAgreementTestFile.py diff --git a/python/src/test/files/rules/detection/mac/PycaCMACTestFile.py b/python/src/test/files/rules/detection/pyca/mac/PycaCMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/mac/PycaCMACTestFile.py rename to python/src/test/files/rules/detection/pyca/mac/PycaCMACTestFile.py diff --git a/python/src/test/files/rules/detection/mac/PycaHMACTestFile.py b/python/src/test/files/rules/detection/pyca/mac/PycaHMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/mac/PycaHMACTestFile.py rename to python/src/test/files/rules/detection/pyca/mac/PycaHMACTestFile.py diff --git a/python/src/test/files/rules/detection/mac/PycaMacDetectionInCustomFunctionTestFile.py b/python/src/test/files/rules/detection/pyca/mac/PycaMacDetectionInCustomFunctionTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/mac/PycaMacDetectionInCustomFunctionTestFile.py rename to python/src/test/files/rules/detection/pyca/mac/PycaMacDetectionInCustomFunctionTestFile.py diff --git a/python/src/test/files/rules/detection/mac/PycaPoly1305TestFile.py b/python/src/test/files/rules/detection/pyca/mac/PycaPoly1305TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/mac/PycaPoly1305TestFile.py rename to python/src/test/files/rules/detection/pyca/mac/PycaPoly1305TestFile.py diff --git a/python/src/test/files/rules/detection/padding/PycaPaddingTestFile.py b/python/src/test/files/rules/detection/pyca/padding/PycaPaddingTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/padding/PycaPaddingTestFile.py rename to python/src/test/files/rules/detection/pyca/padding/PycaPaddingTestFile.py diff --git a/python/src/test/files/rules/detection/symmetric/PycaCipher1TestFile.py b/python/src/test/files/rules/detection/pyca/symmetric/PycaCipher1TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/symmetric/PycaCipher1TestFile.py rename to python/src/test/files/rules/detection/pyca/symmetric/PycaCipher1TestFile.py diff --git a/python/src/test/files/rules/detection/symmetric/PycaCipher2TestFile.py b/python/src/test/files/rules/detection/pyca/symmetric/PycaCipher2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/symmetric/PycaCipher2TestFile.py rename to python/src/test/files/rules/detection/pyca/symmetric/PycaCipher2TestFile.py diff --git a/python/src/test/files/rules/detection/pyca/symmetric/PycaCipher3TestFile.py b/python/src/test/files/rules/detection/pyca/symmetric/PycaCipher3TestFile.py new file mode 100644 index 000000000..45ca10c8c --- /dev/null +++ b/python/src/test/files/rules/detection/pyca/symmetric/PycaCipher3TestFile.py @@ -0,0 +1,36 @@ + +import os +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + +key64 = b"01234567" +key128 = b"0123456789abcdef" +key192 = b"0123456789abcdef01234567" +key256 = b"0123456789abcdef0123456789abcdef" + +iv = b"1234567890abcdef" +nonce = b"123456789012" +data = b"hello world!!!!!" + +# AES-CBC (invalid 64-bit key — should fail at runtime, but useful for static detection testing) +algo_small = algorithms.AES(key64) +c_small = Cipher(algo_small, modes.CBC(iv)) # Noncompliant {{(BlockCipher) AES-CBC}} +encryptor_small = c_small.encryptor() +ct_small = encryptor_small.update(data) + encryptor_small.finalize() + +# AES-CBC (128-bit) +algo_128 = algorithms.AES(key128) +c_128 = Cipher(algo_128, modes.CBC(iv)) # Noncompliant {{(BlockCipher) AES-CBC}} +encryptor_128 = c_128.encryptor() +ct_128 = encryptor_128.update(data) + encryptor_128.finalize() + +# AES-CBC (192-bit) +algo_192 = algorithms.AES(key192) +c_192 = Cipher(algo_192, modes.CBC(iv)) # Noncompliant {{(BlockCipher) AES-CBC}} +encryptor_192 = c_192.encryptor() +ct_192 = encryptor_192.update(data) + encryptor_192.finalize() + +# AES-CBC (256-bit) +algo_256 = algorithms.AES(key256) +c_256 = Cipher(algo_256, modes.CBC(iv)) # Noncompliant {{(BlockCipher) AES-CBC}} +encryptor_256 = c_256.encryptor() +ct_256 = encryptor_256.update(data) + encryptor_256.finalize() \ No newline at end of file diff --git a/python/src/test/files/rules/detection/symmetric/PycaStreamCipher1TestFile.py b/python/src/test/files/rules/detection/pyca/symmetric/PycaStreamCipher1TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/symmetric/PycaStreamCipher1TestFile.py rename to python/src/test/files/rules/detection/pyca/symmetric/PycaStreamCipher1TestFile.py diff --git a/python/src/test/files/rules/detection/wrapping/PycaWrappingTestFile.py b/python/src/test/files/rules/detection/pyca/wrapping/PycaWrappingTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/wrapping/PycaWrappingTestFile.py rename to python/src/test/files/rules/detection/pyca/wrapping/PycaWrappingTestFile.py diff --git a/python/src/test/files/rules/detection/wrapping/PycaWrappingWithPaddingTestFile.py b/python/src/test/files/rules/detection/pyca/wrapping/PycaWrappingWithPaddingTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/wrapping/PycaWrappingWithPaddingTestFile.py rename to python/src/test/files/rules/detection/pyca/wrapping/PycaWrappingWithPaddingTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/AESTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/AESTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py new file mode 100644 index 000000000..82489e8b1 --- /dev/null +++ b/python/src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py @@ -0,0 +1,10 @@ +from Crypto.PublicKey import ECC +from Crypto.Protocol import HPKE +from Crypto.Protocol.HPKE.AEAD import AES128_GCM + + +key = ECC.import_key(open("pub_key.pem").read()) # Noncompliant {{(Key) EC}} + +encryptor = HPKE.new(key, AES128_GCM) # Noncompliant {{(PublicKeyEncryption) EC}} + +ct_1 = encryptor.seal(b'Message 1') \ No newline at end of file diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/PKCS1OAEPTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/PKCS1OAEPTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/PKCS1v15TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/PKCS1v15TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/RC4TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/RC4TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/Salsa20TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/Salsa20TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py rename to python/src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/BLAKE2bTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/BLAKE2bTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/BLAKE2sTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/BLAKE2sTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/MD2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/MD2TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/MD5TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/MD5TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/RIPEMD160TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/RIPEMD160TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA3_224TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA3_224TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA3_256TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA3_256TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA3_384TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA3_384TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA3_512TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA3_512TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/TupleHash128TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/TupleHash128TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/cSHAKE256TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py rename to python/src/test/files/rules/detection/pycrypto/hash/cSHAKE256TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/BcryptTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py rename to python/src/test/files/rules/detection/pycrypto/kdf/BcryptTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py rename to python/src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py rename to python/src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py rename to python/src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py rename to python/src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKDFTestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKDFTestFile.py rename to python/src/test/files/rules/detection/pycrypto/kdf/TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/DHTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py rename to python/src/test/files/rules/detection/pycrypto/keyagreement/DHTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementTestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementTestFile.py rename to python/src/test/files/rules/detection/pycrypto/keyagreement/TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/X25519PublicKeyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/keyagreement/X25519PublicKeyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/X448PrivateKeyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/keyagreement/X448PrivateKeyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/X448PublicKeyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/keyagreement/X448PublicKeyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py b/python/src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py rename to python/src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py b/python/src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py rename to python/src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoMacTestFile.py b/python/src/test/files/rules/detection/pycrypto/mac/TestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoMacTestFile.py rename to python/src/test/files/rules/detection/pycrypto/mac/TestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py b/python/src/test/files/rules/detection/pycrypto/publickey/DSATestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py rename to python/src/test/files/rules/detection/pycrypto/publickey/DSATestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py b/python/src/test/files/rules/detection/pycrypto/publickey/ECCTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py rename to python/src/test/files/rules/detection/pycrypto/publickey/ECCTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py b/python/src/test/files/rules/detection/pycrypto/publickey/ElGamalTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py rename to python/src/test/files/rules/detection/pycrypto/publickey/ElGamalTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py b/python/src/test/files/rules/detection/pycrypto/publickey/RSATestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py rename to python/src/test/files/rules/detection/pycrypto/publickey/RSATestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSASignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSASignTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSAVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignatureECDSAVerifyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py diff --git a/python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py similarity index 100% rename from python/src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py rename to python/src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java deleted file mode 100644 index 1b9518fde..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipherTest.java +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.Algorithm; -import com.ibm.engine.model.CipherAction; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.ValueAction; -import com.ibm.engine.model.context.CipherContext; -import com.ibm.mapper.model.AuthenticatedEncryption; -import com.ibm.mapper.model.BlockCipher; -import com.ibm.mapper.model.BlockSize; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.KeyLength; -import com.ibm.mapper.model.MessageDigest; -import com.ibm.mapper.model.Mode; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.Padding; -import com.ibm.mapper.model.PublicKeyEncryption; -import com.ibm.mapper.model.StreamCipher; -import com.ibm.mapper.model.functionality.Decrypt; -import com.ibm.mapper.model.functionality.Digest; -import com.ibm.mapper.model.functionality.Encrypt; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoCipherTest { - - // ------------------------------------------------------------------------- - // Shared detection-store helpers - // ------------------------------------------------------------------------- - - private static void assertRootValueAction( - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedAlgorithm) { - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(ValueAction.class); - assertThat(value.asString()).isEqualTo(expectedAlgorithm); - } - - private static void assertCipherActionChild( - @Nonnull DetectionStore detectionStore, - @Nonnull TestBase test) { - DetectionStore store = - test.getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); - if (store == null) { - return; - } - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(CipherAction.class); - assertThat(value.asString()) - .satisfiesAnyOf( - s -> assertThat(s).isEqualTo("ENCRYPT"), - s -> assertThat(s).isEqualTo("DECRYPT")); - } - - private static void assertModeChild( - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedMode, - @Nonnull TestBase test) { - DetectionStore store = - test.getStoreOfValueType( - com.ibm.engine.model.Mode.class, detectionStore.getChildren()); - assertThat(store).isNotNull(); - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(com.ibm.engine.model.Mode.class); - assertThat(value.asString()).isEqualTo(expectedMode); - } - - private static void assertImportKeyChild( - @Nonnull DetectionStore detectionStore, - @Nonnull TestBase test) { - DetectionStore store = - test.getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); - if (store != null) { - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(Algorithm.class); - } - } - - // ------------------------------------------------------------------------- - // Shared translation helpers - // ------------------------------------------------------------------------- - - private static INode assertTranslationRoot( - @Nonnull List nodes, - @Nonnull Class kind, - int childCount, - @Nonnull String expectedName) { - assertThat(nodes).hasSize(1); - INode cipher = nodes.get(0); - assertThat(cipher.getKind()).isEqualTo(kind); - assertThat(cipher.getChildren()).hasSize(childCount); - assertThat(cipher.asString()).isEqualTo(expectedName); - return cipher; - } - - private static void assertLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).isEmpty(); - assertThat(node.asString()).isEqualTo(expectedValue); - } - - private static void assertOptionalLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node) - .satisfiesAnyOf( - n -> assertThat(n).isNull(), - n -> { - assertThat(n.getChildren()).isEmpty(); - assertThat(n.asString()).isEqualTo(expectedValue); - }); - } - - private static void assertFunctionalityNodes(@Nonnull INode parent) { - assertOptionalLeafNode(parent, Encrypt.class, "ENCRYPT"); - assertOptionalLeafNode(parent, Decrypt.class, "DECRYPT"); - } - - // ------------------------------------------------------------------------- - // AES - // ------------------------------------------------------------------------- - - static class AESTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherAESTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "AES"); - assertCipherActionChild(detectionStore, this); - assertModeChild(detectionStore, "MODE_CBC", this); - - INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 4, "AES-CBC"); - assertLeafNode(cipher, Mode.class, "CBC"); - assertLeafNode(cipher, Oid.class, "2.16.840.1.101.3.4.1"); - assertLeafNode(cipher, BlockSize.class, "128"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // DES - // ------------------------------------------------------------------------- - - static class DESTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherDESTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "DES"); - assertCipherActionChild(detectionStore, this); - assertModeChild(detectionStore, "MODE_ECB", this); - - INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 4, "DES56-ECB"); - assertLeafNode(cipher, Mode.class, "ECB"); - assertLeafNode(cipher, KeyLength.class, "56"); - assertLeafNode(cipher, BlockSize.class, "64"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // 3DES - // ------------------------------------------------------------------------- - - static class TripleDESTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipher3DESTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "3DES"); - assertModeChild(detectionStore, "MODE_CBC", this); - - INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 2, "3DES"); - assertLeafNode(cipher, Mode.class, "CBC"); - assertLeafNode(cipher, BlockSize.class, "64"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // Blowfish - // ------------------------------------------------------------------------- - - static class BlowfishTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherBlowfishTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "Blowfish"); - assertCipherActionChild(detectionStore, this); - assertModeChild(detectionStore, "MODE_CBC", this); - - INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 1, "Blowfish"); - assertLeafNode(cipher, Mode.class, "CBC"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // CAST5 - // ------------------------------------------------------------------------- - - static class CAST5Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherCAST5TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "CAST5"); - assertCipherActionChild(detectionStore, this); - assertModeChild(detectionStore, "MODE_CBC", this); - - INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 2, "CAST-128"); - assertLeafNode(cipher, Mode.class, "CBC"); - assertLeafNode(cipher, BlockSize.class, "64"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // RC2 - // ------------------------------------------------------------------------- - - static class RC2Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherRC2TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "RC2"); - assertCipherActionChild(detectionStore, this); - assertModeChild(detectionStore, "MODE_CBC", this); - - INode cipher = assertTranslationRoot(nodes, BlockCipher.class, 1, "RC2"); - assertLeafNode(cipher, Mode.class, "CBC"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // RC4 - // ------------------------------------------------------------------------- - - static class RC4Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherRC4TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "RC4"); - assertCipherActionChild(detectionStore, this); - - INode cipher = assertTranslationRoot(nodes, StreamCipher.class, 0, "RC4"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // ChaCha20-Poly1305 - // ------------------------------------------------------------------------- - - static class ChaCha20Poly1305Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20Poly1305TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "ChaCha20Poly1305"); - assertThat(detectionStore.getChildren()).isEmpty(); - - INode cipher = - assertTranslationRoot( - nodes, AuthenticatedEncryption.class, 1, "ChaCha20Poly1305"); - - INode messageDigest = cipher.getChildren().get(MessageDigest.class); - assertThat(messageDigest).isNotNull(); - assertThat(messageDigest.getChildren()).hasSize(1); - assertThat(messageDigest.asString()).isEqualTo("Poly1305"); - assertLeafNode(messageDigest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // ChaCha20 - // ------------------------------------------------------------------------- - - static class ChaCha20Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherChaCha20TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "ChaCha20"); - assertThat(detectionStore.getChildren()).isEmpty(); - - assertTranslationRoot(nodes, StreamCipher.class, 0, "ChaCha20"); - } - } - - // ------------------------------------------------------------------------- - // Salsa20 - // ------------------------------------------------------------------------- - - static class Salsa20Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherSalsa20TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "Salsa20"); - assertCipherActionChild(detectionStore, this); - - INode cipher = assertTranslationRoot(nodes, StreamCipher.class, 1, "Salsa20"); - assertLeafNode(cipher, KeyLength.class, "128"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // PKCS1-OAEP - // ------------------------------------------------------------------------- - - static class PKCS1OAEPTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1OAEPTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "PKCS1_OAEP"); - assertCipherActionChild(detectionStore, this); - assertImportKeyChild(detectionStore, this); - - DetectionStore store = - getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); - if (store != null) { - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(Algorithm.class); - } - - INode cipher = assertTranslationRoot(nodes, PublicKeyEncryption.class, 2, "RSA-OAEP"); - assertLeafNode(cipher, Oid.class, "1.2.840.113549.1.1.7"); - assertLeafNode(cipher, Padding.class, "OAEP"); - assertFunctionalityNodes(cipher); - } - } - - // ------------------------------------------------------------------------- - // PKCS1-v1.5 - // ------------------------------------------------------------------------- - - static class PKCS1v15Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoCipherPKCS1v15TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertRootValueAction(detectionStore, "PKCS1_v1_5"); - assertCipherActionChild(detectionStore, this); - - INode cipher = assertTranslationRoot(nodes, PublicKeyEncryption.class, 2, "RSA"); - assertLeafNode(cipher, Oid.class, "1.2.840.113549.1.1.1"); - assertLeafNode(cipher, Padding.class, "PKCS1"); - assertFunctionalityNodes(cipher); - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java deleted file mode 100644 index 409ffa0f5..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoHashTest.java +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.ValueAction; -import com.ibm.engine.model.context.DigestContext; -import com.ibm.mapper.model.BlockSize; -import com.ibm.mapper.model.DigestSize; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.MessageDigest; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.ParameterSetIdentifier; -import com.ibm.mapper.model.SaltLength; -import com.ibm.mapper.model.functionality.Digest; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoHashTest { - - // ------------------------------------------------------------------------- - // Shared helpers (static so inner classes can access them) - // ------------------------------------------------------------------------- - - private static void assertHashDetection( - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedName) { - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); - assertThat(detectionStore.getChildren()).isEmpty(); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(ValueAction.class); - assertThat(value.asString()).isEqualTo(expectedName); - } - - private static INode assertHashTranslation( - @Nonnull List nodes, int childCount, @Nonnull String expectedName) { - assertThat(nodes).hasSize(1); - INode digest = nodes.get(0); - assertThat(digest).isInstanceOf(MessageDigest.class); - assertThat(digest.getChildren()).hasSize(childCount); - assertThat(digest.asString()).isEqualTo(expectedName); - return digest; - } - - private static void assertLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).isEmpty(); - assertThat(node.asString()).isEqualTo(expectedValue); - } - - // ------------------------------------------------------------------------- - // MD5 - // ------------------------------------------------------------------------- - - static class MD5Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashMD5TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "MD5"); - - INode digest = assertHashTranslation(nodes, 3, "MD5"); - assertLeafNode(digest, BlockSize.class, "512"); - assertLeafNode(digest, DigestSize.class, "128"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA1 - // ------------------------------------------------------------------------- - - static class SHA1Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA1TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA1"); - - INode digest = assertHashTranslation(nodes, 4, "SHA1"); - assertLeafNode(digest, BlockSize.class, "512"); - assertLeafNode(digest, Oid.class, "1.3.14.3.2.26"); - assertLeafNode(digest, DigestSize.class, "160"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA224 - // ------------------------------------------------------------------------- - - static class SHA224Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA224TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA224"); - - INode digest = assertHashTranslation(nodes, 4, "SHA224"); - assertLeafNode(digest, BlockSize.class, "512"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.4"); - assertLeafNode(digest, DigestSize.class, "224"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA256 - // ------------------------------------------------------------------------- - - static class SHA256Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA256TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA256"); - - INode digest = assertHashTranslation(nodes, 4, "SHA256"); - assertLeafNode(digest, BlockSize.class, "512"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(digest, DigestSize.class, "256"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA384 - // ------------------------------------------------------------------------- - - static class SHA384Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA384TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA384"); - - INode digest = assertHashTranslation(nodes, 4, "SHA384"); - assertLeafNode(digest, BlockSize.class, "1024"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.2"); - assertLeafNode(digest, DigestSize.class, "384"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA512 - // ------------------------------------------------------------------------- - - static class SHA512Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA512TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA512"); - - INode digest = assertHashTranslation(nodes, 4, "SHA512"); - assertLeafNode(digest, BlockSize.class, "1024"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.3"); - assertLeafNode(digest, DigestSize.class, "512"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA3-224 - // ------------------------------------------------------------------------- - - static class SHA3_224Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_224TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA3_224"); - - INode digest = assertHashTranslation(nodes, 4, "SHA3-224"); - assertLeafNode(digest, BlockSize.class, "1152"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.7"); - assertLeafNode(digest, DigestSize.class, "224"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA3-256 - // ------------------------------------------------------------------------- - - static class SHA3_256Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_256TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA3_256"); - - INode digest = assertHashTranslation(nodes, 4, "SHA3-256"); - assertLeafNode(digest, BlockSize.class, "1088"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.8"); - assertLeafNode(digest, DigestSize.class, "256"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA3-384 - // ------------------------------------------------------------------------- - - static class SHA3_384Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_384TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA3_384"); - - INode digest = assertHashTranslation(nodes, 4, "SHA3-384"); - assertLeafNode(digest, BlockSize.class, "832"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.9"); - assertLeafNode(digest, DigestSize.class, "384"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // SHA3-512 - // ------------------------------------------------------------------------- - - static class SHA3_512Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashSHA3_512TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "SHA3_512"); - - INode digest = assertHashTranslation(nodes, 4, "SHA3-512"); - assertLeafNode(digest, BlockSize.class, "576"); - assertLeafNode(digest, Oid.class, "2.16.840.1.101.3.4.2.10"); - assertLeafNode(digest, DigestSize.class, "512"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // RIPEMD-160 - // ------------------------------------------------------------------------- - - static class RIPEMD160Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashRIPEMD160TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "RIPEMD160"); - - INode digest = assertHashTranslation(nodes, 2, "RIPEMD-160"); - assertLeafNode(digest, DigestSize.class, "160"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // BLAKE2b - // ------------------------------------------------------------------------- - - static class BLAKE2bTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2bTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "BLAKE2b"); - - INode digest = assertHashTranslation(nodes, 2, "BLAKE2b"); - assertLeafNode(digest, SaltLength.class, "128"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // BLAKE2s - // ------------------------------------------------------------------------- - - static class BLAKE2sTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashBLAKE2sTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "BLAKE2s"); - - INode digest = assertHashTranslation(nodes, 2, "BLAKE2s"); - assertLeafNode(digest, SaltLength.class, "64"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // MD2 - // ------------------------------------------------------------------------- - - static class MD2Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashMD2TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "MD2"); - - INode digest = assertHashTranslation(nodes, 3, "MD2"); - assertLeafNode(digest, BlockSize.class, "128"); - assertLeafNode(digest, DigestSize.class, "128"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // TupleHash128 - // ------------------------------------------------------------------------- - - static class TupleHash128Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashTupleHash128TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "TupleHash128"); - - INode digest = assertHashTranslation(nodes, 2, "TupleHash"); - assertLeafNode(digest, DigestSize.class, "128"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } - - // ------------------------------------------------------------------------- - // cSHAKE256 - // ------------------------------------------------------------------------- - - static class cSHAKE256Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoHashcSHAKE256TestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertHashDetection(detectionStore, "cSHAKE256"); - - INode digest = assertHashTranslation(nodes, 2, "cSHAKE256"); - assertLeafNode(digest, ParameterSetIdentifier.class, "256"); - assertLeafNode(digest, Digest.class, "DIGEST"); - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java deleted file mode 100644 index fb671b9da..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKDFTest.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.Algorithm; -import com.ibm.engine.model.AlgorithmParameter; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.KeySize; -import com.ibm.engine.model.ValueAction; -import com.ibm.engine.model.context.KeyDerivationFunctionContext; -import com.ibm.mapper.model.BlockSize; -import com.ibm.mapper.model.DigestSize; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.KeyDerivationFunction; -import com.ibm.mapper.model.KeyLength; -import com.ibm.mapper.model.MessageDigest; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.PasswordBasedKeyDerivationFunction; -import com.ibm.mapper.model.algorithms.HKDF; -import com.ibm.mapper.model.algorithms.PBKDF1; -import com.ibm.mapper.model.algorithms.PBKDF2; -import com.ibm.mapper.model.algorithms.Scrypt; -import com.ibm.mapper.model.functionality.Digest; -import com.ibm.mapper.model.functionality.KeyDerivation; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoKDFTest { - - // ------------------------------------------------------------------------- - // Shared helpers (static so inner classes can access them) - // ------------------------------------------------------------------------- - - private static void assertRootValueAction( - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedName) { - assertThat(detectionStore.getDetectionValueContext()) - .isInstanceOf(KeyDerivationFunctionContext.class); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(ValueAction.class); - assertThat(value.asString()).isEqualTo(expectedName); - } - - private static void assertKeySizeChild( - @Nonnull TestBase test, - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedBits) { - DetectionStore store = - test.getStoreOfValueType(KeySize.class, detectionStore.getChildren()); - assertThat(store).isNotNull(); - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()) - .isInstanceOf(KeyDerivationFunctionContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(KeySize.class); - assertThat(value.asString()).isEqualTo(expectedBits); - } - - private static void assertAlgorithmChild( - @Nonnull TestBase test, - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedAlgorithm) { - DetectionStore store = - test.getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); - assertThat(store).isNotNull(); - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()) - .isInstanceOf(KeyDerivationFunctionContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(Algorithm.class); - assertThat(value.asString()).isEqualTo(expectedAlgorithm); - } - - @SuppressWarnings("unchecked") - private static void assertIterationsValue( - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedCount) { - IValue iterValue = - detectionStore.getDetectionValues().stream() - .filter(v -> v instanceof AlgorithmParameter) - .findFirst() - .orElse(null); - assertThat(iterValue).isNotNull(); - assertThat(((AlgorithmParameter) iterValue).getKind()) - .isEqualTo(AlgorithmParameter.Kind.ITERATIONS); - assertThat(iterValue.asString()).isEqualTo(expectedCount); - } - - private static INode assertTranslationRoot( - @Nonnull List nodes, - @Nonnull Class kind, - @Nonnull Class instanceOf, - int childCount, - @Nonnull String expectedName) { - assertThat(nodes).hasSize(1); - INode root = nodes.get(0); - assertThat(root.getKind()).isEqualTo(kind); - assertThat(root).isInstanceOf(instanceOf); - assertThat(root.getChildren()).hasSize(childCount); - assertThat(root.asString()).isEqualTo(expectedName); - return root; - } - - private static void assertLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).isEmpty(); - assertThat(node.asString()).isEqualTo(expectedValue); - } - - private static INode assertChildNode( - @Nonnull INode parent, - @Nonnull Class type, - int childCount, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).hasSize(childCount); - assertThat(node.asString()).isEqualTo(expectedValue); - return node; - } - - private static void assertMessageDigestChild( - @Nonnull INode kdfNode, - @Nonnull String expectedDigestName, - @Nonnull String expectedDigestSize, - @Nonnull String expectedOid, - @Nonnull String expectedBlockSize) { - INode md = assertChildNode(kdfNode, MessageDigest.class, 4, expectedDigestName); - assertLeafNode(md, DigestSize.class, expectedDigestSize); - assertLeafNode(md, Oid.class, expectedOid); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(md, BlockSize.class, expectedBlockSize); - } - - // ------------------------------------------------------------------------- - // PBKDF1 - // ------------------------------------------------------------------------- - - static class PBKDF1Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF1TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertRootValueAction(detectionStore, "PBKDF1"); - assertKeySizeChild(this, detectionStore, "128"); - assertAlgorithmChild(this, detectionStore, "SHA256"); - - INode root = - assertTranslationRoot( - nodes, - PasswordBasedKeyDerivationFunction.class, - PBKDF1.class, - 3, - "PBKDF1-SHA256"); - assertMessageDigestChild(root, "SHA256", "256", "2.16.840.1.101.3.4.2.1", "512"); - assertLeafNode(root, KeyLength.class, "128"); - assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); - } - } - - // ------------------------------------------------------------------------- - // PBKDF2 - // ------------------------------------------------------------------------- - - static class PBKDF2Test extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKDFPBKDF2TestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - assertThat(detectionStore.getDetectionValues()).hasSize(2); - assertRootValueAction(detectionStore, "PBKDF2"); - assertIterationsValue(detectionStore, "1"); - assertKeySizeChild(this, detectionStore, "512"); - assertAlgorithmChild(this, detectionStore, "SHA512"); - - INode root = - assertTranslationRoot( - nodes, - PasswordBasedKeyDerivationFunction.class, - PBKDF2.class, - 3, - "PBKDF2-SHA512"); - assertMessageDigestChild(root, "SHA512", "512", "2.16.840.1.101.3.4.2.3", "1024"); - assertLeafNode(root, KeyLength.class, "512"); - assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); - } - } - - // ------------------------------------------------------------------------- - // scrypt - // ------------------------------------------------------------------------- - - static class ScryptTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKDFScryptTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertRootValueAction(detectionStore, "scrypt"); - assertKeySizeChild(this, detectionStore, "256"); - - INode root = - assertTranslationRoot( - nodes, - PasswordBasedKeyDerivationFunction.class, - Scrypt.class, - 2, - "SCRYPT"); - assertLeafNode(root, KeyLength.class, "256"); - assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); - } - } - - // ------------------------------------------------------------------------- - // bcrypt - // ------------------------------------------------------------------------- - - static class BcryptTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verifyNoIssue( - "src/test/files/rules/detection/crypto/PythonCryptoKDFBcryptTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - assertThat(detectionStore.getDetectionValues()).hasSize(2); - assertRootValueAction(detectionStore, "bcrypt"); - assertIterationsValue(detectionStore, "10"); - assertThat(detectionStore.getChildren()).isEmpty(); - - // no mapper for bcrypt yet - assertThat(nodes).isEmpty(); - } - } - - // ------------------------------------------------------------------------- - // HKDF - // ------------------------------------------------------------------------- - - static class HKDFTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKDFHKDFTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertRootValueAction(detectionStore, "HKDF"); - assertKeySizeChild(this, detectionStore, "256"); - assertAlgorithmChild(this, detectionStore, "SHA512"); - - INode root = - assertTranslationRoot( - nodes, KeyDerivationFunction.class, HKDF.class, 3, "HKDF-SHA512"); - assertMessageDigestChild(root, "SHA512", "512", "2.16.840.1.101.3.4.2.3", "1024"); - assertLeafNode(root, KeyLength.class, "256"); - assertLeafNode(root, KeyDerivation.class, "KEYDERIVATION"); - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java deleted file mode 100644 index 6582f5e7f..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoKeyAgreementTest.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.KeyAction; -import com.ibm.engine.model.ValueAction; -import com.ibm.engine.model.context.KeyAgreementContext; -import com.ibm.mapper.model.EllipticCurve; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.KeyAgreement; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.algorithms.ECDH; -import com.ibm.mapper.model.functionality.KeyGeneration; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoKeyAgreementTest { - - // ------------------------------------------------------------------------- - // Shared helpers - // ------------------------------------------------------------------------- - - @SuppressWarnings("rawtypes") - private static void assertDetection( - @Nonnull DetectionStore detectionStore, - @Nonnull Class valueType, - @Nonnull String expectedName) { - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()) - .isInstanceOf(KeyAgreementContext.class); - assertThat(detectionStore.getChildren()).isEmpty(); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(valueType); - assertThat(value.asString()).isEqualTo(expectedName); - } - - private static INode assertTranslation( - @Nonnull List nodes, - @Nonnull Class instanceOf, - @Nonnull String expectedName) { - assertThat(nodes).hasSize(1); - INode root = nodes.get(0); - assertThat(root.getKind()).isEqualTo(KeyAgreement.class); - assertThat(root).isInstanceOf(instanceOf); - assertThat(root.asString()).isEqualTo(expectedName); - return root; - } - - private static INode assertLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.asString()).isEqualTo(expectedValue); - return node; - } - - // ------------------------------------------------------------------------- - // key_agreement (ECDH) - // ------------------------------------------------------------------------- - - static class DHTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementDHTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertDetection(detectionStore, ValueAction.class, "ECDH"); - - INode root = assertTranslation(nodes, ECDH.class, "ECDH"); - assertLeafNode(root, Oid.class, "1.3.132.1.12"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - } - } - - // ------------------------------------------------------------------------- - // import_x25519_public_key - // ------------------------------------------------------------------------- - - static class X25519PublicKeyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PublicKeyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertDetection(detectionStore, KeyAction.class, "GENERATION"); - - INode root = assertTranslation(nodes, KeyAgreement.class, "x25519"); - assertLeafNode(root, EllipticCurve.class, "Curve25519"); - assertLeafNode(root, Oid.class, "1.3.101.110"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - } - } - - // ------------------------------------------------------------------------- - // import_x25519_private_key - // ------------------------------------------------------------------------- - - static class X25519PrivateKeyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX25519PrivateKeyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertDetection(detectionStore, KeyAction.class, "GENERATION"); - - INode root = assertTranslation(nodes, KeyAgreement.class, "x25519"); - assertLeafNode(root, EllipticCurve.class, "Curve25519"); - assertLeafNode(root, Oid.class, "1.3.101.110"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - } - } - - // ------------------------------------------------------------------------- - // import_x448_public_key - // ------------------------------------------------------------------------- - - static class X448PublicKeyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PublicKeyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertDetection(detectionStore, KeyAction.class, "GENERATION"); - - INode root = assertTranslation(nodes, KeyAgreement.class, "x448"); - assertLeafNode(root, EllipticCurve.class, "Curve448"); - assertLeafNode(root, Oid.class, "1.3.101.111"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - } - } - - // ------------------------------------------------------------------------- - // import_x448_private_key - // ------------------------------------------------------------------------- - - static class X448PrivateKeyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoKeyAgreementX448PrivateKeyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - assertDetection(detectionStore, KeyAction.class, "GENERATION"); - - INode root = assertTranslation(nodes, KeyAgreement.class, "x448"); - assertLeafNode(root, EllipticCurve.class, "Curve448"); - assertLeafNode(root, Oid.class, "1.3.101.111"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java deleted file mode 100644 index c4779222a..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoMacTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.Algorithm; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.context.MacContext; -import com.ibm.mapper.model.BlockCipher; -import com.ibm.mapper.model.BlockSize; -import com.ibm.mapper.model.DigestSize; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.Mac; -import com.ibm.mapper.model.MessageDigest; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.functionality.Digest; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoMacTest { - - // ------------------------------------------------------------------------- - // CMAC - // ------------------------------------------------------------------------- - - static class CMACTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoMacCMACTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - /* - * Detection Store - */ - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(MacContext.class); - assertThat(detectionStore.getChildren()).isEmpty(); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(Algorithm.class); - assertThat(value.asString()).isEqualTo("AES"); - - /* - * Translation - */ - assertThat(nodes).hasSize(1); - - INode mac = nodes.get(0); - assertThat(mac).isInstanceOf(Mac.class); - assertThat(mac.asString()).isEqualTo("AES-CMAC"); - assertThat(mac.getChildren()).hasSize(2); - - INode cipher = mac.getChildren().get(BlockCipher.class); - assertThat(cipher).isNotNull(); - assertThat(cipher.asString()).isEqualTo("AES"); - - INode blockSize = cipher.getChildren().get(BlockSize.class); - assertThat(blockSize).isNotNull(); - assertThat(blockSize.getChildren()).isEmpty(); - assertThat(blockSize.asString()).isEqualTo("128"); - - INode oid = cipher.getChildren().get(Oid.class); - assertThat(oid).isNotNull(); - assertThat(oid.getChildren()).isEmpty(); - assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.1"); - } - } - - // ------------------------------------------------------------------------- - // HMAC - // ------------------------------------------------------------------------- - - static class HMACTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoMacHMACTestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - assertThat(findingId).isZero(); - - /* - * Detection Store - */ - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(MacContext.class); - assertThat(detectionStore.getChildren()).isEmpty(); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(Algorithm.class); - assertThat(value.asString()).isEqualTo("SHA256"); - - /* - * Translation - */ - assertThat(nodes).hasSize(1); - - INode mac = nodes.get(0); - assertThat(mac).isInstanceOf(Mac.class); - assertThat(mac.asString()).isEqualTo("HMAC-SHA256"); - assertThat(mac.getChildren()).hasSize(3); - - INode digest = mac.getChildren().get(MessageDigest.class); - assertThat(digest).isNotNull(); - assertThat(digest.asString()).isEqualTo("SHA256"); - assertThat(digest.getChildren()).hasSize(4); - - INode digestFunc = digest.getChildren().get(Digest.class); - assertThat(digestFunc).isNotNull(); - assertThat(digestFunc.getChildren()).isEmpty(); - assertThat(digestFunc.asString()).isEqualTo("DIGEST"); - - INode blockSize = digest.getChildren().get(BlockSize.class); - assertThat(blockSize).isNotNull(); - assertThat(blockSize.getChildren()).isEmpty(); - assertThat(blockSize.asString()).isEqualTo("512"); - - INode digestOid = digest.getChildren().get(Oid.class); - assertThat(digestOid).isNotNull(); - assertThat(digestOid.getChildren()).isEmpty(); - assertThat(digestOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); - - INode digestSize = digest.getChildren().get(DigestSize.class); - assertThat(digestSize).isNotNull(); - assertThat(digestSize.getChildren()).isEmpty(); - assertThat(digestSize.asString()).isEqualTo("256"); - - INode macOid = mac.getChildren().get(Oid.class); - assertThat(macOid).isNotNull(); - assertThat(macOid.getChildren()).isEmpty(); - assertThat(macOid.asString()).isEqualTo("1.2.840.113549.2.9"); - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java deleted file mode 100644 index ea9f916e8..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoPublicKeyTest.java +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.Curve; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.KeyAction; -import com.ibm.engine.model.KeySize; -import com.ibm.engine.model.context.KeyContext; -import com.ibm.engine.model.context.PrivateKeyContext; -import com.ibm.mapper.model.EllipticCurve; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.Key; -import com.ibm.mapper.model.KeyLength; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.PrivateKey; -import com.ibm.mapper.model.PublicKeyEncryption; -import com.ibm.mapper.model.Signature; -import com.ibm.mapper.model.functionality.KeyGeneration; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoPublicKeyTest { - - // ------------------------------------------------------------------------- - // Shared detection-store helpers - // ------------------------------------------------------------------------- - - /** - * Asserts a root store with a single KeyAction(PRIVATE_KEY_GENERATION) in a PrivateKeyContext. - */ - private static void assertGenerateDetection( - @Nonnull - DetectionStore - detectionStore) { - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(PrivateKeyContext.class); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(KeyAction.class); - assertThat(((KeyAction) value).getAction()) - .isEqualTo(KeyAction.Action.PRIVATE_KEY_GENERATION); - } - - /** Asserts a root store with a single KeyAction(GENERATION) in a KeyContext. */ - private static void assertKeyContextDetection( - @Nonnull - DetectionStore - detectionStore) { - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(KeyContext.class); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(KeyAction.class); - assertThat(((KeyAction) value).getAction()).isEqualTo(KeyAction.Action.GENERATION); - } - - /** Asserts the KeySize child store present on generate rules. */ - private static void assertKeySizeChild( - @Nonnull TestBase test, - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedBits) { - DetectionStore store = - test.getStoreOfValueType(KeySize.class, detectionStore.getChildren()); - assertThat(store).isNotNull(); - assertThat(store.getDetectionValues()).hasSize(1); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(KeySize.class); - assertThat(value.asString()).isEqualTo(expectedBits); - } - - /** Asserts the Curve child store present on ECC_CONSTRUCT. */ - private static void assertCurveChild( - @Nonnull TestBase test, - @Nonnull DetectionStore detectionStore, - @Nonnull String expectedCurve) { - DetectionStore store = - test.getStoreOfValueType(Curve.class, detectionStore.getChildren()); - assertThat(store).isNotNull(); - assertThat(store.getDetectionValues()).hasSize(1); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(Curve.class); - assertThat(value.asString()).isEqualTo(expectedCurve); - } - - // ------------------------------------------------------------------------- - // Shared translation helpers - // ------------------------------------------------------------------------- - - private static INode assertTranslationRoot( - @Nonnull List nodes, - @Nonnull Class kind, - int childCount, - @Nonnull String expectedName) { - assertThat(nodes).hasSize(1); - INode root = nodes.get(0); - assertThat(root.getKind()).isEqualTo(kind); - assertThat(root.getChildren()).hasSize(childCount); - assertThat(root.asString()).isEqualTo(expectedName); - return root; - } - - private static void assertLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).isEmpty(); - assertThat(node.asString()).isEqualTo(expectedValue); - } - - private static INode assertChildNode( - @Nonnull INode parent, - @Nonnull Class type, - int childCount, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).hasSize(childCount); - assertThat(node.asString()).isEqualTo(expectedValue); - return node; - } - - // ------------------------------------------------------------------------- - // RSA - // ------------------------------------------------------------------------- - - static class RSATest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyRSATestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - switch (findingId) { - case 0 -> assertRSAGenerate(detectionStore, nodes); - case 1 -> assertRSAConstruct(detectionStore, nodes); - case 2 -> assertRSAImportKey(detectionStore, nodes); - default -> throw new AssertionError("Unexpected findingId: " + findingId); - } - } - - // findingId == 0 (RSA.generate(bits=2048)) - private void assertRSAGenerate( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertGenerateDetection(detectionStore); - assertKeySizeChild(this, detectionStore, "2048"); - - /* - * Translation: PrivateKey(RSA) → KeyGeneration, PrivateKey(RSA), PublicKeyEncryption(RSA) - */ - INode root = assertTranslationRoot(nodes, PrivateKey.class, 3, "RSA"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - - INode innerKey = assertChildNode(root, PrivateKey.class, 3, "RSA"); - assertLeafNode(innerKey, KeyLength.class, "2048"); - assertLeafNode(innerKey, KeyGeneration.class, "KEYGENERATION"); - INode innerPke = assertChildNode(innerKey, PublicKeyEncryption.class, 1, "RSA"); - assertLeafNode(innerPke, Oid.class, "1.2.840.113549.1.1.1"); - - INode outerPke = assertChildNode(root, PublicKeyEncryption.class, 1, "RSA"); - assertLeafNode(outerPke, Oid.class, "1.2.840.113549.1.1.1"); - } - - // findingId == 1 (RSA.construct(...)) - private void assertRSAConstruct( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertKeyContextDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: Key(RSA) → KeyGeneration, PublicKeyEncryption(RSA) - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "RSA"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode pke = assertChildNode(root, PublicKeyEncryption.class, 1, "RSA"); - assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); - } - - // findingId == 2 (RSA.import_key(...)) - private void assertRSAImportKey( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store — identical structure to RSA.construct - */ - assertKeyContextDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation — identical to RSA.construct - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "RSA"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode pke = assertChildNode(root, PublicKeyEncryption.class, 1, "RSA"); - assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); - } - } - - // ------------------------------------------------------------------------- - // DSA - // ------------------------------------------------------------------------- - - static class DSATest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyDSATestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - switch (findingId) { - case 0 -> assertDSAGenerate(detectionStore, nodes); - case 1 -> assertDSAConstruct(detectionStore, nodes); - case 2 -> assertDSAImportKey(detectionStore, nodes); - default -> throw new AssertionError("Unexpected findingId: " + findingId); - } - } - - // findingId == 0 (DSA.generate(bits=2048)) - private void assertDSAGenerate( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertGenerateDetection(detectionStore); - assertKeySizeChild(this, detectionStore, "2048"); - - /* - * Translation: PrivateKey(DSA) → KeyGeneration, PrivateKey(DSA), Signature(DSA) - */ - INode root = assertTranslationRoot(nodes, PrivateKey.class, 3, "DSA"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - - INode innerKey = assertChildNode(root, PrivateKey.class, 3, "DSA"); - assertLeafNode(innerKey, KeyLength.class, "2048"); - assertLeafNode(innerKey, KeyGeneration.class, "KEYGENERATION"); - INode innerSig = assertChildNode(innerKey, Signature.class, 1, "DSA"); - assertLeafNode(innerSig, Oid.class, "1.2.840.10040.4.1"); - - INode outerSig = assertChildNode(root, Signature.class, 1, "DSA"); - assertLeafNode(outerSig, Oid.class, "1.2.840.10040.4.1"); - } - - // findingId == 1 (DSA.construct(...)) - private void assertDSAConstruct( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertKeyContextDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: Key(DSA) → KeyGeneration, Signature(DSA) - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "DSA"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode sig = assertChildNode(root, Signature.class, 1, "DSA"); - assertLeafNode(sig, Oid.class, "1.2.840.10040.4.1"); - } - - // findingId == 2 (DSA.import_key(...)) - private void assertDSAImportKey( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store — identical to DSA.construct - */ - assertKeyContextDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation — identical to DSA.construct - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "DSA"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode sig = assertChildNode(root, Signature.class, 1, "DSA"); - assertLeafNode(sig, Oid.class, "1.2.840.10040.4.1"); - } - } - - // ------------------------------------------------------------------------- - // ECC - // ------------------------------------------------------------------------- - - static class ECCTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyECCTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - switch (findingId) { - case 0 -> assertECCGenerate(detectionStore, nodes); - case 1 -> assertECCConstruct(detectionStore, nodes); - case 2 -> assertECCImportKey(detectionStore, nodes); - default -> throw new AssertionError("Unexpected findingId: " + findingId); - } - } - - // findingId == 0 (ECC.generate(curve="Ed25519")) - private void assertECCGenerate( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store — curve is the root value; no children - */ - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()) - .isInstanceOf(PrivateKeyContext.class); - IValue curve = detectionStore.getDetectionValues().get(0); - assertThat(curve).isInstanceOf(Curve.class); - assertThat(curve.asString()).isEqualTo("Ed25519"); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: PrivateKey(EC-Curve25519) → KeyGeneration, PublicKeyEncryption(EC-Curve25519) - */ - INode root = assertTranslationRoot(nodes, PrivateKey.class, 2, "EC-Curve25519"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode pke = assertChildNode(root, PublicKeyEncryption.class, 2, "EC-Curve25519"); - assertLeafNode(pke, EllipticCurve.class, "Curve25519"); - assertLeafNode(pke, Oid.class, "1.2.840.10045.2.1"); - } - - // findingId == 1 (ECC.construct(curve="Ed25519")) - private void assertECCConstruct( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertKeyContextDetection(detectionStore); - assertCurveChild(this, detectionStore, "Ed25519"); - - /* - * Translation: Key(EC-Curve25519) → KeyGeneration, PublicKeyEncryption(EC-Curve25519) - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "EC-Curve25519"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode pke = assertChildNode(root, PublicKeyEncryption.class, 2, "EC-Curve25519"); - assertLeafNode(pke, EllipticCurve.class, "Curve25519"); - assertLeafNode(pke, Oid.class, "1.2.840.10045.2.1"); - } - - // findingId == 2 (ECC.import_key(...)) - private void assertECCImportKey( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertKeyContextDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: Key(EC) → KeyGeneration, PublicKeyEncryption(EC) - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "EC"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - INode pke = assertChildNode(root, PublicKeyEncryption.class, 1, "EC"); - assertLeafNode(pke, Oid.class, "1.2.840.10045.2.1"); - } - } - - // ------------------------------------------------------------------------- - // ElGamal - // ------------------------------------------------------------------------- - - static class ElGamalTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoPublicKeyElGamalTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - switch (findingId) { - case 0 -> assertElGamalGenerate(detectionStore, nodes); - case 1 -> assertElGamalConstruct(detectionStore, nodes); - default -> throw new AssertionError("Unexpected findingId: " + findingId); - } - } - - // findingId == 0 (ElGamal.generate()) - private void assertElGamalGenerate( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertGenerateDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: PrivateKey(ElGamal) → KeyGeneration, PublicKeyEncryption(ElGamal) - */ - INode root = assertTranslationRoot(nodes, PrivateKey.class, 2, "ElGamal"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - assertChildNode(root, PublicKeyEncryption.class, 0, "ElGamal"); - } - - // findingId == 1 (ElGamal.construct(...)) - private void assertElGamalConstruct( - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertKeyContextDetection(detectionStore); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: Key(ElGamal) → KeyGeneration, PublicKeyEncryption(ElGamal) - */ - INode root = assertTranslationRoot(nodes, Key.class, 2, "ElGamal"); - assertLeafNode(root, KeyGeneration.class, "KEYGENERATION"); - assertChildNode(root, PublicKeyEncryption.class, 0, "ElGamal"); - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java deleted file mode 100644 index 88352e322..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoSignatureTest.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.SignatureAction; -import com.ibm.engine.model.ValueAction; -import com.ibm.engine.model.context.SignatureContext; -import com.ibm.mapper.model.BlockSize; -import com.ibm.mapper.model.DigestSize; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.Key; -import com.ibm.mapper.model.MessageDigest; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.ProbabilisticSignatureScheme; -import com.ibm.mapper.model.PublicKeyEncryption; -import com.ibm.mapper.model.Signature; -import com.ibm.mapper.model.functionality.Digest; -import com.ibm.mapper.model.functionality.KeyGeneration; -import com.ibm.mapper.model.functionality.Sign; -import com.ibm.mapper.model.functionality.Verify; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -class PythonCryptoSignatureTest { - - // ------------------------------------------------------------------------- - // Shared detection-store helpers - // ------------------------------------------------------------------------- - - private static void assertRootValueAction( - @Nonnull DetectionStore detectionStore, - @Nonnull Class expectedContext, - @Nonnull String expectedValue) { - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(expectedContext); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(ValueAction.class); - assertThat(value.asString()).isEqualTo(expectedValue); - } - - private static void assertSignatureActionChild( - @Nonnull DetectionStore detectionStore, - @Nonnull TestBase test, - @Nonnull String expectedAction) { - DetectionStore store = - test.getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); - assertThat(store).isNotNull(); - assertThat(store.getDetectionValues()).hasSize(1); - assertThat(store.getDetectionValueContext()).isInstanceOf(SignatureContext.class); - IValue value = store.getDetectionValues().get(0); - assertThat(value).isInstanceOf(SignatureAction.class); - assertThat(value.asString()).isEqualTo(expectedAction); - } - - // ------------------------------------------------------------------------- - // Shared translation helpers - // ------------------------------------------------------------------------- - - private static INode assertTranslationRoot( - @Nonnull List nodes, - @Nonnull Class kind, - int childCount, - @Nonnull String expectedName) { - assertThat(nodes).hasSize(1); - INode root = nodes.get(0); - assertThat(root.getKind()).isEqualTo(kind); - assertThat(root.getChildren()).hasSize(childCount); - assertThat(root.asString()).isEqualTo(expectedName); - return root; - } - - private static void assertLeafNode( - @Nonnull INode parent, - @Nonnull Class type, - @Nonnull String expectedValue) { - INode node = parent.getChildren().get(type); - assertThat(node).isNotNull(); - assertThat(node.getChildren()).isEmpty(); - assertThat(node.asString()).isEqualTo(expectedValue); - } - - /** Asserts a MessageDigest child on parent, returning it for further inspection. */ - private static INode assertMessageDigestChild( - @Nonnull INode parent, @Nonnull String expectedName, int childCount) { - INode md = parent.getChildren().get(MessageDigest.class); - assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo(expectedName); - assertThat(md.getChildren()).hasSize(childCount); - return md; - } - - /** Asserts a Key child on parent, returning it for further inspection. */ - private static INode assertKeyChild( - @Nonnull INode parent, @Nonnull String expectedAlgorithm, int childCount) { - INode key = parent.getChildren().get(Key.class); - assertThat(key).isNotNull(); - assertThat(key.asString()).isEqualTo(expectedAlgorithm); - assertThat(key.getChildren()).hasSize(childCount); - return key; - } - - // ------------------------------------------------------------------------- - // DSS - // ------------------------------------------------------------------------- - - static class DSSSignTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSSignTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - // Signature SHA256withDSA - assertRootValueAction(detectionStore, SignatureContext.class, "DSS"); - assertSignatureActionChild(detectionStore, this, "SIGN"); - - INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withDSA"); - assertLeafNode(sig, Oid.class, "2.16.840.1.101.3.4.3.2"); - INode key = assertKeyChild(sig, "DSA", 2); - assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); - INode md = assertMessageDigestChild(sig, "SHA256", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(md, DigestSize.class, "256"); - assertLeafNode(md, BlockSize.class, "512"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(sig, Sign.class, "SIGN"); - } - } - } - - static class DSSVerifyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignatureDSSVerifyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - assertRootValueAction(detectionStore, SignatureContext.class, "DSS"); - assertSignatureActionChild(detectionStore, this, "VERIFY"); - - INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withDSA"); - assertLeafNode(sig, Oid.class, "2.16.840.1.101.3.4.3.2"); - INode key = assertKeyChild(sig, "DSA", 2); - assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); - INode md = assertMessageDigestChild(sig, "SHA256", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(md, DigestSize.class, "256"); - assertLeafNode(md, BlockSize.class, "512"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(sig, Verify.class, "VERIFY"); - } - } - } - - // ------------------------------------------------------------------------- - // EdDSA - // ------------------------------------------------------------------------- - - static class EdDSASignTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSASignTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - // Signature EdDSA - assertRootValueAction(detectionStore, SignatureContext.class, "EDDSA"); - assertSignatureActionChild(detectionStore, this, "SIGN"); - - INode sig = assertTranslationRoot(nodes, Signature.class, 2, "EdDSA"); - INode md = assertMessageDigestChild(sig, "SHA512", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.3"); - assertLeafNode(md, DigestSize.class, "512"); - assertLeafNode(md, BlockSize.class, "1024"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(sig, Sign.class, "SIGN"); - } - } - } - - static class EdDSAVerifyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignatureEdDSAVerifyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - assertRootValueAction(detectionStore, SignatureContext.class, "EDDSA"); - assertSignatureActionChild(detectionStore, this, "VERIFY"); - - INode sig = assertTranslationRoot(nodes, Signature.class, 2, "EdDSA"); - INode md = assertMessageDigestChild(sig, "SHA512", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.3"); - assertLeafNode(md, DigestSize.class, "512"); - assertLeafNode(md, BlockSize.class, "1024"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(sig, Verify.class, "VERIFY"); - } - } - } - - // ------------------------------------------------------------------------- - // PKCS1v15 - // ------------------------------------------------------------------------- - - static class PKCS1v15SignTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15SignTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - // Signature SHA256withRSA - assertRootValueAction(detectionStore, SignatureContext.class, "RSA"); - assertSignatureActionChild(detectionStore, this, "SIGN"); - - INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withRSA"); - assertLeafNode(sig, Oid.class, "1.2.840.113549.1.1.11"); - INode key = assertKeyChild(sig, "RSA", 2); - assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); - INode pke = key.getChildren().get(PublicKeyEncryption.class); - assertThat(pke).isNotNull(); - assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); - INode md = assertMessageDigestChild(sig, "SHA256", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(md, DigestSize.class, "256"); - assertLeafNode(md, BlockSize.class, "512"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(sig, Sign.class, "SIGN"); - } - } - } - - static class PKCS1v15VerifyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignaturePKCS1v15VerifyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - assertRootValueAction(detectionStore, SignatureContext.class, "RSA"); - assertSignatureActionChild(detectionStore, this, "VERIFY"); - - INode sig = assertTranslationRoot(nodes, Signature.class, 4, "SHA256withRSA"); - assertLeafNode(sig, Oid.class, "1.2.840.113549.1.1.11"); - INode key = assertKeyChild(sig, "RSA", 2); - assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); - INode pke = key.getChildren().get(PublicKeyEncryption.class); - assertThat(pke).isNotNull(); - assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); - INode md = assertMessageDigestChild(sig, "SHA256", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(md, DigestSize.class, "256"); - assertLeafNode(md, BlockSize.class, "512"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(sig, Verify.class, "VERIFY"); - } - } - } - - // ------------------------------------------------------------------------- - // PSS - // ------------------------------------------------------------------------- - - static class PSSSignTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSSignTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - // ProbabilisticSignatureScheme RSASSA-PSS - assertRootValueAction(detectionStore, SignatureContext.class, "RSA-PSS"); - assertSignatureActionChild(detectionStore, this, "SIGN"); - - INode pss = - assertTranslationRoot( - nodes, ProbabilisticSignatureScheme.class, 4, "RSASSA-PSS"); - assertLeafNode(pss, Oid.class, "1.2.840.113549.1.1.10"); - INode key = assertKeyChild(pss, "RSA", 2); - assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); - INode pke = key.getChildren().get(PublicKeyEncryption.class); - assertThat(pke).isNotNull(); - assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); - INode md = assertMessageDigestChild(pss, "SHA256", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(md, DigestSize.class, "256"); - assertLeafNode(md, BlockSize.class, "512"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(pss, Sign.class, "SIGN"); - } - } - } - - static class PSSVerifyTest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/crypto/PythonCryptoSignaturePSSVerifyTestFile.py", - this); - } - - @Override - public void asserts( - int findingId, - @Nonnull - DetectionStore - detectionStore, - @Nonnull List nodes) { - if (findingId == 2) { - assertRootValueAction(detectionStore, SignatureContext.class, "RSA-PSS"); - assertSignatureActionChild(detectionStore, this, "VERIFY"); - - INode pss = - assertTranslationRoot( - nodes, ProbabilisticSignatureScheme.class, 4, "RSASSA-PSS"); - assertLeafNode(pss, Oid.class, "1.2.840.113549.1.1.10"); - INode key = assertKeyChild(pss, "RSA", 2); - assertLeafNode(key, KeyGeneration.class, "KEYGENERATION"); - INode pke = key.getChildren().get(PublicKeyEncryption.class); - assertThat(pke).isNotNull(); - assertLeafNode(pke, Oid.class, "1.2.840.113549.1.1.1"); - INode md = assertMessageDigestChild(pss, "SHA256", 4); - assertLeafNode(md, Oid.class, "2.16.840.1.101.3.4.2.1"); - assertLeafNode(md, DigestSize.class, "256"); - assertLeafNode(md, BlockSize.class, "512"); - assertLeafNode(md, Digest.class, "DIGEST"); - assertLeafNode(pss, Verify.class, "VERIFY"); - } - } - } -} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/aead/PycaAESGCMTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAESGCMTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/aead/PycaAESGCMTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAESGCMTest.java index d3409b362..7811c3317 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/aead/PycaAESGCMTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/aead/PycaAESGCMTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.aead; +package com.ibm.plugin.rules.detection.pyca.aead; import static org.assertj.core.api.Assertions.assertThat; @@ -52,7 +52,7 @@ class PycaAESGCMTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/aead/PycaAESGCMTestFile.py", this); + "src/test/files/rules/detection/pyca/aead/PycaAESGCMTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/aead/PycaChaCha20Poly1305Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/aead/PycaChaCha20Poly1305Test.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/aead/PycaChaCha20Poly1305Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/aead/PycaChaCha20Poly1305Test.java index 004201c31..88c1b01f4 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/aead/PycaChaCha20Poly1305Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/aead/PycaChaCha20Poly1305Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.aead; +package com.ibm.plugin.rules.detection.pyca.aead; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaChaCha20Poly1305Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/aead/PycaChaCha20Poly1305TestFile.py", this); + "src/test/files/rules/detection/pyca/aead/PycaChaCha20Poly1305TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DSA/PycaDSANumbersTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DSA/PycaDSANumbersTest.java similarity index 96% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DSA/PycaDSANumbersTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DSA/PycaDSANumbersTest.java index 2178efc29..beebbd7c6 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DSA/PycaDSANumbersTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DSA/PycaDSANumbersTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.DSA; +package com.ibm.plugin.rules.detection.pyca.asymmetric.DSA; import static org.assertj.core.api.Assertions.assertThat; @@ -47,7 +47,8 @@ class PycaDSANumbersTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/DSA/PycaDSANumbersTestFile.py", this); + "src/test/files/rules/detection/pyca/asymmetric/DSA/PycaDSANumbersTestFile.py", + this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DSA/PycaDSASignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DSA/PycaDSASignTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DSA/PycaDSASignTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DSA/PycaDSASignTest.java index 295196b08..1c4cfcafe 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DSA/PycaDSASignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DSA/PycaDSASignTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.DSA; +package com.ibm.plugin.rules.detection.pyca.asymmetric.DSA; import static org.assertj.core.api.Assertions.assertThat; @@ -54,7 +54,7 @@ class PycaDSASignTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/DSA/PycaDSASignTestFile.py", this); + "src/test/files/rules/detection/pyca/asymmetric/DSA/PycaDSASignTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java index 06ce44018..4097dcf75 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.DiffieHellman; +package com.ibm.plugin.rules.detection.pyca.asymmetric.DiffieHellman; import static org.assertj.core.api.Assertions.assertThat; @@ -47,7 +47,7 @@ public final class PycaDiffieHellmanGenerateTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanGenerateTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java index bdd8bf7dc..26099a4a9 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.DiffieHellman; +package com.ibm.plugin.rules.detection.pyca.asymmetric.DiffieHellman; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +45,7 @@ class PycaDiffieHellmanNumbersTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/DiffieHellman/PycaDiffieHellmanNumbersTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java index dde89a44a..d34d4fa91 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.EllipticCurve; +package com.ibm.plugin.rules.detection.pyca.asymmetric.EllipticCurve; import static org.assertj.core.api.Assertions.assertThat; @@ -46,7 +46,7 @@ class PycaEllipticCurveDeriveTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveDeriveTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java index ca421610e..c073991dc 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.EllipticCurve; +package com.ibm.plugin.rules.detection.pyca.asymmetric.EllipticCurve; import static org.assertj.core.api.Assertions.assertThat; @@ -57,7 +57,7 @@ class PycaEllipticCurveKeyExchangeTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveKeyExchangeTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java similarity index 90% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java index 2c95fc794..9c1f7d79c 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.EllipticCurve; +package com.ibm.plugin.rules.detection.pyca.asymmetric.EllipticCurve; import com.ibm.engine.detection.DetectionStore; import com.ibm.mapper.model.INode; @@ -38,7 +38,7 @@ class PycaEllipticCurveNumbersTest extends TestBase { @Test void test() { PythonCheckVerifier.verifyNoIssue( - "src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveNumbersTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java index c6156730e..84e4928eb 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSign2Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.EllipticCurve; +package com.ibm.plugin.rules.detection.pyca.asymmetric.EllipticCurve; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaEllipticCurveSign2Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSign2TestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java index 42e6c8347..e70a1c3df 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSignTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.EllipticCurve; +package com.ibm.plugin.rules.detection.pyca.asymmetric.EllipticCurve; import static org.assertj.core.api.Assertions.assertThat; @@ -54,7 +54,7 @@ class PycaEllipticCurveSignTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveSignTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java similarity index 91% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java index ab38d7bcb..2941263c2 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.EllipticCurve; +package com.ibm.plugin.rules.detection.pyca.asymmetric.EllipticCurve; import com.ibm.engine.detection.DetectionStore; import com.ibm.mapper.model.INode; @@ -41,7 +41,7 @@ class PycaEllipticCurveVerifyTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py", + "src/test/files/rules/detection/pyca/asymmetric/EllipticCurve/PycaEllipticCurveVerifyTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSADecryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSADecryptTest.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSADecryptTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSADecryptTest.java index 416e98ba3..274f3bcd8 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSADecryptTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSADecryptTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.RSA; +package com.ibm.plugin.rules.detection.pyca.asymmetric.RSA; import static org.assertj.core.api.Assertions.assertThat; @@ -58,7 +58,8 @@ class PycaRSADecryptTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/RSA/PycaRSADecryptTestFile.py", this); + "src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSADecryptTestFile.py", + this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSANumbersTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSANumbersTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSANumbersTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSANumbersTest.java index c78a44f64..5321621ee 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSANumbersTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSANumbersTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.RSA; +package com.ibm.plugin.rules.detection.pyca.asymmetric.RSA; import static org.assertj.core.api.Assertions.assertThat; @@ -47,7 +47,8 @@ class PycaRSANumbersTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/RSA/PycaRSANumbersTestFile.py", this); + "src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSANumbersTestFile.py", + this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSASign1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSASign1Test.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSASign1Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSASign1Test.java index e57bdb78a..25c86fe9c 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSASign1Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSASign1Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.RSA; +package com.ibm.plugin.rules.detection.pyca.asymmetric.RSA; import static org.assertj.core.api.Assertions.assertThat; @@ -56,7 +56,7 @@ class PycaRSASign1Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/RSA/PycaRSASign1TestFile.py", this); + "src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSASign1TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSASign2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSASign2Test.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSASign2Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSASign2Test.java index bb5181e56..c39328fa6 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/asymmetric/RSA/PycaRSASign2Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/asymmetric/RSA/PycaRSASign2Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric.RSA; +package com.ibm.plugin.rules.detection.pyca.asymmetric.RSA; import static org.assertj.core.api.Assertions.assertThat; @@ -55,7 +55,7 @@ class PycaRSASign2Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/asymmetric/RSA/PycaRSASign2TestFile.py", this); + "src/test/files/rules/detection/pyca/asymmetric/RSA/PycaRSASign2TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaFernetDecryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernetDecryptTest.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaFernetDecryptTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernetDecryptTest.java index 10119414d..19f7d28cd 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaFernetDecryptTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernetDecryptTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.fernet; +package com.ibm.plugin.rules.detection.pyca.fernet; import static org.assertj.core.api.Assertions.assertThat; @@ -58,7 +58,7 @@ class PycaFernetDecryptTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/fernet/PycaFernetDecryptTestFile.py", this); + "src/test/files/rules/detection/pyca/fernet/PycaFernetDecryptTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaFernetEncryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernetEncryptTest.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaFernetEncryptTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernetEncryptTest.java index 759916b45..5ad5aa112 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaFernetEncryptTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaFernetEncryptTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.fernet; +package com.ibm.plugin.rules.detection.pyca.fernet; import static org.assertj.core.api.Assertions.assertThat; @@ -58,7 +58,7 @@ class PycaFernetEncryptTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/fernet/PycaFernetEncryptTestFile.py", this); + "src/test/files/rules/detection/pyca/fernet/PycaFernetEncryptTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaMultiFernetTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaMultiFernetTest.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaMultiFernetTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaMultiFernetTest.java index 36fe6893b..ac90ea5a5 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/fernet/PycaMultiFernetTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/fernet/PycaMultiFernetTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.fernet; +package com.ibm.plugin.rules.detection.pyca.fernet; import static org.assertj.core.api.Assertions.assertThat; @@ -59,7 +59,7 @@ class PycaMultiFernetTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/fernet/PycaMultiFernetTestFile.py", this); + "src/test/files/rules/detection/pyca/fernet/PycaMultiFernetTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHashDirectTest.java similarity index 96% rename from python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHashDirectTest.java index dd1305ba6..0e57b8a00 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/hash/PycaHashDirectTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHashDirectTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.hash; +package com.ibm.plugin.rules.detection.pyca.hash; import static org.assertj.core.api.Assertions.assertThat; @@ -46,7 +46,7 @@ class PycaHashDirectTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/hash/PycaHashDirectTest.py", this); + "src/test/files/rules/detection/pyca/hash/PycaHashDirectTest.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaConcatKDFHMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaConcatKDFHMACTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaConcatKDFHMACTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaConcatKDFHMACTest.java index 4c72b5be8..2e7bd5711 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaConcatKDFHMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaConcatKDFHMACTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaConcatKDFHMACTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaConcatKDFHMACTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaConcatKDFHMACTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaConcatKDFHashTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaConcatKDFHashTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaConcatKDFHashTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaConcatKDFHashTest.java index 68a47dbc9..e10a0c5f2 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaConcatKDFHashTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaConcatKDFHashTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -49,7 +49,7 @@ class PycaConcatKDFHashTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaConcatKDFHashTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaConcatKDFHashTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaHKDFExpandTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaHKDFExpandTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaHKDFExpandTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaHKDFExpandTest.java index 0eade96a6..585f7448b 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaHKDFExpandTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaHKDFExpandTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaHKDFExpandTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaHKDFExpandTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaHKDFExpandTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaHKDFTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaHKDFTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaHKDFTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaHKDFTest.java index e7a4a5f16..1db1ba235 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaHKDFTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaHKDFTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -49,7 +49,8 @@ class PycaHKDFTest extends TestBase { @Test void test() { - PythonCheckVerifier.verify("src/test/files/rules/detection/kdf/PycaHKDFTestFile.py", this); + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pyca/kdf/PycaHKDFTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaKBKDFCMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKBKDFCMACTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaKBKDFCMACTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKBKDFCMACTest.java index 0436832c1..16e7df570 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaKBKDFCMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKBKDFCMACTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaKBKDFCMACTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaKBKDFCMACTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaKBKDFCMACTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaKBKDFHMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKBKDFHMACTest.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaKBKDFHMACTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKBKDFHMACTest.java index ef0fad6b9..828cbf21d 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaKBKDFHMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaKBKDFHMACTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -52,7 +52,7 @@ class PycaKBKDFHMACTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaKBKDFHMACTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaKBKDFHMACTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaPBKDF2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaPBKDF2Test.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaPBKDF2Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaPBKDF2Test.java index bdcc9af1f..a714802e5 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaPBKDF2Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaPBKDF2Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -51,7 +51,7 @@ class PycaPBKDF2Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaPBKDF2TestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaPBKDF2TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaScryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaScryptTest.java similarity index 96% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaScryptTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaScryptTest.java index b137aabb5..f1a85a3fb 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaScryptTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaScryptTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +45,7 @@ class PycaScryptTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaScryptTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaScryptTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaX963KDFTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaX963KDFTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaX963KDFTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaX963KDFTest.java index 786fa46cb..9310d6380 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/kdf/PycaX963KDFTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/kdf/PycaX963KDFTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.kdf; +package com.ibm.plugin.rules.detection.pyca.kdf; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaX963KDFTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/kdf/PycaX963KDFTestFile.py", this); + "src/test/files/rules/detection/pyca/kdf/PycaX963KDFTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/keyagreement/PycaKeyAgreementTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/keyagreement/PycaKeyAgreementTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/keyagreement/PycaKeyAgreementTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/keyagreement/PycaKeyAgreementTest.java index bb88f0e77..9327a162f 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/keyagreement/PycaKeyAgreementTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/keyagreement/PycaKeyAgreementTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.keyagreement; +package com.ibm.plugin.rules.detection.pyca.keyagreement; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +45,8 @@ class PycaKeyAgreementTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/keyagreement/PycaKeyAgreementTestFile.py", this); + "src/test/files/rules/detection/pyca/keyagreement/PycaKeyAgreementTestFile.py", + this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaCMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaCMACTest.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaCMACTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaCMACTest.java index bbc0f3f2b..afeab14a3 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaCMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaCMACTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.mac; +package com.ibm.plugin.rules.detection.pyca.mac; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +45,8 @@ class PycaCMACTest extends TestBase { @Test void test() { - PythonCheckVerifier.verify("src/test/files/rules/detection/mac/PycaCMACTestFile.py", this); + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pyca/mac/PycaCMACTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaHMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaHMACTest.java similarity index 96% rename from python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaHMACTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaHMACTest.java index 9957f5381..374ee293d 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaHMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaHMACTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.mac; +package com.ibm.plugin.rules.detection.pyca.mac; import static org.assertj.core.api.Assertions.assertThat; @@ -47,7 +47,8 @@ class PycaHMACTest extends TestBase { @Test void test() { - PythonCheckVerifier.verify("src/test/files/rules/detection/mac/PycaHMACTestFile.py", this); + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pyca/mac/PycaHMACTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaMacDetectionInCustomFunctionTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaMacDetectionInCustomFunctionTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaMacDetectionInCustomFunctionTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaMacDetectionInCustomFunctionTest.java index 9a89f28eb..e7806b573 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaMacDetectionInCustomFunctionTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaMacDetectionInCustomFunctionTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.mac; +package com.ibm.plugin.rules.detection.pyca.mac; import static org.assertj.core.api.Assertions.assertThat; @@ -53,7 +53,7 @@ class PycaMacDetectionInCustomFunctionTest extends TestBase { @Test void testCryptographicOperationInCustomFunction() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/mac/PycaMacDetectionInCustomFunctionTestFile.py", + "src/test/files/rules/detection/pyca/mac/PycaMacDetectionInCustomFunctionTestFile.py", this); } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaPoly1305Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaPoly1305Test.java similarity index 96% rename from python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaPoly1305Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaPoly1305Test.java index fecc5bd37..54872cf69 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/mac/PycaPoly1305Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/mac/PycaPoly1305Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.mac; +package com.ibm.plugin.rules.detection.pyca.mac; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +45,7 @@ class PycaPoly1305Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/mac/PycaPoly1305TestFile.py", this); + "src/test/files/rules/detection/pyca/mac/PycaPoly1305TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/padding/PycaPaddingTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPaddingTest.java similarity index 97% rename from python/src/test/java/com/ibm/plugin/rules/detection/padding/PycaPaddingTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPaddingTest.java index a2f29030a..7d3a43556 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/padding/PycaPaddingTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPaddingTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.padding; +package com.ibm.plugin.rules.detection.pyca.padding; import static org.assertj.core.api.Assertions.assertThat; @@ -46,7 +46,7 @@ class PycaPaddingTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/padding/PycaPaddingTestFile.py", this); + "src/test/files/rules/detection/pyca/padding/PycaPaddingTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher1Test.java similarity index 98% rename from python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher1Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher1Test.java index 73a1d6ebb..36834055c 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher1Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher1Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.symmetric; +package com.ibm.plugin.rules.detection.pyca.symmetric; import static org.assertj.core.api.Assertions.assertThat; @@ -50,7 +50,7 @@ class PycaCipher1Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/symmetric/PycaCipher1TestFile.py", this); + "src/test/files/rules/detection/pyca/symmetric/PycaCipher1TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher2Test.java similarity index 96% rename from python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher2Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher2Test.java index 74ac657a9..a69bca299 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaCipher2Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher2Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.symmetric; +package com.ibm.plugin.rules.detection.pyca.symmetric; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +45,7 @@ class PycaCipher2Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/symmetric/PycaCipher2TestFile.py", this); + "src/test/files/rules/detection/pyca/symmetric/PycaCipher2TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher3Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher3Test.java new file mode 100644 index 000000000..0ad33a939 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher3Test.java @@ -0,0 +1,115 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pyca.symmetric; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Encrypt; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +class PycaCipher3Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pyca/symmetric/PycaCipher3TestFile.py", this); + } + + @SuppressWarnings("null") + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value0 = detectionStore.getDetectionValues().get(0); + assertThat(value0).isInstanceOf(Algorithm.class); + assertThat(value0.asString()).isEqualTo("AES"); + + List> store_1 = + getStoresOfValueType(CipherAction.class, detectionStore.getChildren()); + assertThat(store_1).isNotNull(); + for (DetectionStore store : store_1) { + assertThat(store.getDetectionValues()).hasSize(1); + assertThat(store.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value0_1 = store.getDetectionValues().get(0); + assertThat(value0_1).isInstanceOf(CipherAction.class); + assertThat(value0_1.asString()).isEqualTo("ENCRYPT"); + } + + // /* + // * Translation + // */ + assertThat(nodes).hasSize(1); + + // BlockCipher + INode blockCipherNode = nodes.get(0); + assertThat(blockCipherNode.getKind()).isEqualTo(BlockCipher.class); + assertThat(blockCipherNode.getChildren()).hasSize(4); + assertThat(blockCipherNode.asString()).isEqualTo("AES-CBC"); + + // Mode under BlockCipher + INode modeNode = blockCipherNode.getChildren().get(Mode.class); + assertThat(modeNode).isNotNull(); + assertThat(modeNode.getChildren()).isEmpty(); + assertThat(modeNode.asString()).isEqualTo("CBC"); + + // Oid under BlockCipher + INode oidNode = blockCipherNode.getChildren().get(Oid.class); + assertThat(oidNode).isNotNull(); + assertThat(oidNode.getChildren()).isEmpty(); + assertThat(oidNode.asString()).isEqualTo("2.16.840.1.101.3.4.1"); + + // Encrypt under BlockCipher + INode encryptNode = blockCipherNode.getChildren().get(Encrypt.class); + assertThat(encryptNode).isNotNull(); + assertThat(encryptNode.getChildren()).isEmpty(); + assertThat(encryptNode.asString()).isEqualTo("ENCRYPT"); + + // BlockSize under BlockCipher + INode blockSizeNode1 = blockCipherNode.getChildren().get(BlockSize.class); + assertThat(blockSizeNode1).isNotNull(); + assertThat(blockSizeNode1.getChildren()).isEmpty(); + assertThat(blockSizeNode1.asString()).isEqualTo("128"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaStreamCipher1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaStreamCipher1Test.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaStreamCipher1Test.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaStreamCipher1Test.java index 7c5b1f339..98776e4f0 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/symmetric/PycaStreamCipher1Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaStreamCipher1Test.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.symmetric; +package com.ibm.plugin.rules.detection.pyca.symmetric; import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +44,7 @@ class PycaStreamCipher1Test extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/symmetric/PycaStreamCipher1TestFile.py", this); + "src/test/files/rules/detection/pyca/symmetric/PycaStreamCipher1TestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/wrapping/PycaWrappingTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrappingTest.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/wrapping/PycaWrappingTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrappingTest.java index 003eaaf9c..9c1a34897 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/wrapping/PycaWrappingTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrappingTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.wrapping; +package com.ibm.plugin.rules.detection.pyca.wrapping; import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +44,7 @@ class PycaWrappingTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/wrapping/PycaWrappingTestFile.py", this); + "src/test/files/rules/detection/pyca/wrapping/PycaWrappingTestFile.py", this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/wrapping/PycaWrappingWithPaddingTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrappingWithPaddingTest.java similarity index 95% rename from python/src/test/java/com/ibm/plugin/rules/detection/wrapping/PycaWrappingWithPaddingTest.java rename to python/src/test/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrappingWithPaddingTest.java index 37d0bb788..bfeeec87f 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/wrapping/PycaWrappingWithPaddingTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pyca/wrapping/PycaWrappingWithPaddingTest.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.wrapping; +package com.ibm.plugin.rules.detection.pyca.wrapping; import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +44,8 @@ class PycaWrappingWithPaddingTest extends TestBase { @Test void test() { PythonCheckVerifier.verify( - "src/test/files/rules/detection/wrapping/PycaWrappingWithPaddingTestFile.py", this); + "src/test/files/rules/detection/pyca/wrapping/PycaWrappingWithPaddingTestFile.py", + this); } @Override diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/AESTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/AESTest.java new file mode 100644 index 000000000..d84e3b32f --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/AESTest.java @@ -0,0 +1,100 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.mapper.model.Oid; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AESTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/AESTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("AES"); + + DetectionStore modeStore = + getStoreOfValueType(com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(modeStore).isNotNull(); + assertThat(modeStore.getDetectionValues().get(0).asString()).isEqualTo("MODE_CBC"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); + assertThat(cipher.getChildren()).hasSize(4); + assertThat(cipher.asString()).isEqualTo("AES-CBC"); + + INode mode = cipher.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.getChildren()).isEmpty(); + assertThat(mode.asString()).isEqualTo("CBC"); + + INode oid = cipher.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.1"); + + INode blockSize = cipher.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("128"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java new file mode 100644 index 000000000..2e2960083 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java @@ -0,0 +1,88 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class BlowfishTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("Blowfish"); + + DetectionStore modeStore = + getStoreOfValueType(com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(modeStore).isNotNull(); + assertThat(modeStore.getDetectionValues().get(0).asString()).isEqualTo("MODE_CBC"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); + assertThat(cipher.getChildren()).hasSize(1); + assertThat(cipher.asString()).isEqualTo("Blowfish"); + + INode mode = cipher.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.getChildren()).isEmpty(); + assertThat(mode.asString()).isEqualTo("CBC"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java new file mode 100644 index 000000000..12c91b316 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java @@ -0,0 +1,94 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class CAST5Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("CAST5"); + + DetectionStore modeStore = + getStoreOfValueType(com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(modeStore).isNotNull(); + assertThat(modeStore.getDetectionValues().get(0).asString()).isEqualTo("MODE_CBC"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); + assertThat(cipher.getChildren()).hasSize(2); + assertThat(cipher.asString()).isEqualTo("CAST-128"); + + INode mode = cipher.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.getChildren()).isEmpty(); + assertThat(mode.asString()).isEqualTo("CBC"); + + INode blockSize = cipher.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("64"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java new file mode 100644 index 000000000..94fd9a09c --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java @@ -0,0 +1,80 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.AuthenticatedEncryption; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ChaCha20Poly1305Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("ChaCha20Poly1305"); + assertThat(detectionStore.getChildren()).isEmpty(); + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(AuthenticatedEncryption.class); + assertThat(cipher.getChildren()).hasSize(1); + assertThat(cipher.asString()).isEqualTo("ChaCha20Poly1305"); + + INode messageDigest = cipher.getChildren().get(MessageDigest.class); + assertThat(messageDigest).isNotNull(); + assertThat(messageDigest.getChildren()).hasSize(1); + assertThat(messageDigest.asString()).isEqualTo("Poly1305"); + + INode digest = messageDigest.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Test.java new file mode 100644 index 000000000..443a3b348 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Test.java @@ -0,0 +1,68 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.StreamCipher; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ChaCha20Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/ChaCha20TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("ChaCha20"); + assertThat(detectionStore.getChildren()).isEmpty(); + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(StreamCipher.class); + assertThat(cipher.getChildren()).isEmpty(); + assertThat(cipher.asString()).isEqualTo("ChaCha20"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java new file mode 100644 index 000000000..714ebbe3a --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java @@ -0,0 +1,100 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.Mode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class DESTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("DES"); + + DetectionStore modeStore = + getStoreOfValueType(com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(modeStore).isNotNull(); + assertThat(modeStore.getDetectionValues().get(0).asString()).isEqualTo("MODE_ECB"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); + assertThat(cipher.getChildren()).hasSize(4); + assertThat(cipher.asString()).isEqualTo("DES56-ECB"); + + INode mode = cipher.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.getChildren()).isEmpty(); + assertThat(mode.asString()).isEqualTo("ECB"); + + INode keyLength = cipher.getChildren().get(KeyLength.class); + assertThat(keyLength).isNotNull(); + assertThat(keyLength.getChildren()).isEmpty(); + assertThat(keyLength.asString()).isEqualTo("56"); + + INode blockSize = cipher.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("64"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1OAEPTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1OAEPTest.java new file mode 100644 index 000000000..f7d5dac8a --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1OAEPTest.java @@ -0,0 +1,98 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Padding; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PKCS1OAEPTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/PKCS1OAEPTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("PKCS1_OAEP"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + DetectionStore keyStore = + getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + if (keyStore != null) { + assertThat(keyStore.getDetectionValues()).hasSize(1); + assertThat(keyStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + assertThat(keyStore.getDetectionValues().get(0)).isInstanceOf(Algorithm.class); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(PublicKeyEncryption.class); + assertThat(cipher.getChildren()).hasSize(2); + assertThat(cipher.asString()).isEqualTo("RSA-OAEP"); + + INode oid = cipher.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.113549.1.1.7"); + + INode padding = cipher.getChildren().get(Padding.class); + assertThat(padding).isNotNull(); + assertThat(padding.getChildren()).isEmpty(); + assertThat(padding.asString()).isEqualTo("OAEP"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1v15Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1v15Test.java new file mode 100644 index 000000000..ae488c6ff --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PKCS1v15Test.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Padding; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PKCS1v15Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/PKCS1v15TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("PKCS1_v1_5"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(PublicKeyEncryption.class); + assertThat(cipher.getChildren()).hasSize(2); + assertThat(cipher.asString()).isEqualTo("RSA"); + + INode oid = cipher.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.113549.1.1.1"); + + INode padding = cipher.getChildren().get(Padding.class); + assertThat(padding).isNotNull(); + assertThat(padding.getChildren()).isEmpty(); + assertThat(padding.asString()).isEqualTo("PKCS1"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java new file mode 100644 index 000000000..71338d5f6 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java @@ -0,0 +1,195 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.mapper.model.AuthenticatedEncryption; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.Mode; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.Encrypt; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PythonCryptoHPKETest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> assertECCImportKey(detectionStore, nodes); + case 1 -> assertHPKENew(detectionStore, nodes); + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } + + // ------------------------------------------------------------------------- + // findingId == 0 (ECC.import_key(...)) + // ------------------------------------------------------------------------- + + private void assertECCImportKey( + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(KeyContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) value).getAction()).isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: Key(EC) → KeyGeneration, PublicKeyEncryption(EC) → Oid + */ + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.asString()).isEqualTo("EC"); + assertThat(root.getChildren()).hasSize(2); + + INode pke = root.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.asString()).isEqualTo("EC"); + assertThat(pke.getChildren()).hasSize(1); + INode oid = pke.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.asString()).isEqualTo("1.2.840.10045.2.1"); + + INode keyGen = root.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + } + + // ------------------------------------------------------------------------- + // findingId == 1 (HPKE.new(key, AES128_GCM)) + // ------------------------------------------------------------------------- + + private void assertHPKENew( + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("HPKE"); + + // Children: ENCRYPT action, two Algorithm stores (key and AEAD), plus a KeyAction child + // from the ECC import_key detection that is promoted as a sub-finding. + assertThat(detectionStore.getChildren()).hasSize(4); + + DetectionStore encryptStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + assertThat(encryptStore).isNotNull(); + assertThat(encryptStore.getDetectionValues()).hasSize(1); + IValue encryptValue = encryptStore.getDetectionValues().get(0); + assertThat(encryptValue).isInstanceOf(CipherAction.class); + assertThat(((CipherAction) encryptValue).getAction()) + .isEqualTo(CipherAction.Action.ENCRYPT); + + List> algoStores = + getStoresOfValueType(Algorithm.class, detectionStore.getChildren()); + assertThat(algoStores).hasSize(2); + algoStores.forEach( + s -> { + assertThat(s.getDetectionValues()).hasSize(1); + assertThat(s.getDetectionValues().get(0)).isInstanceOf(Algorithm.class); + }); + + /* + * Translation (enriched): + * PublicKeyEncryption(EC) + * ├─ Encrypt + * ├─ Oid(1.2.840.10045.2.1) + * └─ AuthenticatedEncryption(AES128-GCM) + * ├─ BlockSize(128) + * ├─ Oid(2.16.840.1.101.3.4.1.6) + * ├─ KeyLength(128) + * └─ Mode(GCM) + */ + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PublicKeyEncryption.class); + assertThat(root.asString()).isEqualTo("EC"); + assertThat(root.getChildren()).hasSize(3); + + INode encrypt = root.getChildren().get(Encrypt.class); + assertThat(encrypt).isNotNull(); + assertThat(encrypt.asString()).isEqualTo("ENCRYPT"); + + INode rootOid = root.getChildren().get(Oid.class); + assertThat(rootOid).isNotNull(); + assertThat(rootOid.asString()).isEqualTo("1.2.840.10045.2.1"); + + INode aead = root.getChildren().get(AuthenticatedEncryption.class); + assertThat(aead).isNotNull(); + assertThat(aead.asString()).isEqualTo("AES128-GCM"); + assertThat(aead.getChildren()).hasSize(4); + + INode blockSize = aead.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.asString()).isEqualTo("128"); + + INode aeadOid = aead.getChildren().get(Oid.class); + assertThat(aeadOid).isNotNull(); + assertThat(aeadOid.asString()).isEqualTo("2.16.840.1.101.3.4.1.6"); + + INode keyLength = aead.getChildren().get(KeyLength.class); + assertThat(keyLength).isNotNull(); + assertThat(keyLength.asString()).isEqualTo("128"); + + INode mode = aead.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.asString()).isEqualTo("GCM"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java new file mode 100644 index 000000000..46fa04a3c --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java @@ -0,0 +1,88 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class RC2Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RC2"); + + DetectionStore modeStore = + getStoreOfValueType(com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(modeStore).isNotNull(); + assertThat(modeStore.getDetectionValues().get(0).asString()).isEqualTo("MODE_CBC"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); + assertThat(cipher.getChildren()).hasSize(1); + assertThat(cipher.asString()).isEqualTo("RC2"); + + INode mode = cipher.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.getChildren()).isEmpty(); + assertThat(mode.asString()).isEqualTo("CBC"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC4Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC4Test.java new file mode 100644 index 000000000..c5e0b7336 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC4Test.java @@ -0,0 +1,77 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.StreamCipher; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class RC4Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/RC4TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RC4"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(StreamCipher.class); + assertThat(cipher.getChildren()).isEmpty(); + assertThat(cipher.asString()).isEqualTo("RC4"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/Salsa20Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/Salsa20Test.java new file mode 100644 index 000000000..5805dcca0 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/Salsa20Test.java @@ -0,0 +1,83 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.StreamCipher; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class Salsa20Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/Salsa20TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("Salsa20"); + + DetectionStore actionStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + if (actionStore != null) { + assertThat(actionStore.getDetectionValues().get(0).asString()) + .satisfiesAnyOf( + s -> assertThat(s).isEqualTo("ENCRYPT"), + s -> assertThat(s).isEqualTo("DECRYPT")); + } + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(StreamCipher.class); + assertThat(cipher.getChildren()).hasSize(1); + assertThat(cipher.asString()).isEqualTo("Salsa20"); + + INode keyLength = cipher.getChildren().get(KeyLength.class); + assertThat(keyLength).isNotNull(); + assertThat(keyLength.getChildren()).isEmpty(); + assertThat(keyLength.asString()).isEqualTo("128"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java new file mode 100644 index 000000000..134b3062a --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java @@ -0,0 +1,84 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class TripleDESTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("3DES"); + + DetectionStore modeStore = + getStoreOfValueType(com.ibm.engine.model.Mode.class, detectionStore.getChildren()); + assertThat(modeStore).isNotNull(); + assertThat(modeStore.getDetectionValues().get(0).asString()).isEqualTo("MODE_CBC"); + + assertThat(nodes).hasSize(1); + INode cipher = nodes.get(0); + assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); + assertThat(cipher.getChildren()).hasSize(2); + assertThat(cipher.asString()).isEqualTo("3DES"); + + INode mode = cipher.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.getChildren()).isEmpty(); + assertThat(mode.asString()).isEqualTo("CBC"); + + INode blockSize = cipher.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("64"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2bTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2bTest.java new file mode 100644 index 000000000..f1c54fe17 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2bTest.java @@ -0,0 +1,80 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.SaltLength; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class BLAKE2bTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/BLAKE2bTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("BLAKE2b"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(2); + assertThat(md.asString()).isEqualTo("BLAKE2b"); + + INode saltLength = md.getChildren().get(SaltLength.class); + assertThat(saltLength).isNotNull(); + assertThat(saltLength.getChildren()).isEmpty(); + assertThat(saltLength.asString()).isEqualTo("128"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2sTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2sTest.java new file mode 100644 index 000000000..53a984914 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/BLAKE2sTest.java @@ -0,0 +1,80 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.SaltLength; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class BLAKE2sTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/BLAKE2sTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("BLAKE2s"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(2); + assertThat(md.asString()).isEqualTo("BLAKE2s"); + + INode saltLength = md.getChildren().get(SaltLength.class); + assertThat(saltLength).isNotNull(); + assertThat(saltLength.getChildren()).isEmpty(); + assertThat(saltLength.asString()).isEqualTo("64"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD2Test.java new file mode 100644 index 000000000..9603d7ff5 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD2Test.java @@ -0,0 +1,86 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class MD2Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/MD2TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("MD2"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(3); + assertThat(md.asString()).isEqualTo("MD2"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("128"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("128"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD5Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD5Test.java new file mode 100644 index 000000000..4841ea4b2 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/MD5Test.java @@ -0,0 +1,86 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class MD5Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/MD5TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("MD5"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(3); + assertThat(md.asString()).isEqualTo("MD5"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("128"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/RIPEMD160Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/RIPEMD160Test.java new file mode 100644 index 000000000..9ae8ab849 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/RIPEMD160Test.java @@ -0,0 +1,80 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class RIPEMD160Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/RIPEMD160TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RIPEMD160"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(2); + assertThat(md.asString()).isEqualTo("RIPEMD-160"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("160"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java new file mode 100644 index 000000000..098906082 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA1Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA1"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA1"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.3.14.3.2.26"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("160"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java new file mode 100644 index 000000000..2aa989158 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA224Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA224"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA224"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.4"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("224"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java new file mode 100644 index 000000000..c57233605 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA256Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA256"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA256"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java new file mode 100644 index 000000000..994af8f7a --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA384Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA384"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA384"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("1024"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.2"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("384"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_224Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_224Test.java new file mode 100644 index 000000000..028159f49 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_224Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA3_224Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA3_224TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA3_224"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA3-224"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("1152"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.7"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("224"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_256Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_256Test.java new file mode 100644 index 000000000..59872895c --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_256Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA3_256Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA3_256TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA3_256"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA3-256"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("1088"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.8"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_384Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_384Test.java new file mode 100644 index 000000000..15e7518cb --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_384Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA3_384Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA3_384TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA3_384"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA3-384"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("832"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.9"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("384"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_512Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_512Test.java new file mode 100644 index 000000000..1b757a736 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA3_512Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA3_512Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA3_512TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA3_512"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA3-512"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("576"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.10"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("512"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java new file mode 100644 index 000000000..9485cc62f --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SHA512Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("SHA512"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA512"); + + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("1024"); + + INode oid = md.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("512"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/TupleHash128Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/TupleHash128Test.java new file mode 100644 index 000000000..4ba2c2ad0 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/TupleHash128Test.java @@ -0,0 +1,80 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class TupleHash128Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/TupleHash128TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("TupleHash128"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(2); + assertThat(md.asString()).isEqualTo("TupleHash"); + + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("128"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/cSHAKE256Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/cSHAKE256Test.java new file mode 100644 index 000000000..82a4b7db7 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/cSHAKE256Test.java @@ -0,0 +1,80 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.hash; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.ParameterSetIdentifier; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class cSHAKE256Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/hash/cSHAKE256TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(DigestContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("cSHAKE256"); + + assertThat(nodes).hasSize(1); + INode md = nodes.get(0); + assertThat(md).isInstanceOf(MessageDigest.class); + assertThat(md.getChildren()).hasSize(2); + assertThat(md.asString()).isEqualTo("cSHAKE256"); + + INode parameterSetIdentifier = md.getChildren().get(ParameterSetIdentifier.class); + assertThat(parameterSetIdentifier).isNotNull(); + assertThat(parameterSetIdentifier.getChildren()).isEmpty(); + assertThat(parameterSetIdentifier.asString()).isEqualTo("256"); + + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/BcryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/BcryptTest.java new file mode 100644 index 000000000..0d05c8fc4 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/BcryptTest.java @@ -0,0 +1,76 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.kdf; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.AlgorithmParameter; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class BcryptTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verifyNoIssue( + "src/test/files/rules/detection/pycrypto/kdf/BcryptTestFile.py", this); + } + + @Override + @SuppressWarnings("unchecked") + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(2); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("bcrypt"); + + IValue iterValue = + detectionStore.getDetectionValues().stream() + .filter(v -> v instanceof AlgorithmParameter) + .findFirst() + .orElse(null); + assertThat(iterValue).isNotNull(); + assertThat(((AlgorithmParameter) iterValue).getKind()) + .isEqualTo(AlgorithmParameter.Kind.ITERATIONS); + assertThat(iterValue.asString()).isEqualTo("10"); + + assertThat(detectionStore.getChildren()).isEmpty(); + assertThat(nodes).isEmpty(); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java new file mode 100644 index 000000000..71e03b346 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java @@ -0,0 +1,102 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.kdf; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyDerivationFunction; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.algorithms.HKDF; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyDerivation; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class HKDFTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("HKDF"); + + DetectionStore keySizeStore = + getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(keySizeStore).isNotNull(); + assertThat(keySizeStore.getDetectionValues().get(0).asString()).isEqualTo("256"); + + DetectionStore algorithmStore = + getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + assertThat(algorithmStore).isNotNull(); + assertThat(algorithmStore.getDetectionValues().get(0).asString()).isEqualTo("SHA512"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyDerivationFunction.class); + assertThat(root).isInstanceOf(HKDF.class); + assertThat(root.getChildren()).hasSize(3); + assertThat(root.asString()).isEqualTo("HKDF-SHA512"); + + INode md = root.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.getChildren().get(DigestSize.class).asString()).isEqualTo("512"); + assertThat(md.getChildren().get(Oid.class).asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); + assertThat(md.getChildren().get(Digest.class).asString()).isEqualTo("DIGEST"); + assertThat(md.getChildren().get(BlockSize.class).asString()).isEqualTo("1024"); + + assertThat(root.getChildren().get(KeyLength.class).asString()).isEqualTo("256"); + assertThat(root.getChildren().get(KeyDerivation.class).asString()) + .isEqualTo("KEYDERIVATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java new file mode 100644 index 000000000..9a6dff08e --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java @@ -0,0 +1,117 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.kdf; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PasswordBasedKeyDerivationFunction; +import com.ibm.mapper.model.algorithms.PBKDF1; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyDerivation; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PBKDF1Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("PBKDF1"); + + DetectionStore keySizeStore = + getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(keySizeStore).isNotNull(); + assertThat(keySizeStore.getDetectionValues()).hasSize(1); + assertThat(keySizeStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + assertThat(keySizeStore.getDetectionValues().get(0)).isInstanceOf(KeySize.class); + assertThat(keySizeStore.getDetectionValues().get(0).asString()).isEqualTo("128"); + + DetectionStore algorithmStore = + getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + assertThat(algorithmStore).isNotNull(); + assertThat(algorithmStore.getDetectionValues()).hasSize(1); + assertThat(algorithmStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + assertThat(algorithmStore.getDetectionValues().get(0)).isInstanceOf(Algorithm.class); + assertThat(algorithmStore.getDetectionValues().get(0).asString()).isEqualTo("SHA256"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PasswordBasedKeyDerivationFunction.class); + assertThat(root).isInstanceOf(PBKDF1.class); + assertThat(root.getChildren()).hasSize(3); + assertThat(root.asString()).isEqualTo("PBKDF1-SHA256"); + + INode md = root.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA256"); + + assertThat(md.getChildren().get(DigestSize.class)).isNotNull(); + assertThat(md.getChildren().get(DigestSize.class).asString()).isEqualTo("256"); + assertThat(md.getChildren().get(Oid.class)).isNotNull(); + assertThat(md.getChildren().get(Oid.class).asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + assertThat(md.getChildren().get(Digest.class)).isNotNull(); + assertThat(md.getChildren().get(Digest.class).asString()).isEqualTo("DIGEST"); + assertThat(md.getChildren().get(BlockSize.class)).isNotNull(); + assertThat(md.getChildren().get(BlockSize.class).asString()).isEqualTo("512"); + + assertThat(root.getChildren().get(KeyLength.class)).isNotNull(); + assertThat(root.getChildren().get(KeyLength.class).asString()).isEqualTo("128"); + assertThat(root.getChildren().get(KeyDerivation.class)).isNotNull(); + assertThat(root.getChildren().get(KeyDerivation.class).asString()) + .isEqualTo("KEYDERIVATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java new file mode 100644 index 000000000..dc1bdcabc --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java @@ -0,0 +1,114 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.kdf; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.AlgorithmParameter; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PasswordBasedKeyDerivationFunction; +import com.ibm.mapper.model.algorithms.PBKDF2; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyDerivation; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PBKDF2Test extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py", this); + } + + @Override + @SuppressWarnings("unchecked") + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(2); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("PBKDF2"); + + IValue iterValue = + detectionStore.getDetectionValues().stream() + .filter(v -> v instanceof AlgorithmParameter) + .findFirst() + .orElse(null); + assertThat(iterValue).isNotNull(); + assertThat(((AlgorithmParameter) iterValue).getKind()) + .isEqualTo(AlgorithmParameter.Kind.ITERATIONS); + assertThat(iterValue.asString()).isEqualTo("1"); + + DetectionStore keySizeStore = + getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(keySizeStore).isNotNull(); + assertThat(keySizeStore.getDetectionValues().get(0).asString()).isEqualTo("512"); + + DetectionStore algorithmStore = + getStoreOfValueType(Algorithm.class, detectionStore.getChildren()); + assertThat(algorithmStore).isNotNull(); + assertThat(algorithmStore.getDetectionValues().get(0).asString()).isEqualTo("SHA512"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PasswordBasedKeyDerivationFunction.class); + assertThat(root).isInstanceOf(PBKDF2.class); + assertThat(root.getChildren()).hasSize(3); + assertThat(root.asString()).isEqualTo("PBKDF2-SHA512"); + + INode md = root.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.getChildren()).hasSize(4); + assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.getChildren().get(DigestSize.class).asString()).isEqualTo("512"); + assertThat(md.getChildren().get(Oid.class).asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); + assertThat(md.getChildren().get(Digest.class).asString()).isEqualTo("DIGEST"); + assertThat(md.getChildren().get(BlockSize.class).asString()).isEqualTo("1024"); + + assertThat(root.getChildren().get(KeyLength.class).asString()).isEqualTo("512"); + assertThat(root.getChildren().get(KeyDerivation.class).asString()) + .isEqualTo("KEYDERIVATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java new file mode 100644 index 000000000..043764c5f --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java @@ -0,0 +1,82 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.kdf; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.PasswordBasedKeyDerivationFunction; +import com.ibm.mapper.model.algorithms.Scrypt; +import com.ibm.mapper.model.functionality.KeyDerivation; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ScryptTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyDerivationFunctionContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("scrypt"); + + DetectionStore keySizeStore = + getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(keySizeStore).isNotNull(); + assertThat(keySizeStore.getDetectionValues().get(0).asString()).isEqualTo("256"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PasswordBasedKeyDerivationFunction.class); + assertThat(root).isInstanceOf(Scrypt.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("SCRYPT"); + + assertThat(root.getChildren().get(KeyLength.class).asString()).isEqualTo("256"); + assertThat(root.getChildren().get(KeyDerivation.class).asString()) + .isEqualTo("KEYDERIVATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/DHTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/DHTest.java new file mode 100644 index 000000000..8d2f23ea5 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/DHTest.java @@ -0,0 +1,76 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.keyagreement; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.algorithms.ECDH; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class DHTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/keyagreement/DHTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyAgreementContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + assertThat(detectionStore.getDetectionValues().get(0)).isInstanceOf(ValueAction.class); + assertThat(detectionStore.getDetectionValues().get(0).asString()).isEqualTo("ECDH"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyAgreement.class); + assertThat(root).isInstanceOf(ECDH.class); + assertThat(root.asString()).isEqualTo("ECDH"); + + assertThat(root.getChildren().get(Oid.class)).isNotNull(); + assertThat(root.getChildren().get(Oid.class).asString()).isEqualTo("1.3.132.1.12"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(KeyGeneration.class).asString()) + .isEqualTo("KEYGENERATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTest.java new file mode 100644 index 000000000..3f57606e3 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTest.java @@ -0,0 +1,78 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.keyagreement; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class X25519PrivateKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/keyagreement/X25519PrivateKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyAgreementContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + assertThat(detectionStore.getDetectionValues().get(0)).isInstanceOf(KeyAction.class); + assertThat(detectionStore.getDetectionValues().get(0).asString()).isEqualTo("GENERATION"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyAgreement.class); + assertThat(root.asString()).isEqualTo("x25519"); + + assertThat(root.getChildren().get(EllipticCurve.class)).isNotNull(); + assertThat(root.getChildren().get(EllipticCurve.class).asString()).isEqualTo("Curve25519"); + assertThat(root.getChildren().get(Oid.class)).isNotNull(); + assertThat(root.getChildren().get(Oid.class).asString()).isEqualTo("1.3.101.110"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(KeyGeneration.class).asString()) + .isEqualTo("KEYGENERATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PublicKeyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PublicKeyTest.java new file mode 100644 index 000000000..929a0ff09 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X25519PublicKeyTest.java @@ -0,0 +1,78 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.keyagreement; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class X25519PublicKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/keyagreement/X25519PublicKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyAgreementContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + assertThat(detectionStore.getDetectionValues().get(0)).isInstanceOf(KeyAction.class); + assertThat(detectionStore.getDetectionValues().get(0).asString()).isEqualTo("GENERATION"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyAgreement.class); + assertThat(root.asString()).isEqualTo("x25519"); + + assertThat(root.getChildren().get(EllipticCurve.class)).isNotNull(); + assertThat(root.getChildren().get(EllipticCurve.class).asString()).isEqualTo("Curve25519"); + assertThat(root.getChildren().get(Oid.class)).isNotNull(); + assertThat(root.getChildren().get(Oid.class).asString()).isEqualTo("1.3.101.110"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(KeyGeneration.class).asString()) + .isEqualTo("KEYGENERATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PrivateKeyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PrivateKeyTest.java new file mode 100644 index 000000000..953007c19 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PrivateKeyTest.java @@ -0,0 +1,78 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.keyagreement; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class X448PrivateKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/keyagreement/X448PrivateKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyAgreementContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + assertThat(detectionStore.getDetectionValues().get(0)).isInstanceOf(KeyAction.class); + assertThat(detectionStore.getDetectionValues().get(0).asString()).isEqualTo("GENERATION"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyAgreement.class); + assertThat(root.asString()).isEqualTo("x448"); + + assertThat(root.getChildren().get(EllipticCurve.class)).isNotNull(); + assertThat(root.getChildren().get(EllipticCurve.class).asString()).isEqualTo("Curve448"); + assertThat(root.getChildren().get(Oid.class)).isNotNull(); + assertThat(root.getChildren().get(Oid.class).asString()).isEqualTo("1.3.101.111"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(KeyGeneration.class).asString()) + .isEqualTo("KEYGENERATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PublicKeyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PublicKeyTest.java new file mode 100644 index 000000000..016bcf1d3 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/X448PublicKeyTest.java @@ -0,0 +1,78 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.keyagreement; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class X448PublicKeyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/keyagreement/X448PublicKeyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyAgreementContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + assertThat(detectionStore.getDetectionValues().get(0)).isInstanceOf(KeyAction.class); + assertThat(detectionStore.getDetectionValues().get(0).asString()).isEqualTo("GENERATION"); + + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(KeyAgreement.class); + assertThat(root.asString()).isEqualTo("x448"); + + assertThat(root.getChildren().get(EllipticCurve.class)).isNotNull(); + assertThat(root.getChildren().get(EllipticCurve.class).asString()).isEqualTo("Curve448"); + assertThat(root.getChildren().get(Oid.class)).isNotNull(); + assertThat(root.getChildren().get(Oid.class).asString()).isEqualTo("1.3.101.111"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(KeyGeneration.class).asString()) + .isEqualTo("KEYGENERATION"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java new file mode 100644 index 000000000..d5962861d --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java @@ -0,0 +1,92 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.mac; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.context.MacContext; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mac; +import com.ibm.mapper.model.Oid; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class CMACTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(MacContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + assertThat(value.asString()).isEqualTo("AES"); + + /* + * Translation + */ + assertThat(nodes).hasSize(1); + + INode mac = nodes.get(0); + assertThat(mac).isInstanceOf(Mac.class); + assertThat(mac.asString()).isEqualTo("AES-CMAC"); + assertThat(mac.getChildren()).hasSize(2); + + INode cipher = mac.getChildren().get(BlockCipher.class); + assertThat(cipher).isNotNull(); + assertThat(cipher.asString()).isEqualTo("AES"); + + INode blockSize = cipher.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("128"); + + INode oid = cipher.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.1"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java new file mode 100644 index 000000000..35bf4e431 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java @@ -0,0 +1,91 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.mac; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.context.MacContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mac; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class HMACTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + assertThat(findingId).isZero(); + + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(MacContext.class); + assertThat(detectionStore.getChildren()).isEmpty(); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(Algorithm.class); + assertThat(value.asString()).isEqualTo("SHA256"); + + assertThat(nodes).hasSize(1); + INode mac = nodes.get(0); + assertThat(mac).isInstanceOf(Mac.class); + assertThat(mac.asString()).isEqualTo("HMAC-SHA256"); + assertThat(mac.getChildren()).hasSize(3); + + INode digest = mac.getChildren().get(MessageDigest.class); + assertThat(digest).isNotNull(); + assertThat(digest.asString()).isEqualTo("SHA256"); + assertThat(digest.getChildren()).hasSize(4); + + assertThat(digest.getChildren().get(Digest.class)).isNotNull(); + assertThat(digest.getChildren().get(Digest.class).asString()).isEqualTo("DIGEST"); + assertThat(digest.getChildren().get(BlockSize.class)).isNotNull(); + assertThat(digest.getChildren().get(BlockSize.class).asString()).isEqualTo("512"); + assertThat(digest.getChildren().get(Oid.class)).isNotNull(); + assertThat(digest.getChildren().get(Oid.class).asString()) + .isEqualTo("2.16.840.1.101.3.4.2.1"); + assertThat(digest.getChildren().get(DigestSize.class)).isNotNull(); + assertThat(digest.getChildren().get(DigestSize.class).asString()).isEqualTo("256"); + + assertThat(mac.getChildren().get(Oid.class)).isNotNull(); + assertThat(mac.getChildren().get(Oid.class).asString()).isEqualTo("1.2.840.113549.2.9"); + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/DSATest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/DSATest.java new file mode 100644 index 000000000..c87ae21af --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/DSATest.java @@ -0,0 +1,147 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.publickey; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PrivateKey; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class DSATest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/publickey/DSATestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> { + // DSA.generate(bits=2048) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(PrivateKeyContext.class); + IValue v = detectionStore.getDetectionValues().get(0); + assertThat(v).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) v).getAction()) + .isEqualTo(KeyAction.Action.PRIVATE_KEY_GENERATION); + + DetectionStore keySizeStore = + getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(keySizeStore).isNotNull(); + assertThat(keySizeStore.getDetectionValues().get(0).asString()).isEqualTo("2048"); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PrivateKey.class); + assertThat(root.getChildren()).hasSize(3); + assertThat(root.asString()).isEqualTo("DSA"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + + INode innerKey = root.getChildren().get(PrivateKey.class); + assertThat(innerKey).isNotNull(); + assertThat(innerKey.getChildren()).hasSize(3); + assertThat(innerKey.getChildren().get(KeyLength.class).asString()) + .isEqualTo("2048"); + INode innerSig = innerKey.getChildren().get(Signature.class); + assertThat(innerSig).isNotNull(); + assertThat(innerSig.getChildren().get(Oid.class).asString()) + .isEqualTo("1.2.840.10040.4.1"); + + INode outerSig = root.getChildren().get(Signature.class); + assertThat(outerSig).isNotNull(); + assertThat(outerSig.getChildren().get(Oid.class).asString()) + .isEqualTo("1.2.840.10040.4.1"); + } + case 1 -> { + // DSA.construct(...) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("DSA"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat( + root.getChildren() + .get(Signature.class) + .getChildren() + .get(Oid.class) + .asString()) + .isEqualTo("1.2.840.10040.4.1"); + } + case 2 -> { + // DSA.import_key(...) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("DSA"); + assertThat( + root.getChildren() + .get(Signature.class) + .getChildren() + .get(Oid.class) + .asString()) + .isEqualTo("1.2.840.10040.4.1"); + } + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ECCTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ECCTest.java new file mode 100644 index 000000000..6ea001dcc --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ECCTest.java @@ -0,0 +1,141 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.publickey; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Curve; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.mapper.model.EllipticCurve; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PrivateKey; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ECCTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/publickey/ECCTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> { + // ECC.generate(curve="Ed25519") + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(PrivateKeyContext.class); + IValue v = detectionStore.getDetectionValues().get(0); + assertThat(v).isInstanceOf(Curve.class); + assertThat(v.asString()).isEqualTo("Ed25519"); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PrivateKey.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("EC-Curve25519"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + + INode pke = root.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren()).hasSize(2); + assertThat(pke.asString()).isEqualTo("EC-Curve25519"); + assertThat(pke.getChildren().get(EllipticCurve.class).asString()) + .isEqualTo("Curve25519"); + assertThat(pke.getChildren().get(Oid.class).asString()) + .isEqualTo("1.2.840.10045.2.1"); + } + case 1 -> { + // ECC.construct(curve="Ed25519") + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + + DetectionStore curveStore = + getStoreOfValueType(Curve.class, detectionStore.getChildren()); + assertThat(curveStore).isNotNull(); + assertThat(curveStore.getDetectionValues().get(0).asString()).isEqualTo("Ed25519"); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("EC-Curve25519"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + + INode pke = root.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren().get(EllipticCurve.class).asString()) + .isEqualTo("Curve25519"); + assertThat(pke.getChildren().get(Oid.class).asString()) + .isEqualTo("1.2.840.10045.2.1"); + } + case 2 -> { + // ECC.import_key(...) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("EC"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat( + root.getChildren() + .get(PublicKeyEncryption.class) + .getChildren() + .get(Oid.class) + .asString()) + .isEqualTo("1.2.840.10045.2.1"); + } + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ElGamalTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ElGamalTest.java new file mode 100644 index 000000000..51084023d --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/ElGamalTest.java @@ -0,0 +1,101 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.publickey; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.PrivateKey; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ElGamalTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/publickey/ElGamalTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> { + // ElGamal.generate() + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(PrivateKeyContext.class); + IValue v = detectionStore.getDetectionValues().get(0); + assertThat(v).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) v).getAction()) + .isEqualTo(KeyAction.Action.PRIVATE_KEY_GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PrivateKey.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("ElGamal"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(PublicKeyEncryption.class)).isNotNull(); + assertThat(root.getChildren().get(PublicKeyEncryption.class).getChildren()) + .isEmpty(); + } + case 1 -> { + // ElGamal.construct(...) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("ElGamal"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(PublicKeyEncryption.class)).isNotNull(); + assertThat(root.getChildren().get(PublicKeyEncryption.class).getChildren()) + .isEmpty(); + } + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/RSATest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/RSATest.java new file mode 100644 index 000000000..c0460f1e3 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/publickey/RSATest.java @@ -0,0 +1,153 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.publickey; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.KeySize; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PrivateKey; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class RSATest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/publickey/RSATestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> { + // RSA.generate(bits=2048) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(PrivateKeyContext.class); + IValue v = detectionStore.getDetectionValues().get(0); + assertThat(v).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) v).getAction()) + .isEqualTo(KeyAction.Action.PRIVATE_KEY_GENERATION); + + DetectionStore keySizeStore = + getStoreOfValueType(KeySize.class, detectionStore.getChildren()); + assertThat(keySizeStore).isNotNull(); + assertThat(keySizeStore.getDetectionValues().get(0).asString()).isEqualTo("2048"); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PrivateKey.class); + assertThat(root.getChildren()).hasSize(3); + assertThat(root.asString()).isEqualTo("RSA"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + + INode innerKey = root.getChildren().get(PrivateKey.class); + assertThat(innerKey).isNotNull(); + assertThat(innerKey.getChildren()).hasSize(3); + assertThat(innerKey.asString()).isEqualTo("RSA"); + assertThat(innerKey.getChildren().get(KeyLength.class).asString()) + .isEqualTo("2048"); + assertThat(innerKey.getChildren().get(KeyGeneration.class)).isNotNull(); + INode innerPke = innerKey.getChildren().get(PublicKeyEncryption.class); + assertThat(innerPke).isNotNull(); + assertThat(innerPke.getChildren().get(Oid.class).asString()) + .isEqualTo("1.2.840.113549.1.1.1"); + + INode outerPke = root.getChildren().get(PublicKeyEncryption.class); + assertThat(outerPke).isNotNull(); + assertThat(outerPke.getChildren().get(Oid.class).asString()) + .isEqualTo("1.2.840.113549.1.1.1"); + } + case 1 -> { + // RSA.construct(...) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat(detectionStore.getDetectionValues().get(0)) + .isInstanceOf(KeyAction.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("RSA"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat(root.getChildren().get(PublicKeyEncryption.class)).isNotNull(); + assertThat( + root.getChildren() + .get(PublicKeyEncryption.class) + .getChildren() + .get(Oid.class) + .asString()) + .isEqualTo("1.2.840.113549.1.1.1"); + } + case 2 -> { + // RSA.import_key(...) + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(KeyContext.class); + assertThat( + ((KeyAction) detectionStore.getDetectionValues().get(0)) + .getAction()) + .isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.getChildren()).hasSize(2); + assertThat(root.asString()).isEqualTo("RSA"); + assertThat(root.getChildren().get(KeyGeneration.class)).isNotNull(); + assertThat( + root.getChildren() + .get(PublicKeyEncryption.class) + .getChildren() + .get(Oid.class) + .asString()) + .isEqualTo("1.2.840.113549.1.1.1"); + } + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java new file mode 100644 index 000000000..1f577490c --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java @@ -0,0 +1,128 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class DSSSignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("DSS"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("SIGN"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(4); + assertThat(sig.asString()).isEqualTo("SHA256withDSA"); + + INode oid = sig.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.3.2"); + + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("DSA"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode sign = sig.getChildren().get(Sign.class); + assertThat(sign).isNotNull(); + assertThat(sign.getChildren()).isEmpty(); + assertThat(sign.asString()).isEqualTo("SIGN"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java new file mode 100644 index 000000000..825a45596 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java @@ -0,0 +1,128 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Verify; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class DSSVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("DSS"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("VERIFY"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(4); + assertThat(sig.asString()).isEqualTo("SHA256withDSA"); + + INode oid = sig.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("2.16.840.1.101.3.4.3.2"); + + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("DSA"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode verify = sig.getChildren().get(Verify.class); + assertThat(verify).isNotNull(); + assertThat(verify.getChildren()).isEmpty(); + assertThat(verify.asString()).isEqualTo("VERIFY"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java new file mode 100644 index 000000000..a8aead15c --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java @@ -0,0 +1,112 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class EdDSASignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("EDDSA"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("SIGN"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(2); + assertThat(sig.asString()).isEqualTo("EdDSA"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("512"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("1024"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode sign = sig.getChildren().get(Sign.class); + assertThat(sign).isNotNull(); + assertThat(sign.getChildren()).isEmpty(); + assertThat(sign.asString()).isEqualTo("SIGN"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java new file mode 100644 index 000000000..f3693fc1b --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java @@ -0,0 +1,112 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.Verify; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class EdDSAVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("EDDSA"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("VERIFY"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(2); + assertThat(sig.asString()).isEqualTo("EdDSA"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("512"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("1024"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode verify = sig.getChildren().get(Verify.class); + assertThat(verify).isNotNull(); + assertThat(verify.getChildren()).isEmpty(); + assertThat(verify.asString()).isEqualTo("VERIFY"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java new file mode 100644 index 000000000..76230028b --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java @@ -0,0 +1,135 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PKCS1v15SignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RSA"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("SIGN"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(4); + assertThat(sig.asString()).isEqualTo("SHA256withRSA"); + + INode oid = sig.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.113549.1.1.11"); + + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("RSA"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + INode pkeOid = pke.getChildren().get(Oid.class); + assertThat(pkeOid).isNotNull(); + assertThat(pkeOid.getChildren()).isEmpty(); + assertThat(pkeOid.asString()).isEqualTo("1.2.840.113549.1.1.1"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode sign = sig.getChildren().get(Sign.class); + assertThat(sign).isNotNull(); + assertThat(sign.getChildren()).isEmpty(); + assertThat(sign.asString()).isEqualTo("SIGN"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java new file mode 100644 index 000000000..2c2e4449c --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java @@ -0,0 +1,136 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Verify; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PKCS1v15VerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py", + this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RSA"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("VERIFY"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(4); + assertThat(sig.asString()).isEqualTo("SHA256withRSA"); + + INode oid = sig.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.113549.1.1.11"); + + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("RSA"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + INode pkeOid = pke.getChildren().get(Oid.class); + assertThat(pkeOid).isNotNull(); + assertThat(pkeOid.getChildren()).isEmpty(); + assertThat(pkeOid.asString()).isEqualTo("1.2.840.113549.1.1.1"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode verify = sig.getChildren().get(Verify.class); + assertThat(verify).isNotNull(); + assertThat(verify.getChildren()).isEmpty(); + assertThat(verify.asString()).isEqualTo("VERIFY"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java new file mode 100644 index 000000000..9f8275c5a --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java @@ -0,0 +1,135 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.ProbabilisticSignatureScheme; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PSSSignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RSA-PSS"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("SIGN"); + + // translation + assertThat(nodes).hasSize(1); + INode pss = nodes.get(0); + assertThat(pss.getKind()).isEqualTo(ProbabilisticSignatureScheme.class); + assertThat(pss.getChildren()).hasSize(4); + assertThat(pss.asString()).isEqualTo("RSASSA-PSS"); + + INode oid = pss.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.113549.1.1.10"); + + INode key = pss.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("RSA"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + INode pkeOid = pke.getChildren().get(Oid.class); + assertThat(pkeOid).isNotNull(); + assertThat(pkeOid.getChildren()).isEmpty(); + assertThat(pkeOid.asString()).isEqualTo("1.2.840.113549.1.1.1"); + + INode md = pss.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode sign = pss.getChildren().get(Sign.class); + assertThat(sign).isNotNull(); + assertThat(sign.getChildren()).isEmpty(); + assertThat(sign.asString()).isEqualTo("SIGN"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java new file mode 100644 index 000000000..066ce09ce --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java @@ -0,0 +1,135 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.ProbabilisticSignatureScheme; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Verify; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class PSSVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("RSA-PSS"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("VERIFY"); + + // translation + assertThat(nodes).hasSize(1); + INode pss = nodes.get(0); + assertThat(pss.getKind()).isEqualTo(ProbabilisticSignatureScheme.class); + assertThat(pss.getChildren()).hasSize(4); + assertThat(pss.asString()).isEqualTo("RSASSA-PSS"); + + INode oid = pss.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.113549.1.1.10"); + + INode key = pss.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("RSA"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + INode pkeOid = pke.getChildren().get(Oid.class); + assertThat(pkeOid).isNotNull(); + assertThat(pkeOid.getChildren()).isEmpty(); + assertThat(pkeOid.asString()).isEqualTo("1.2.840.113549.1.1.1"); + + INode md = pss.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode verify = pss.getChildren().get(Verify.class); + assertThat(verify).isNotNull(); + assertThat(verify.getChildren()).isEmpty(); + assertThat(verify.asString()).isEqualTo("VERIFY"); + } + } +} From 85beb72bc7675734dc086d0eb45e3c85a927dfab Mon Sep 17 00:00:00 2001 From: san-zrl Date: Tue, 21 Jul 2026 16:29:07 +0200 Subject: [PATCH 4/9] added memoization Signed-off-by: san-zrl --- .../detection/crypto/PythonCryptoCipher.java | 286 ------------------ .../detection/pyca/asymmetric/PycaDSA.java | 4 +- .../pyca/asymmetric/PycaEllipticCurve.java | 4 +- .../detection/pyca/asymmetric/PycaRSA.java | 4 +- .../rules/detection/pyca/hash/PycaHash.java | 11 +- .../detection/pyca/padding/PycaPadding.java | 4 +- .../detection/pyca/symmetric/PycaCipher.java | 4 +- .../pycrypto/cipher/PythonCryptoCipher.java | 11 + .../pycrypto/hash/PythonCryptoHash.java | 11 + .../pycrypto/kdf/PythonCryptoKDF.java | 11 + .../PythonCryptoKeyAgreement.java | 11 + .../pycrypto/mac/PythonCryptoMac.java | 11 + .../publickey/PythonCryptoPublicKey.java | 45 +-- .../pycrypto/random/PythonCryptoRandom.java | 11 + .../signature/PythonCryptoSignature.java | 11 + 15 files changed, 124 insertions(+), 315 deletions(-) delete mode 100644 python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java deleted file mode 100644 index 2190bca07..000000000 --- a/python/src/main/java/com/ibm/plugin/rules/detection/crypto/PythonCryptoCipher.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.crypto; - -import static com.ibm.engine.detection.MethodMatcher.ANY; - -import com.ibm.engine.model.CipherAction; -import com.ibm.engine.model.context.CipherContext; -import com.ibm.engine.model.factory.CipherActionFactory; -import com.ibm.engine.model.factory.ModeFactory; -import com.ibm.engine.model.factory.ValueActionFactory; -import com.ibm.engine.rule.IDetectionRule; -import com.ibm.engine.rule.builder.DetectionRuleBuilder; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.sonar.plugins.python.api.tree.Tree; - -@SuppressWarnings("java:S1192") -public final class PythonCryptoCipher { - - private PythonCryptoCipher() { - // private - } - - private static final IDetectionRule ENCRYPT = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes(ANY) - .forMethods("encrypt") - .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.ENCRYPT)) - .withMethodParameter(ANY) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withoutDependingDetectionRules(); - - private static final IDetectionRule DECRYPT = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes(ANY) - .forMethods("decrypt") - .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.DECRYPT)) - .withMethodParameter(ANY) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withoutDependingDetectionRules(); - - private static final IDetectionRule AES_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.AES") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("AES")) - .withMethodParameter(ANY) - .withMethodParameter("Crypto.Cipher.AES.*") - .shouldBeDetectedAs(new ModeFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule DES_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.DES") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("DES")) - .withMethodParameter(ANY) - .withMethodParameter("Crypto.Cipher.DES.*") - .shouldBeDetectedAs(new ModeFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule DES3_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.DES3") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("3DES")) - .withMethodParameter(ANY) - .withMethodParameter("Crypto.Cipher.DES3.*") - .shouldBeDetectedAs(new ModeFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule BLOWFISH_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.Blowfish") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("Blowfish")) - .withMethodParameter(ANY) - .withMethodParameter("Crypto.Cipher.Blowfish.*") - .shouldBeDetectedAs(new ModeFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule CAST_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.CAST") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("CAST5")) - .withMethodParameter(ANY) - .withMethodParameter("Crypto.Cipher.CAST.*") - .shouldBeDetectedAs(new ModeFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule ARC2_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.ARC2") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("RC2")) - .withMethodParameter(ANY) - .withMethodParameter("Crypto.Cipher.ARC2.*") - .shouldBeDetectedAs(new ModeFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule ARC4_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.ARC4") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("RC4")) - .withAnyParameters() - .buildForContext(new CipherContext(Map.of("algorithm", "RC4"))) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule CHACHA20_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.ChaCha20") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20")) - .withAnyParameters() - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withoutDependingDetectionRules(); - - private static final IDetectionRule CHACHA20_POLY1305_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.ChaCha20_Poly1305") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20Poly1305")) - .withAnyParameters() - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withoutDependingDetectionRules(); - - private static final IDetectionRule SALSA20_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes("Crypto.Cipher.Salsa20") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("Salsa20")) - .withAnyParameters() - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule PKCS1_OAEP_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) - .withAnyParameters() // This must be changed if the rule below is enabled. - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - // // Variant with hash algo. This detects the hash but it won't be mapped. - // private static final IDetectionRule PKCS1_OAEP_NEW_WITH_HASH = - // new DetectionRuleBuilder() - // .createDetectionRule() - // .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") - // .forMethods("new") - // .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_OAEP")) - // .withMethodParameter(ANY) // key - // .withMethodParameter("Crypto.Hash.*") - // .shouldBeDetectedAs(new AlgorithmFactory<>()) - // .asChildOfParameterWithId(-1) - // .buildForContext(new CipherContext()) - // .inBundle(() -> "PyCrypto") - // .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule PKCS1_V1_5_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectExactTypes("Crypto.Cipher.PKCS1_v1_5") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("PKCS1_v1_5")) - .withAnyParameters() - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - - private static final IDetectionRule SEAL = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes(ANY) - .forMethods("seal") - .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.ENCRYPT)) - .withMethodParameter(ANY) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withoutDependingDetectionRules(); - - private static final IDetectionRule UNSEAL = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectTypes(ANY) - .forMethods("unseal") - .shouldBeDetectedAs(new CipherActionFactory<>(CipherAction.Action.DECRYPT)) - .withMethodParameter(ANY) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withoutDependingDetectionRules(); - - private static final IDetectionRule HPKE_NEW = - new DetectionRuleBuilder() - .createDetectionRule() - .forObjectExactTypes("Crypto.Protocol.HPKE") - .forMethods("new") - .shouldBeDetectedAs(new ValueActionFactory<>("HPKE")) - .withMethodParameter(ANY) - .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) - .asChildOfParameterWithId(-1) - .withMethodParameter(ANY) - .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) - .asChildOfParameterWithId(-1) - .buildForContext(new CipherContext()) - .inBundle(() -> "PyCrypto") - .withDependingDetectionRules(List.of(SEAL, UNSEAL)); - - @Nonnull - public static List> rules() { - return List.of( - AES_NEW, - DES_NEW, - DES3_NEW, - BLOWFISH_NEW, - CAST_NEW, - ARC2_NEW, - ARC4_NEW, - CHACHA20_NEW, - CHACHA20_POLY1305_NEW, - SALSA20_NEW, - PKCS1_OAEP_NEW, - // PKCS1_OAEP_NEW_WITH_HASH, - PKCS1_V1_5_NEW, - HPKE_NEW); - } -} diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDSA.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDSA.java index 51211987f..e53f390df 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDSA.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaDSA.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric; +package com.ibm.plugin.rules.detection.pyca.asymmetric; import static com.ibm.engine.detection.MethodMatcher.ANY; @@ -33,7 +33,7 @@ import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; import com.ibm.plugin.rules.detection.Memoize; -import com.ibm.plugin.rules.detection.hash.PycaHash; +import com.ibm.plugin.rules.detection.pyca.hash.PycaHash; import java.util.List; import java.util.Map; import java.util.function.Supplier; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaEllipticCurve.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaEllipticCurve.java index 195cc53b5..3e1842f6f 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaEllipticCurve.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaEllipticCurve.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric; +package com.ibm.plugin.rules.detection.pyca.asymmetric; import static com.ibm.engine.detection.MethodMatcher.ANY; @@ -34,7 +34,7 @@ import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; import com.ibm.plugin.rules.detection.Memoize; -import com.ibm.plugin.rules.detection.hash.PycaHash; +import com.ibm.plugin.rules.detection.pyca.hash.PycaHash; import java.util.List; import java.util.Map; import java.util.function.Supplier; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaRSA.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaRSA.java index 8eeaf5766..4d3364e26 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaRSA.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/asymmetric/PycaRSA.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.asymmetric; +package com.ibm.plugin.rules.detection.pyca.asymmetric; import static com.ibm.engine.detection.MethodMatcher.ANY; @@ -37,7 +37,7 @@ import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; import com.ibm.plugin.rules.detection.Memoize; -import com.ibm.plugin.rules.detection.hash.PycaHash; +import com.ibm.plugin.rules.detection.pyca.hash.PycaHash; import java.util.List; import java.util.Map; import java.util.function.Supplier; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java index 8d5238928..f3da3342f 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/hash/PycaHash.java @@ -116,7 +116,16 @@ private static List> buildRules() { } @Nonnull - public static List> wrapperRules() { + private static final Supplier>> WRAPPER_RULES = + Memoize.of(PycaHash::wrapperRule); + + @Nonnull + public static List> wrapperRule() { return List.of(HASH_WRAPPER); } + + @Nonnull + public static List> wrapperRules() { + return WRAPPER_RULES.get(); + } } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPadding.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPadding.java index 404367ff3..314b90058 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPadding.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/padding/PycaPadding.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.padding; +package com.ibm.plugin.rules.detection.pyca.padding; import com.ibm.engine.model.Size; import com.ibm.engine.model.context.CipherContext; @@ -26,7 +26,7 @@ import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; import com.ibm.plugin.rules.detection.Memoize; -import com.ibm.plugin.rules.detection.symmetric.PycaCipher; +import com.ibm.plugin.rules.detection.pyca.symmetric.PycaCipher; import java.util.Arrays; import java.util.LinkedList; import java.util.List; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher.java index 2438d9eaf..06b8d0b0e 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pyca/symmetric/PycaCipher.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibm.plugin.rules.detection.symmetric; +package com.ibm.plugin.rules.detection.pyca.symmetric; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.context.CipherContext; @@ -27,7 +27,7 @@ import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; import com.ibm.plugin.rules.detection.Memoize; -import com.ibm.plugin.rules.detection.padding.PycaPadding; +import com.ibm.plugin.rules.detection.pyca.padding.PycaPadding; import java.util.Arrays; import java.util.LinkedList; import java.util.List; diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java index 1755e2517..a22ec01be 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java @@ -28,8 +28,10 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -266,8 +268,17 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(SEAL, UNSEAL)); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoCipher::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of( AES_NEW, DES_NEW, diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java index 56fec946e..324808bd2 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/hash/PythonCryptoHash.java @@ -23,9 +23,11 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -65,8 +67,17 @@ private PythonCryptoHash() { "BLAKE2b", "BLAKE2s"); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoHash::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { LinkedList> rules = new LinkedList<>(); for (final String hash : PythonCryptoHash.hashes) { rules.add( diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java index e665fa794..091d48cae 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PythonCryptoKDF.java @@ -30,8 +30,10 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -157,8 +159,17 @@ private PythonCryptoKDF() { .inBundle(() -> "PyCa") .withoutDependingDetectionRules(); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoKDF::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of(PBKDF1, PBKDF2, SCRYPT, BCRYPT, BCRYPT_CHECK, HKDF); } } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java index 27ce1487f..fce667513 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/keyagreement/PythonCryptoKeyAgreement.java @@ -25,8 +25,10 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -93,8 +95,17 @@ private PythonCryptoKeyAgreement() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoKeyAgreement::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of( DH_KEY_AGREEMENT, IMPORT_X25519_PUBLIC_KEY, diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java index 8eaa98d7d..c16d54138 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/mac/PythonCryptoMac.java @@ -25,8 +25,10 @@ import com.ibm.engine.model.factory.AlgorithmFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -75,8 +77,17 @@ private PythonCryptoMac() { // .inBundle(() -> "PyCrypto") // .withoutDependingDetectionRules(); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoMac::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of(NEW_CMAC, NEW_HMAC); } } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java index 37abb4456..513193d10 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java @@ -29,8 +29,10 @@ import com.ibm.engine.model.factory.KeySizeFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -226,52 +228,59 @@ private PythonCryptoPublicKey() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); - public static List> RSAPublicKeyRules() { - return List.of(RSA_CONSTRUCT, RSA_PUBLIC_KEY); - } + @Nonnull + private static final Supplier>> RSA_RULES = + Memoize.of(PythonCryptoPublicKey::buildRSARules); @Nonnull - public static List> RSAPrivateKeyRules() { - return List.of(RSA_CONSTRUCT, RSA_GENERATE); + public static List> RSARules() { + return RSA_RULES.get(); } @Nonnull - public static List> RSARules() { + private static List> buildRSARules() { return List.of(RSA_CONSTRUCT, RSA_GENERATE, RSA_PUBLIC_KEY); } @Nonnull - public static List> DSAPublicKeyRules() { - return List.of(DSA_CONSTRUCT, DSA_PUBLIC_KEY); - } + private static final Supplier>> DSA_RULES = + Memoize.of(PythonCryptoPublicKey::buildDSARules); @Nonnull - public static List> DSAPrivateKeyRules() { - return List.of(DSA_CONSTRUCT, DSA_GENERATE); + public static List> DSARules() { + return DSA_RULES.get(); } @Nonnull - public static List> DSARules() { + private static List> buildDSARules() { return List.of(DSA_CONSTRUCT, DSA_GENERATE, DSA_PUBLIC_KEY); } @Nonnull - public static List> ECCPublicKeyRules() { - return List.of(ECC_CONSTRUCT, ECC_PUBLIC_KEY, EDDSA_IMPORT_PUBLIC_KEY); - } + private static final Supplier>> ECC_RULES = + Memoize.of(PythonCryptoPublicKey::buildECCRules); @Nonnull - public static List> ECCPrivateKeyRules() { - return List.of(ECC_CONSTRUCT, ECC_GENERATE, EDDSA_IMPORT_PRIVATE_KEY); + public static List> ECCRules() { + return ECC_RULES.get(); } @Nonnull - public static List> ECCRules() { + private static List> buildECCRules() { return List.of(ECC_CONSTRUCT, ECC_GENERATE, ECC_PUBLIC_KEY); } + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoPublicKey::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of( RSA_CONSTRUCT, RSA_GENERATE, diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java index f88d889a8..3e2529696 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/random/PythonCryptoRandom.java @@ -25,7 +25,9 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import java.util.List; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -59,8 +61,17 @@ private PythonCryptoRandom() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoRandom::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of(RANDOM_GET_BYTES, RANDOM_FUNC); } } diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java index ac9a5c885..e1b757694 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/signature/PythonCryptoSignature.java @@ -28,9 +28,11 @@ import com.ibm.engine.model.factory.ValueActionFactory; import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.ibm.plugin.rules.detection.Memoize; import com.ibm.plugin.rules.detection.pycrypto.hash.PythonCryptoHash; import com.ibm.plugin.rules.detection.pycrypto.publickey.PythonCryptoPublicKey; import java.util.List; +import java.util.function.Supplier; import javax.annotation.Nonnull; import org.sonar.plugins.python.api.tree.Tree; @@ -164,8 +166,17 @@ private PythonCryptoSignature() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(SIGN, VERIFY)); + @Nonnull + private static final Supplier>> RULES = + Memoize.of(PythonCryptoSignature::buildRules); + @Nonnull public static List> rules() { + return RULES.get(); + } + + @Nonnull + private static List> buildRules() { return List.of(PKCS1V15, PSS, PSS_MGF1, DSS, ECDSA, EDDSA); } } From 760703e25014e892b4a103f6e61df80cc88dba2b Mon Sep 17 00:00:00 2001 From: san-zrl Date: Tue, 21 Jul 2026 16:30:02 +0200 Subject: [PATCH 5/9] Fixed test after rebase Signed-off-by: san-zrl --- .../files/rules/detection/pycrypto/cipher/BlowfishTestFile.py | 2 +- .../files/rules/detection/pycrypto/cipher/CAST5TestFile.py | 2 +- .../detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py | 2 +- .../test/files/rules/detection/pycrypto/cipher/DESTestFile.py | 2 +- .../test/files/rules/detection/pycrypto/cipher/RC2TestFile.py | 2 +- .../rules/detection/pycrypto/cipher/TripleDESTestFile.py | 2 +- .../test/files/rules/detection/pycrypto/hash/SHA1TestFile.py | 2 +- .../files/rules/detection/pycrypto/hash/SHA224TestFile.py | 2 +- .../files/rules/detection/pycrypto/hash/SHA256TestFile.py | 2 +- .../files/rules/detection/pycrypto/hash/SHA384TestFile.py | 2 +- .../files/rules/detection/pycrypto/hash/SHA512TestFile.py | 2 +- .../test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py | 2 +- .../test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py | 2 +- .../test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py | 2 +- .../test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py | 2 +- .../test/files/rules/detection/pycrypto/mac/CMACTestFile.py | 2 +- .../test/files/rules/detection/pycrypto/mac/HMACTestFile.py | 2 +- .../rules/detection/pycrypto/signature/DSSSignTestFile.py | 4 ++-- .../rules/detection/pycrypto/signature/DSSVerifyTestFile.py | 4 ++-- .../rules/detection/pycrypto/signature/EdDSASignTestFile.py | 2 +- .../rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py | 2 +- .../detection/pycrypto/signature/PKCS1v15SignTestFile.py | 4 ++-- .../detection/pycrypto/signature/PKCS1v15VerifyTestFile.py | 4 ++-- .../rules/detection/pycrypto/signature/PSSSignTestFile.py | 4 ++-- .../rules/detection/pycrypto/signature/PSSVerifyTestFile.py | 4 ++-- .../plugin/rules/detection/pycrypto/cipher/BlowfishTest.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java | 2 +- .../rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java | 2 +- .../rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java | 4 ++-- .../ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java | 2 +- .../plugin/rules/detection/pycrypto/cipher/TripleDESTest.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java | 2 +- .../ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java | 2 +- .../com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java | 4 ++-- .../ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java | 4 ++-- .../ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java | 4 ++-- .../ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java | 2 +- .../com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java | 2 +- .../com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java | 4 ++-- .../rules/detection/pycrypto/signature/DSSSignTest.java | 4 ++-- .../rules/detection/pycrypto/signature/DSSVerifyTest.java | 4 ++-- .../rules/detection/pycrypto/signature/EdDSASignTest.java | 2 +- .../rules/detection/pycrypto/signature/EdDSAVerifyTest.java | 2 +- .../rules/detection/pycrypto/signature/PKCS1v15SignTest.java | 4 ++-- .../detection/pycrypto/signature/PKCS1v15VerifyTest.java | 4 ++-- .../rules/detection/pycrypto/signature/PSSSignTest.java | 4 ++-- .../rules/detection/pycrypto/signature/PSSVerifyTest.java | 4 ++-- 51 files changed, 68 insertions(+), 68 deletions(-) diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py index 876f81f8a..acbb3603a 100644 --- a/python/src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/cipher/BlowfishTestFile.py @@ -1,4 +1,4 @@ from Crypto.Cipher import Blowfish key_blowfish = b"0123456789abcdef" -cipher_blowfish = Blowfish.new(key_blowfish, Blowfish.MODE_CBC) # Noncompliant {{(BlockCipher) Blowfish}} +cipher_blowfish = Blowfish.new(key_blowfish, Blowfish.MODE_CBC) # Noncompliant {{(BlockCipher) Blowfish-CBC}} diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py index 60f3b6aaa..dd654fcea 100644 --- a/python/src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/cipher/CAST5TestFile.py @@ -1,4 +1,4 @@ from Crypto.Cipher import CAST key_cast = b"0123456789abcdef" -cipher_cast = CAST.new(key_cast, CAST.MODE_CBC) # Noncompliant {{(BlockCipher) CAST-128}} +cipher_cast = CAST.new(key_cast, CAST.MODE_CBC) # Noncompliant {{(BlockCipher) CAST5-CBC}} diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py index 34261dd56..2f69ea0be 100644 --- a/python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/cipher/ChaCha20Poly1305TestFile.py @@ -2,6 +2,6 @@ key_chacha20_poly1305 = b"0123456789abcdef0123456789abcdef" nonce_chacha20_poly1305 = b"01234567" -cipher_chacha20_poly1305 = ChaCha20_Poly1305.new( # Noncompliant {{(AuthenticatedEncryption) ChaCha20Poly1305}} +cipher_chacha20_poly1305 = ChaCha20_Poly1305.new( # Noncompliant {{(AuthenticatedEncryption) ChaCha20-Poly1305}} key=key_chacha20_poly1305, nonce=nonce_chacha20_poly1305) diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py index fd9402e6c..bb956ab8e 100644 --- a/python/src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/cipher/DESTestFile.py @@ -1,5 +1,5 @@ from Crypto.Cipher import DES key_des = b"01234567" -cipher_des = DES.new(key_des, DES.MODE_ECB) # Noncompliant {{(BlockCipher) DES56-ECB}} +cipher_des = DES.new(key_des, DES.MODE_ECB) # Noncompliant {{(BlockCipher) DES-56-ECB}} cipher_des.decrypt(b'some blob') diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py index 70bc03196..9ba68e2c4 100644 --- a/python/src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/cipher/RC2TestFile.py @@ -1,4 +1,4 @@ from Crypto.Cipher import ARC2 key_arc2 = b"0123456789abcdef" -cipher_arc2 = ARC2.new(key_arc2, ARC2.MODE_CBC) # Noncompliant {{(BlockCipher) RC2}} +cipher_arc2 = ARC2.new(key_arc2, ARC2.MODE_CBC) # Noncompliant {{(BlockCipher) RC2-CBC}} diff --git a/python/src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py b/python/src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py index e3b1f2483..45ac67190 100644 --- a/python/src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/cipher/TripleDESTestFile.py @@ -1,4 +1,4 @@ from Crypto.Cipher import DES3 key_3des = b"0123456789abcdef01234567" -cipher_3des = DES3.new(key_3des, DES3.MODE_CBC) # Noncompliant {{(BlockCipher) 3DES}} +cipher_3des = DES3.new(key_3des, DES3.MODE_CBC) # Noncompliant {{(BlockCipher) 3DES-CBC}} diff --git a/python/src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py index 218735199..49966efe3 100644 --- a/python/src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/hash/SHA1TestFile.py @@ -1,3 +1,3 @@ from Crypto.Hash import SHA1 -hash_sha1 = SHA1.new() # Noncompliant {{(MessageDigest) SHA1}} +hash_sha1 = SHA1.new() # Noncompliant {{(MessageDigest) SHA-1}} diff --git a/python/src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py index fdbf255f7..b6cdab156 100644 --- a/python/src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/hash/SHA224TestFile.py @@ -1,3 +1,3 @@ from Crypto.Hash import SHA224 -hash_sha224 = SHA224.new() # Noncompliant {{(MessageDigest) SHA224}} +hash_sha224 = SHA224.new() # Noncompliant {{(MessageDigest) SHA-224}} diff --git a/python/src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py index 00ad62b9e..46a45ccd2 100644 --- a/python/src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/hash/SHA256TestFile.py @@ -1,3 +1,3 @@ from Crypto.Hash import SHA256 -hash_sha256 = SHA256.new() # Noncompliant {{(MessageDigest) SHA256}} +hash_sha256 = SHA256.new() # Noncompliant {{(MessageDigest) SHA-256}} diff --git a/python/src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py index 98f1e69dd..69c9d06d9 100644 --- a/python/src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/hash/SHA384TestFile.py @@ -1,3 +1,3 @@ from Crypto.Hash import SHA384 -hash_sha384 = SHA384.new() # Noncompliant {{(MessageDigest) SHA384}} +hash_sha384 = SHA384.new() # Noncompliant {{(MessageDigest) SHA-384}} diff --git a/python/src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py b/python/src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py index 72a71a274..d49f1fe8a 100644 --- a/python/src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/hash/SHA512TestFile.py @@ -1,3 +1,3 @@ from Crypto.Hash import SHA512 -hash_sha512 = SHA512.new() # Noncompliant {{(MessageDigest) SHA512}} +hash_sha512 = SHA512.new() # Noncompliant {{(MessageDigest) SHA-512}} diff --git a/python/src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py index 53bc9bc4f..9641cf2aa 100644 --- a/python/src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/kdf/HKDFTestFile.py @@ -4,4 +4,4 @@ def test_hkdf(): secret = b"secret" salt = b"salt1234567890ab" - key = HKDF(secret, 32, salt, SHA512) # Noncompliant {{(KeyDerivationFunction) HKDF-SHA512}} + key = HKDF(secret, 32, salt, SHA512) # Noncompliant {{(KeyDerivationFunction) HKDF-SHA-512}} diff --git a/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py index 3f191548b..92df75869 100644 --- a/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF1TestFile.py @@ -4,4 +4,4 @@ def test_pbkdf1(): password = b"password" salt = b"salt1234" - key = PBKDF1(password, salt, 16, 1000, SHA256) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF1-SHA256}} + key = PBKDF1(password, salt, 16, 1000, SHA256) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF1-SHA-256}} diff --git a/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py index 614aa54cf..ec22b108c 100644 --- a/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/kdf/PBKDF2TestFile.py @@ -4,4 +4,4 @@ def test_pbkdf2(): password = b"password" salt = b"salt1234" - key = PBKDF2(password, salt, dkLen=64, count=1, hmac_hash_module=SHA512) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA512}} + key = PBKDF2(password, salt, dkLen=64, count=1, hmac_hash_module=SHA512) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA-512}} diff --git a/python/src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py index a22e8d2b6..3dacc3111 100644 --- a/python/src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/kdf/ScryptTestFile.py @@ -3,4 +3,4 @@ def test_scrypt(): password = b"password" salt = b"salt1234" - key = scrypt(password, salt, key_len=32, N=2**14, r=8, p=1, num_keys=1) # Noncompliant {{(PasswordBasedKeyDerivationFunction) SCRYPT}} + key = scrypt(password, salt, key_len=32, N=2**14, r=8, p=1, num_keys=1) # Noncompliant {{(PasswordBasedKeyDerivationFunction) scrypt}} diff --git a/python/src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py b/python/src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py index 41bbd2fdb..b2524fbfd 100644 --- a/python/src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/mac/CMACTestFile.py @@ -2,4 +2,4 @@ from Crypto.Cipher import AES key = b'some key' -cmac = CMAC.new(key, AES) # Noncompliant {{(Mac) AES-CMAC}} +cmac = CMAC.new(key, AES) # Noncompliant {{(Mac) CMAC-AES}} diff --git a/python/src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py b/python/src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py index 46adbc216..bc776cb2e 100644 --- a/python/src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/mac/HMACTestFile.py @@ -1,4 +1,4 @@ from Crypto.Hash import HMAC, SHA256 secret = b'some secret' -hmac = HMAC.new(secret, digestmod=SHA256) # Noncompliant {{(Mac) HMAC-SHA256}} +hmac = HMAC.new(secret, digestmod=SHA256) # Noncompliant {{(Mac) HMAC-SHA-256}} diff --git a/python/src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py index a51220a25..7295f477e 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/DSSSignTestFile.py @@ -4,6 +4,6 @@ message = b'some message' key = DSA.import_key(open('privkey.der').read()) # Noncompliant {{(Key) DSA}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -signer = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withDSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +signer = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) DSA-SHA-256}} signature = signer.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py index c59d15504..a5e50a715 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/DSSVerifyTestFile.py @@ -4,8 +4,8 @@ message = b'some message' key = DSA.import_key(open('pubkey.der').read()) # Noncompliant {{(Key) DSA}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -verifier = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withDSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +verifier = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) DSA-SHA-256}} signature = b'some signature' try: diff --git a/python/src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py index 8fed3902a..debbc8912 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/EdDSASignTestFile.py @@ -3,7 +3,7 @@ from Crypto.Hash import SHA512 message = b'some message' -prehashed_message = SHA512.new(message) # Noncompliant {{(MessageDigest) SHA512}} +prehashed_message = SHA512.new(message) # Noncompliant {{(MessageDigest) SHA-512}} key = ECC.import_key(open("private_ed25519.pem").read()) # Noncompliant {{(Key) EC}} signer = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) EdDSA}} signature = signer.sign(prehashed_message) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py index ef2736762..36002942b 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/EdDSAVerifyTestFile.py @@ -4,7 +4,7 @@ message = b'some message' key = ECC.import_key(open("public_ed25519.pem").read()) # Noncompliant {{(Key) EC}} -h = SHA512.new(message) # Noncompliant {{(MessageDigest) SHA512}} +h = SHA512.new(message) # Noncompliant {{(MessageDigest) SHA-512}} verifier = eddsa.new(key, 'rfc8032') # Noncompliant {{(Signature) EdDSA}} signature = b'some signature' diff --git a/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py index 39da6967d..512492b8f 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15SignTestFile.py @@ -4,6 +4,6 @@ message = b'To be signed' key = RSA.import_key(open('private_key.der').read()) # Noncompliant {{(Key) RSA}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -scheme = pkcs1_15.new(key) # Noncompliant {{(Signature) SHA256withRSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +scheme = pkcs1_15.new(key) # Noncompliant {{(Signature) RSA-PKCS1-1.5-SHA-256}} signature = scheme.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py index f394f306e..c28633e0e 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/PKCS1v15VerifyTestFile.py @@ -4,8 +4,8 @@ message = b'To be signed' key = RSA.import_key(open('private_key.der').read()) # Noncompliant {{(Key) RSA}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -scheme = pkcs1_15.new(key) # Noncompliant {{(Signature) SHA256withRSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +scheme = pkcs1_15.new(key) # Noncompliant {{(Signature) RSA-PKCS1-1.5-SHA-256}} signature = b'some sginature' try: diff --git a/python/src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py index 8270f842d..be000c574 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/PSSSignTestFile.py @@ -4,6 +4,6 @@ message = b'To be signed' key = RSA.import_key(open('private_key.der').read()) # Noncompliant {{(Key) RSA}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -scheme = pss.new(key) # Noncompliant {{(ProbabilisticSignatureScheme) RSASSA-PSS}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +scheme = pss.new(key) # Noncompliant {{(ProbabilisticSignatureScheme) RSA-PSS}} signature = scheme.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py index 905ba9bcc..87b44fb1c 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/PSSVerifyTestFile.py @@ -5,8 +5,8 @@ message = b'To be signed' key = RSA.import_key(open('pubkey.der', 'rb').read()) # Noncompliant {{(Key) RSA}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -verifier = pss.new(key) # Noncompliant {{(ProbabilisticSignatureScheme) RSASSA-PSS}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +verifier = pss.new(key) # Noncompliant {{(ProbabilisticSignatureScheme) RSA-PSS}} signature = b'some sginature' try: diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java index 2e2960083..22cbae93c 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/BlowfishTest.java @@ -78,7 +78,7 @@ public void asserts( INode cipher = nodes.get(0); assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); assertThat(cipher.getChildren()).hasSize(1); - assertThat(cipher.asString()).isEqualTo("Blowfish"); + assertThat(cipher.asString()).isEqualTo("Blowfish-CBC"); INode mode = cipher.getChildren().get(Mode.class); assertThat(mode).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java index 12c91b316..5c174d392 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/CAST5Test.java @@ -79,7 +79,7 @@ public void asserts( INode cipher = nodes.get(0); assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); assertThat(cipher.getChildren()).hasSize(2); - assertThat(cipher.asString()).isEqualTo("CAST-128"); + assertThat(cipher.asString()).isEqualTo("CAST5-CBC"); INode mode = cipher.getChildren().get(Mode.class); assertThat(mode).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java index 94fd9a09c..8a8c6a9c7 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/ChaCha20Poly1305Test.java @@ -65,7 +65,7 @@ public void asserts( INode cipher = nodes.get(0); assertThat(cipher.getKind()).isEqualTo(AuthenticatedEncryption.class); assertThat(cipher.getChildren()).hasSize(1); - assertThat(cipher.asString()).isEqualTo("ChaCha20Poly1305"); + assertThat(cipher.asString()).isEqualTo("ChaCha20-Poly1305"); INode messageDigest = cipher.getChildren().get(MessageDigest.class); assertThat(messageDigest).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java index 714ebbe3a..cee58d89c 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/DESTest.java @@ -80,7 +80,7 @@ public void asserts( INode cipher = nodes.get(0); assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); assertThat(cipher.getChildren()).hasSize(4); - assertThat(cipher.asString()).isEqualTo("DES56-ECB"); + assertThat(cipher.asString()).isEqualTo("DES-56-ECB"); INode mode = cipher.getChildren().get(Mode.class); assertThat(mode).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java index 71338d5f6..e330b7b2b 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java @@ -151,7 +151,7 @@ private void assertHPKENew( * PublicKeyEncryption(EC) * ├─ Encrypt * ├─ Oid(1.2.840.10045.2.1) - * └─ AuthenticatedEncryption(AES128-GCM) + * └─ AuthenticatedEncryption(AES-128-GCM) * ├─ BlockSize(128) * ├─ Oid(2.16.840.1.101.3.4.1.6) * ├─ KeyLength(128) @@ -173,7 +173,7 @@ private void assertHPKENew( INode aead = root.getChildren().get(AuthenticatedEncryption.class); assertThat(aead).isNotNull(); - assertThat(aead.asString()).isEqualTo("AES128-GCM"); + assertThat(aead.asString()).isEqualTo("AES-128-GCM"); assertThat(aead.getChildren()).hasSize(4); INode blockSize = aead.getChildren().get(BlockSize.class); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java index 46fa04a3c..bd456aa8b 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/RC2Test.java @@ -78,7 +78,7 @@ public void asserts( INode cipher = nodes.get(0); assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); assertThat(cipher.getChildren()).hasSize(1); - assertThat(cipher.asString()).isEqualTo("RC2"); + assertThat(cipher.asString()).isEqualTo("RC2-CBC"); INode mode = cipher.getChildren().get(Mode.class); assertThat(mode).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java index 134b3062a..2437eb099 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/TripleDESTest.java @@ -69,7 +69,7 @@ public void asserts( INode cipher = nodes.get(0); assertThat(cipher.getKind()).isEqualTo(BlockCipher.class); assertThat(cipher.getChildren()).hasSize(2); - assertThat(cipher.asString()).isEqualTo("3DES"); + assertThat(cipher.asString()).isEqualTo("3DES-CBC"); INode mode = cipher.getChildren().get(Mode.class); assertThat(mode).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java index 098906082..43f1f8a88 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA1Test.java @@ -67,7 +67,7 @@ public void asserts( INode md = nodes.get(0); assertThat(md).isInstanceOf(MessageDigest.class); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA1"); + assertThat(md.asString()).isEqualTo("SHA-1"); INode blockSize = md.getChildren().get(BlockSize.class); assertThat(blockSize).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java index 2aa989158..55dc5bb4c 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA224Test.java @@ -67,7 +67,7 @@ public void asserts( INode md = nodes.get(0); assertThat(md).isInstanceOf(MessageDigest.class); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA224"); + assertThat(md.asString()).isEqualTo("SHA-224"); INode blockSize = md.getChildren().get(BlockSize.class); assertThat(blockSize).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java index c57233605..7984cf644 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA256Test.java @@ -67,7 +67,7 @@ public void asserts( INode md = nodes.get(0); assertThat(md).isInstanceOf(MessageDigest.class); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); INode blockSize = md.getChildren().get(BlockSize.class); assertThat(blockSize).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java index 994af8f7a..8a4698440 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA384Test.java @@ -67,7 +67,7 @@ public void asserts( INode md = nodes.get(0); assertThat(md).isInstanceOf(MessageDigest.class); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA384"); + assertThat(md.asString()).isEqualTo("SHA-384"); INode blockSize = md.getChildren().get(BlockSize.class); assertThat(blockSize).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java index 9485cc62f..9d0b7d92d 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/hash/SHA512Test.java @@ -67,7 +67,7 @@ public void asserts( INode md = nodes.get(0); assertThat(md).isInstanceOf(MessageDigest.class); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.asString()).isEqualTo("SHA-512"); INode blockSize = md.getChildren().get(BlockSize.class); assertThat(blockSize).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java index 71e03b346..d58e52ca7 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/HKDFTest.java @@ -84,12 +84,12 @@ public void asserts( assertThat(root.getKind()).isEqualTo(KeyDerivationFunction.class); assertThat(root).isInstanceOf(HKDF.class); assertThat(root.getChildren()).hasSize(3); - assertThat(root.asString()).isEqualTo("HKDF-SHA512"); + assertThat(root.asString()).isEqualTo("HKDF-SHA-512"); INode md = root.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.asString()).isEqualTo("SHA-512"); assertThat(md.getChildren().get(DigestSize.class).asString()).isEqualTo("512"); assertThat(md.getChildren().get(Oid.class).asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); assertThat(md.getChildren().get(Digest.class).asString()).isEqualTo("DIGEST"); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java index 9a6dff08e..50318602e 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF1Test.java @@ -92,12 +92,12 @@ public void asserts( assertThat(root.getKind()).isEqualTo(PasswordBasedKeyDerivationFunction.class); assertThat(root).isInstanceOf(PBKDF1.class); assertThat(root.getChildren()).hasSize(3); - assertThat(root.asString()).isEqualTo("PBKDF1-SHA256"); + assertThat(root.asString()).isEqualTo("PBKDF1-SHA-256"); INode md = root.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren().get(DigestSize.class)).isNotNull(); assertThat(md.getChildren().get(DigestSize.class).asString()).isEqualTo("256"); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java index dc1bdcabc..7cc7a3057 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/PBKDF2Test.java @@ -96,12 +96,12 @@ public void asserts( assertThat(root.getKind()).isEqualTo(PasswordBasedKeyDerivationFunction.class); assertThat(root).isInstanceOf(PBKDF2.class); assertThat(root.getChildren()).hasSize(3); - assertThat(root.asString()).isEqualTo("PBKDF2-SHA512"); + assertThat(root.asString()).isEqualTo("PBKDF2-SHA-512"); INode md = root.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); assertThat(md.getChildren()).hasSize(4); - assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.asString()).isEqualTo("SHA-512"); assertThat(md.getChildren().get(DigestSize.class).asString()).isEqualTo("512"); assertThat(md.getChildren().get(Oid.class).asString()).isEqualTo("2.16.840.1.101.3.4.2.3"); assertThat(md.getChildren().get(Digest.class).asString()).isEqualTo("DIGEST"); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java index 043764c5f..9aaac66ae 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/kdf/ScryptTest.java @@ -73,7 +73,7 @@ public void asserts( assertThat(root.getKind()).isEqualTo(PasswordBasedKeyDerivationFunction.class); assertThat(root).isInstanceOf(Scrypt.class); assertThat(root.getChildren()).hasSize(2); - assertThat(root.asString()).isEqualTo("SCRYPT"); + assertThat(root.asString()).isEqualTo("scrypt"); assertThat(root.getChildren().get(KeyLength.class).asString()).isEqualTo("256"); assertThat(root.getChildren().get(KeyDerivation.class).asString()) diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java index d5962861d..5daf5dbff 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/CMACTest.java @@ -72,7 +72,7 @@ public void asserts( INode mac = nodes.get(0); assertThat(mac).isInstanceOf(Mac.class); - assertThat(mac.asString()).isEqualTo("AES-CMAC"); + assertThat(mac.asString()).isEqualTo("CMAC-AES"); assertThat(mac.getChildren()).hasSize(2); INode cipher = mac.getChildren().get(BlockCipher.class); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java index 35bf4e431..b62ec4557 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/mac/HMACTest.java @@ -67,12 +67,12 @@ public void asserts( assertThat(nodes).hasSize(1); INode mac = nodes.get(0); assertThat(mac).isInstanceOf(Mac.class); - assertThat(mac.asString()).isEqualTo("HMAC-SHA256"); + assertThat(mac.asString()).isEqualTo("HMAC-SHA-256"); assertThat(mac.getChildren()).hasSize(3); INode digest = mac.getChildren().get(MessageDigest.class); assertThat(digest).isNotNull(); - assertThat(digest.asString()).isEqualTo("SHA256"); + assertThat(digest.asString()).isEqualTo("SHA-256"); assertThat(digest.getChildren()).hasSize(4); assertThat(digest.getChildren().get(Digest.class)).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java index 1f577490c..1f63da7a4 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSSignTest.java @@ -82,7 +82,7 @@ public void asserts( INode sig = nodes.get(0); assertThat(sig.getKind()).isEqualTo(Signature.class); assertThat(sig.getChildren()).hasSize(4); - assertThat(sig.asString()).isEqualTo("SHA256withDSA"); + assertThat(sig.asString()).isEqualTo("DSA-SHA-256"); INode oid = sig.getChildren().get(Oid.class); assertThat(oid).isNotNull(); @@ -100,7 +100,7 @@ public void asserts( INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java index 825a45596..f953bb88d 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/DSSVerifyTest.java @@ -82,7 +82,7 @@ public void asserts( INode sig = nodes.get(0); assertThat(sig.getKind()).isEqualTo(Signature.class); assertThat(sig.getChildren()).hasSize(4); - assertThat(sig.asString()).isEqualTo("SHA256withDSA"); + assertThat(sig.asString()).isEqualTo("DSA-SHA-256"); INode oid = sig.getChildren().get(Oid.class); assertThat(oid).isNotNull(); @@ -100,7 +100,7 @@ public void asserts( INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java index a8aead15c..65be61906 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java @@ -84,7 +84,7 @@ public void asserts( INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.asString()).isEqualTo("SHA-512"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java index f3693fc1b..729be1221 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java @@ -84,7 +84,7 @@ public void asserts( INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA512"); + assertThat(md.asString()).isEqualTo("SHA-512"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java index 76230028b..63d6d5485 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15SignTest.java @@ -83,7 +83,7 @@ public void asserts( INode sig = nodes.get(0); assertThat(sig.getKind()).isEqualTo(Signature.class); assertThat(sig.getChildren()).hasSize(4); - assertThat(sig.asString()).isEqualTo("SHA256withRSA"); + assertThat(sig.asString()).isEqualTo("RSA-PKCS1-1.5-SHA-256"); INode oid = sig.getChildren().get(Oid.class); assertThat(oid).isNotNull(); @@ -107,7 +107,7 @@ public void asserts( INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java index 2c2e4449c..58b0cb8a4 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PKCS1v15VerifyTest.java @@ -84,7 +84,7 @@ public void asserts( INode sig = nodes.get(0); assertThat(sig.getKind()).isEqualTo(Signature.class); assertThat(sig.getChildren()).hasSize(4); - assertThat(sig.asString()).isEqualTo("SHA256withRSA"); + assertThat(sig.asString()).isEqualTo("RSA-PKCS1-1.5-SHA-256"); INode oid = sig.getChildren().get(Oid.class); assertThat(oid).isNotNull(); @@ -108,7 +108,7 @@ public void asserts( INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java index 9f8275c5a..f87f57004 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSSignTest.java @@ -83,7 +83,7 @@ public void asserts( INode pss = nodes.get(0); assertThat(pss.getKind()).isEqualTo(ProbabilisticSignatureScheme.class); assertThat(pss.getChildren()).hasSize(4); - assertThat(pss.asString()).isEqualTo("RSASSA-PSS"); + assertThat(pss.asString()).isEqualTo("RSA-PSS"); INode oid = pss.getChildren().get(Oid.class); assertThat(oid).isNotNull(); @@ -107,7 +107,7 @@ public void asserts( INode md = pss.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java index 066ce09ce..6ada8cfb9 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/PSSVerifyTest.java @@ -83,7 +83,7 @@ public void asserts( INode pss = nodes.get(0); assertThat(pss.getKind()).isEqualTo(ProbabilisticSignatureScheme.class); assertThat(pss.getChildren()).hasSize(4); - assertThat(pss.asString()).isEqualTo("RSASSA-PSS"); + assertThat(pss.asString()).isEqualTo("RSA-PSS"); INode oid = pss.getChildren().get(Oid.class); assertThat(oid).isNotNull(); @@ -107,7 +107,7 @@ public void asserts( INode md = pss.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); - assertThat(md.asString()).isEqualTo("SHA256"); + assertThat(md.asString()).isEqualTo("SHA-256"); assertThat(md.getChildren()).hasSize(4); INode mdOid = md.getChildren().get(Oid.class); assertThat(mdOid).isNotNull(); From 383d73cb9cd944e9329b35a872da4c9b62833e0b Mon Sep 17 00:00:00 2001 From: san-zrl Date: Wed, 22 Jul 2026 10:08:42 +0200 Subject: [PATCH 6/9] Improved HPKE test Signed-off-by: san-zrl --- .../detection/pycrypto/cipher/HPKETest.java | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java new file mode 100644 index 000000000..60fd4b850 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java @@ -0,0 +1,195 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.cipher; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.Algorithm; +import com.ibm.engine.model.CipherAction; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.KeyAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.mapper.model.AuthenticatedEncryption; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.KeyLength; +import com.ibm.mapper.model.Mode; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.functionality.Encrypt; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class HPKETest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + switch (findingId) { + case 0 -> assertECCImportKey(detectionStore, nodes); + case 1 -> assertHPKENew(detectionStore, nodes); + default -> throw new AssertionError("Unexpected findingId: " + findingId); + } + } + + // ------------------------------------------------------------------------- + // findingId == 0 (ECC.import_key(...)) + // ------------------------------------------------------------------------- + + private void assertECCImportKey( + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(KeyContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(KeyAction.class); + assertThat(((KeyAction) value).getAction()).isEqualTo(KeyAction.Action.GENERATION); + assertThat(detectionStore.getChildren()).isEmpty(); + + /* + * Translation: Key(EC) → KeyGeneration, PublicKeyEncryption(EC) → Oid + */ + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(Key.class); + assertThat(root.asString()).isEqualTo("EC"); + assertThat(root.getChildren()).hasSize(2); + + INode pke = root.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.asString()).isEqualTo("EC"); + assertThat(pke.getChildren()).hasSize(1); + INode oid = pke.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.asString()).isEqualTo("1.2.840.10045.2.1"); + + INode keyGen = root.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + } + + // ------------------------------------------------------------------------- + // findingId == 1 (HPKE.new(key, AES128_GCM)) + // ------------------------------------------------------------------------- + + private void assertHPKENew( + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("HPKE"); + + // Children: ENCRYPT action, two Algorithm stores (key and AEAD), plus a KeyAction child + // from the ECC import_key detection that is promoted as a sub-finding. + assertThat(detectionStore.getChildren()).hasSize(4); + + DetectionStore encryptStore = + getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); + assertThat(encryptStore).isNotNull(); + assertThat(encryptStore.getDetectionValues()).hasSize(1); + IValue encryptValue = encryptStore.getDetectionValues().get(0); + assertThat(encryptValue).isInstanceOf(CipherAction.class); + assertThat(((CipherAction) encryptValue).getAction()) + .isEqualTo(CipherAction.Action.ENCRYPT); + + List> algoStores = + getStoresOfValueType(Algorithm.class, detectionStore.getChildren()); + assertThat(algoStores).hasSize(2); + algoStores.forEach( + s -> { + assertThat(s.getDetectionValues()).hasSize(1); + assertThat(s.getDetectionValues().get(0)).isInstanceOf(Algorithm.class); + }); + + /* + * Translation (enriched): + * PublicKeyEncryption(EC) + * ├─ Encrypt + * ├─ Oid(1.2.840.10045.2.1) + * └─ AuthenticatedEncryption(AES-128-GCM) + * ├─ BlockSize(128) + * ├─ Oid(2.16.840.1.101.3.4.1.6) + * ├─ KeyLength(128) + * └─ Mode(GCM) + */ + assertThat(nodes).hasSize(1); + INode root = nodes.get(0); + assertThat(root.getKind()).isEqualTo(PublicKeyEncryption.class); + assertThat(root.asString()).isEqualTo("EC"); + assertThat(root.getChildren()).hasSize(3); + + INode encrypt = root.getChildren().get(Encrypt.class); + assertThat(encrypt).isNotNull(); + assertThat(encrypt.asString()).isEqualTo("ENCRYPT"); + + INode rootOid = root.getChildren().get(Oid.class); + assertThat(rootOid).isNotNull(); + assertThat(rootOid.asString()).isEqualTo("1.2.840.10045.2.1"); + + INode aead = root.getChildren().get(AuthenticatedEncryption.class); + assertThat(aead).isNotNull(); + assertThat(aead.asString()).isEqualTo("AES-128-GCM"); + assertThat(aead.getChildren()).hasSize(4); + + INode blockSize = aead.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.asString()).isEqualTo("128"); + + INode aeadOid = aead.getChildren().get(Oid.class); + assertThat(aeadOid).isNotNull(); + assertThat(aeadOid.asString()).isEqualTo("2.16.840.1.101.3.4.1.6"); + + INode keyLength = aead.getChildren().get(KeyLength.class); + assertThat(keyLength).isNotNull(); + assertThat(keyLength.asString()).isEqualTo("128"); + + INode mode = aead.getChildren().get(Mode.class); + assertThat(mode).isNotNull(); + assertThat(mode.asString()).isEqualTo("GCM"); + } +} From f4b206a1b5b3748c9648e16a216a8cd6d8650719 Mon Sep 17 00:00:00 2001 From: san-zrl Date: Wed, 22 Jul 2026 10:09:02 +0200 Subject: [PATCH 7/9] Improved HPKE test Signed-off-by: san-zrl --- .../pycrypto/cipher/PythonCryptoCipher.java | 7 +- .../contexts/PycaCipherContextTranslator.java | 1 + .../pycrypto/cipher/PythonCryptoHPKETest.java | 195 ------------------ 3 files changed, 5 insertions(+), 198 deletions(-) delete mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java index a22ec01be..1a53b1862 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java @@ -23,6 +23,7 @@ import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.AlgorithmFactory; import com.ibm.engine.model.factory.CipherActionFactory; import com.ibm.engine.model.factory.ModeFactory; import com.ibm.engine.model.factory.ValueActionFactory; @@ -258,11 +259,11 @@ private PythonCryptoCipher() { .forMethods("new") .shouldBeDetectedAs(new ValueActionFactory<>("HPKE")) .withMethodParameter(ANY) - .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) + .shouldBeDetectedAs(new AlgorithmFactory<>()) .asChildOfParameterWithId(-1) // .addDependingDetectionRules(PythonCryptoPublicKey.ECCRules()) - .withMethodParameter(ANY) - .shouldBeDetectedAs(new com.ibm.engine.model.factory.AlgorithmFactory<>()) + .withMethodParameter("Crypto.Protocol.HPKE.AEAD.*") + .shouldBeDetectedAs(new AlgorithmFactory<>()) .asChildOfParameterWithId(-1) .buildForContext(new CipherContext()) .inBundle(() -> "PyCrypto") diff --git a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java index 4cc5a94d5..5a961e63f 100644 --- a/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java +++ b/python/src/main/java/com/ibm/plugin/translation/translator/contexts/PycaCipherContextTranslator.java @@ -125,6 +125,7 @@ public final class PycaCipherContextTranslator implements IContextTranslation Optional.of(new CBC(detectionLocation)); case "CTR", "MODE_CTR" -> Optional.of(new CTR(detectionLocation)); case "OFB", "MODE_OFB" -> Optional.of(new OFB(detectionLocation)); + case "MODE_OCB" -> Optional.of(new OCB(detectionLocation)); case "CFB", "MODE_CFB" -> Optional.of(new CFB(detectionLocation)); case "CFB8" -> Optional.of(new CFB(8, detectionLocation)); case "GCM", "MODE_GCM" -> Optional.of(new GCM(detectionLocation)); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java deleted file mode 100644 index e330b7b2b..000000000 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoHPKETest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Sonar Cryptography Plugin - * Copyright (C) 2026 PQCA - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ibm.plugin.rules.detection.pycrypto.cipher; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.Algorithm; -import com.ibm.engine.model.CipherAction; -import com.ibm.engine.model.IValue; -import com.ibm.engine.model.KeyAction; -import com.ibm.engine.model.ValueAction; -import com.ibm.engine.model.context.CipherContext; -import com.ibm.engine.model.context.KeyContext; -import com.ibm.mapper.model.AuthenticatedEncryption; -import com.ibm.mapper.model.BlockSize; -import com.ibm.mapper.model.INode; -import com.ibm.mapper.model.Key; -import com.ibm.mapper.model.KeyLength; -import com.ibm.mapper.model.Mode; -import com.ibm.mapper.model.Oid; -import com.ibm.mapper.model.PublicKeyEncryption; -import com.ibm.mapper.model.functionality.Encrypt; -import com.ibm.mapper.model.functionality.KeyGeneration; -import com.ibm.plugin.TestBase; -import java.util.List; -import javax.annotation.Nonnull; -import org.junit.jupiter.api.Test; -import org.sonar.plugins.python.api.PythonCheck; -import org.sonar.plugins.python.api.PythonVisitorContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -public class PythonCryptoHPKETest extends TestBase { - - @Test - void test() { - PythonCheckVerifier.verify( - "src/test/files/rules/detection/pycrypto/cipher/HPKETestFile.py", this); - } - - @Override - public void asserts( - int findingId, - @Nonnull DetectionStore detectionStore, - @Nonnull List nodes) { - switch (findingId) { - case 0 -> assertECCImportKey(detectionStore, nodes); - case 1 -> assertHPKENew(detectionStore, nodes); - default -> throw new AssertionError("Unexpected findingId: " + findingId); - } - } - - // ------------------------------------------------------------------------- - // findingId == 0 (ECC.import_key(...)) - // ------------------------------------------------------------------------- - - private void assertECCImportKey( - @Nonnull DetectionStore detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(KeyContext.class); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(KeyAction.class); - assertThat(((KeyAction) value).getAction()).isEqualTo(KeyAction.Action.GENERATION); - assertThat(detectionStore.getChildren()).isEmpty(); - - /* - * Translation: Key(EC) → KeyGeneration, PublicKeyEncryption(EC) → Oid - */ - assertThat(nodes).hasSize(1); - INode root = nodes.get(0); - assertThat(root.getKind()).isEqualTo(Key.class); - assertThat(root.asString()).isEqualTo("EC"); - assertThat(root.getChildren()).hasSize(2); - - INode pke = root.getChildren().get(PublicKeyEncryption.class); - assertThat(pke).isNotNull(); - assertThat(pke.asString()).isEqualTo("EC"); - assertThat(pke.getChildren()).hasSize(1); - INode oid = pke.getChildren().get(Oid.class); - assertThat(oid).isNotNull(); - assertThat(oid.asString()).isEqualTo("1.2.840.10045.2.1"); - - INode keyGen = root.getChildren().get(KeyGeneration.class); - assertThat(keyGen).isNotNull(); - assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); - } - - // ------------------------------------------------------------------------- - // findingId == 1 (HPKE.new(key, AES128_GCM)) - // ------------------------------------------------------------------------- - - private void assertHPKENew( - @Nonnull DetectionStore detectionStore, - @Nonnull List nodes) { - /* - * Detection Store - */ - assertThat(detectionStore.getDetectionValues()).hasSize(1); - assertThat(detectionStore.getDetectionValueContext()).isInstanceOf(CipherContext.class); - IValue value = detectionStore.getDetectionValues().get(0); - assertThat(value).isInstanceOf(ValueAction.class); - assertThat(value.asString()).isEqualTo("HPKE"); - - // Children: ENCRYPT action, two Algorithm stores (key and AEAD), plus a KeyAction child - // from the ECC import_key detection that is promoted as a sub-finding. - assertThat(detectionStore.getChildren()).hasSize(4); - - DetectionStore encryptStore = - getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); - assertThat(encryptStore).isNotNull(); - assertThat(encryptStore.getDetectionValues()).hasSize(1); - IValue encryptValue = encryptStore.getDetectionValues().get(0); - assertThat(encryptValue).isInstanceOf(CipherAction.class); - assertThat(((CipherAction) encryptValue).getAction()) - .isEqualTo(CipherAction.Action.ENCRYPT); - - List> algoStores = - getStoresOfValueType(Algorithm.class, detectionStore.getChildren()); - assertThat(algoStores).hasSize(2); - algoStores.forEach( - s -> { - assertThat(s.getDetectionValues()).hasSize(1); - assertThat(s.getDetectionValues().get(0)).isInstanceOf(Algorithm.class); - }); - - /* - * Translation (enriched): - * PublicKeyEncryption(EC) - * ├─ Encrypt - * ├─ Oid(1.2.840.10045.2.1) - * └─ AuthenticatedEncryption(AES-128-GCM) - * ├─ BlockSize(128) - * ├─ Oid(2.16.840.1.101.3.4.1.6) - * ├─ KeyLength(128) - * └─ Mode(GCM) - */ - assertThat(nodes).hasSize(1); - INode root = nodes.get(0); - assertThat(root.getKind()).isEqualTo(PublicKeyEncryption.class); - assertThat(root.asString()).isEqualTo("EC"); - assertThat(root.getChildren()).hasSize(3); - - INode encrypt = root.getChildren().get(Encrypt.class); - assertThat(encrypt).isNotNull(); - assertThat(encrypt.asString()).isEqualTo("ENCRYPT"); - - INode rootOid = root.getChildren().get(Oid.class); - assertThat(rootOid).isNotNull(); - assertThat(rootOid.asString()).isEqualTo("1.2.840.10045.2.1"); - - INode aead = root.getChildren().get(AuthenticatedEncryption.class); - assertThat(aead).isNotNull(); - assertThat(aead.asString()).isEqualTo("AES-128-GCM"); - assertThat(aead.getChildren()).hasSize(4); - - INode blockSize = aead.getChildren().get(BlockSize.class); - assertThat(blockSize).isNotNull(); - assertThat(blockSize.asString()).isEqualTo("128"); - - INode aeadOid = aead.getChildren().get(Oid.class); - assertThat(aeadOid).isNotNull(); - assertThat(aeadOid.asString()).isEqualTo("2.16.840.1.101.3.4.1.6"); - - INode keyLength = aead.getChildren().get(KeyLength.class); - assertThat(keyLength).isNotNull(); - assertThat(keyLength.asString()).isEqualTo("128"); - - INode mode = aead.getChildren().get(Mode.class); - assertThat(mode).isNotNull(); - assertThat(mode.asString()).isEqualTo("GCM"); - } -} From e4d246fe07991b229a16bc8b3d09cbc3849e38ed Mon Sep 17 00:00:00 2001 From: san-zrl Date: Wed, 22 Jul 2026 12:26:18 +0200 Subject: [PATCH 8/9] Updated EdDSA, ECDSA and HPKE rules and tests Signed-off-by: san-zrl --- .../pycrypto/cipher/PythonCryptoCipher.java | 3 +- .../publickey/PythonCryptoPublicKey.java | 2 +- .../rules/detection/pycrypto/kdf/TestFile.py | 37 ----- .../pycrypto/keyagreement/TestFile.py | 22 --- .../rules/detection/pycrypto/mac/TestFile.py | 10 -- .../pycrypto/signature/ECDSASignTestFile.py | 4 +- .../pycrypto/signature/ECDSAVerifyTestFile.py | 4 +- .../detection/pycrypto/cipher/HPKETest.java | 38 +++-- .../pycrypto/signature/ECDSASignTest.java | 132 ++++++++++++++++++ .../pycrypto/signature/ECDSAVerifyTest.java | 132 ++++++++++++++++++ .../pycrypto/signature/EdDSASignTest.java | 17 ++- .../pycrypto/signature/EdDSAVerifyTest.java | 17 ++- 12 files changed, 327 insertions(+), 91 deletions(-) delete mode 100644 python/src/test/files/rules/detection/pycrypto/kdf/TestFile.py delete mode 100644 python/src/test/files/rules/detection/pycrypto/keyagreement/TestFile.py delete mode 100644 python/src/test/files/rules/detection/pycrypto/mac/TestFile.py create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSASignTest.java create mode 100644 python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSAVerifyTest.java diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java index 1a53b1862..7a2e24b04 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java @@ -30,6 +30,7 @@ import com.ibm.engine.rule.IDetectionRule; import com.ibm.engine.rule.builder.DetectionRuleBuilder; import com.ibm.plugin.rules.detection.Memoize; +import com.ibm.plugin.rules.detection.pycrypto.publickey.PythonCryptoPublicKey; import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -261,7 +262,7 @@ private PythonCryptoCipher() { .withMethodParameter(ANY) .shouldBeDetectedAs(new AlgorithmFactory<>()) .asChildOfParameterWithId(-1) - // .addDependingDetectionRules(PythonCryptoPublicKey.ECCRules()) + .addDependingDetectionRules(PythonCryptoPublicKey.ECCRules()) .withMethodParameter("Crypto.Protocol.HPKE.AEAD.*") .shouldBeDetectedAs(new AlgorithmFactory<>()) .asChildOfParameterWithId(-1) diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java index 513193d10..e1fdb9483 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/publickey/PythonCryptoPublicKey.java @@ -267,7 +267,7 @@ public static List> ECCRules() { @Nonnull private static List> buildECCRules() { - return List.of(ECC_CONSTRUCT, ECC_GENERATE, ECC_PUBLIC_KEY); + return List.of(ECC_CONSTRUCT, ECC_GENERATE, ECC_IMPORT, ECC_PUBLIC_KEY); } @Nonnull diff --git a/python/src/test/files/rules/detection/pycrypto/kdf/TestFile.py b/python/src/test/files/rules/detection/pycrypto/kdf/TestFile.py deleted file mode 100644 index a4dc93132..000000000 --- a/python/src/test/files/rules/detection/pycrypto/kdf/TestFile.py +++ /dev/null @@ -1,37 +0,0 @@ -from Crypto.Protocol.KDF import PBKDF1, PBKDF2, scrypt, bcrypt, HKDF -from Crypto.Hash import SHA256, SHA512 - -# PBKDF1 -def test_pbkdf1(): - password = b"password" - salt = b"salt1234" - key = PBKDF1(password, salt, 16, 1000, SHA256) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF1-SHA256}} - - -# PBKDF2 -def test_pbkdf2(): - password = b"password" - salt = b"salt1234" - key = PBKDF2(password, salt, dkLen=64, count=1, hmac_hash_module=SHA512) # Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA512}} - - -# scrypt -def test_scrypt(): - password = b"password" - salt = b"salt1234" - key2 = scrypt(password, salt, key_len=32, N=2**14, r=8, p=1, num_keys=1) # Noncompliant {{(PasswordBasedKeyDerivationFunction) SCRYPT}} - - -# bcrypt -def test_bcrypt(): - password = b"password" - salt = b"salt1234567890ab" - key2 = bcrypt(password, cost=10, salt=salt) # detected but not mapped - - -# HKDF -def test_hkdf(): - secret = b"secret" - salt = b"salt1234567890ab" - key = HKDF(secret, 32, salt, SHA512) # Noncompliant {{(KeyDerivationFunction) HKDF-SHA512}} - diff --git a/python/src/test/files/rules/detection/pycrypto/keyagreement/TestFile.py b/python/src/test/files/rules/detection/pycrypto/keyagreement/TestFile.py deleted file mode 100644 index 7d4f47217..000000000 --- a/python/src/test/files/rules/detection/pycrypto/keyagreement/TestFile.py +++ /dev/null @@ -1,22 +0,0 @@ -from Crypto.PublicKey import ECC -from Crypto.Hash import SHAKE128 -from Crypto.Protocol.DH import key_agreement, import_x25519_public_key, import_x25519_private_key, import_x448_public_key, import_x448_public_key - -def kdf(x): - return SHAKE128.new(x).read(32) # Noncompliant {{(ExtendableOutputFunction) SHAKE128}} - -U_static = ECC.generate(curve='p256') # Noncompliant {{(PrivateKey) EC-secp256r1}} - -V_static = U_static.public_key() - -session_key = key_agreement(static_priv=U_static, # Noncompliant {{(KeyAgreement) ECDH}} - static_pub=V_static, - kdf=kdf) - -pub_key = import_x25519_public_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x25519}} - -priv_key = import_x25519_private_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x25519}} - -pub_key = import_x448_public_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x448}} - -priv_key = import_x448_public_key(b'some 56 byte key') # Noncompliant {{(KeyAgreement) x448}} \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/mac/TestFile.py b/python/src/test/files/rules/detection/pycrypto/mac/TestFile.py deleted file mode 100644 index f4fd4f244..000000000 --- a/python/src/test/files/rules/detection/pycrypto/mac/TestFile.py +++ /dev/null @@ -1,10 +0,0 @@ -from Crypto.Hash import CMAC, HMAC, SHA256 -from Crypto.Cipher import AES - -# CMAC -key = b'some key' -cmac = CMAC.new(key, AES) # Noncompliant {{(Mac) AES-CMAC}} - -# HMAC -secret = b'some secret' -hmac = HMAC.new(secret, digestmod=SHA256) # Noncompliant {{(Mac) HMAC-SHA256}} \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py index 04c1fdff5..f8e0479f3 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py @@ -4,6 +4,6 @@ message = b'some message' key = ECC.import_key(open('privkey.der').read()) # Noncompliant {{(Key) EC}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -signer = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withECDSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +signer = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) ECDSA-SHA-256}} signature = signer.sign(h) \ No newline at end of file diff --git a/python/src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py b/python/src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py index d5d4d0773..e6a1806a7 100644 --- a/python/src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py +++ b/python/src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py @@ -4,8 +4,8 @@ message = b'some message' key = ECC.import_key(open('pubkey.der').read()) # Noncompliant {{(Key) EC}} -h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA256}} -verifier = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) SHA256withECDSA}} +h = SHA256.new(message) # Noncompliant {{(MessageDigest) SHA-256}} +verifier = DSS.new(key, 'fips-186-3') # Noncompliant {{(Signature) ECDSA-SHA-256}} signature = b'some signature' try: diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java index 60fd4b850..f35187237 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/cipher/HPKETest.java @@ -22,7 +22,6 @@ import static org.assertj.core.api.Assertions.assertThat; import com.ibm.engine.detection.DetectionStore; -import com.ibm.engine.model.Algorithm; import com.ibm.engine.model.CipherAction; import com.ibm.engine.model.IValue; import com.ibm.engine.model.KeyAction; @@ -124,10 +123,6 @@ private void assertHPKENew( assertThat(value).isInstanceOf(ValueAction.class); assertThat(value.asString()).isEqualTo("HPKE"); - // Children: ENCRYPT action, two Algorithm stores (key and AEAD), plus a KeyAction child - // from the ECC import_key detection that is promoted as a sub-finding. - assertThat(detectionStore.getChildren()).hasSize(4); - DetectionStore encryptStore = getStoreOfValueType(CipherAction.class, detectionStore.getChildren()); assertThat(encryptStore).isNotNull(); @@ -137,14 +132,12 @@ private void assertHPKENew( assertThat(((CipherAction) encryptValue).getAction()) .isEqualTo(CipherAction.Action.ENCRYPT); - List> algoStores = - getStoresOfValueType(Algorithm.class, detectionStore.getChildren()); - assertThat(algoStores).hasSize(2); - algoStores.forEach( - s -> { - assertThat(s.getDetectionValues()).hasSize(1); - assertThat(s.getDetectionValues().get(0)).isInstanceOf(Algorithm.class); - }); + DetectionStore keyStore = + getStoreOfValueType(KeyAction.class, detectionStore.getChildren()); + assertThat(keyStore).isNotNull(); + assertThat(keyStore.getDetectionValues()).hasSize(1); + assertThat(((KeyAction) keyStore.getDetectionValues().get(0)).getAction()) + .isEqualTo(KeyAction.Action.GENERATION); /* * Translation (enriched): @@ -156,12 +149,17 @@ private void assertHPKENew( * ├─ Oid(2.16.840.1.101.3.4.1.6) * ├─ KeyLength(128) * └─ Mode(GCM) + * └─ (Key) EC + * └─ (PublicKeyEncryption) EC + * └─ (Oid) 1.2.840.10045.2.1 + * └─ (KeyGeneration) KEYGENERATION + * └─ (Oid) 1.2.840.10045.2.1 */ assertThat(nodes).hasSize(1); INode root = nodes.get(0); assertThat(root.getKind()).isEqualTo(PublicKeyEncryption.class); assertThat(root.asString()).isEqualTo("EC"); - assertThat(root.getChildren()).hasSize(3); + assertThat(root.getChildren()).hasSize(4); INode encrypt = root.getChildren().get(Encrypt.class); assertThat(encrypt).isNotNull(); @@ -191,5 +189,17 @@ private void assertHPKENew( INode mode = aead.getChildren().get(Mode.class); assertThat(mode).isNotNull(); assertThat(mode.asString()).isEqualTo("GCM"); + + INode key = root.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("EC"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren().get(Oid.class).asString()).isEqualTo("1.2.840.10045.2.1"); } } diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSASignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSASignTest.java new file mode 100644 index 000000000..44c82d828 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSASignTest.java @@ -0,0 +1,132 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ECDSASignTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/ECDSASignTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("ECDSA"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("SIGN"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(4); + assertThat(sig.asString()).isEqualTo("ECDSA-SHA-256"); + + INode oid = sig.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.10045.4.3.2"); + + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("EC"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren().get(Oid.class).asString()).isEqualTo("1.2.840.10045.2.1"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA-256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode sign = sig.getChildren().get(Sign.class); + assertThat(sign).isNotNull(); + assertThat(sign.getChildren()).isEmpty(); + assertThat(sign.asString()).isEqualTo("SIGN"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSAVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSAVerifyTest.java new file mode 100644 index 000000000..e34b57645 --- /dev/null +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/ECDSAVerifyTest.java @@ -0,0 +1,132 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2026 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.pycrypto.signature; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.SignatureAction; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.BlockSize; +import com.ibm.mapper.model.DigestSize; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; +import com.ibm.mapper.model.functionality.Verify; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.plugins.python.api.PythonCheck; +import org.sonar.plugins.python.api.PythonVisitorContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class ECDSAVerifyTest extends TestBase { + + @Test + void test() { + PythonCheckVerifier.verify( + "src/test/files/rules/detection/pycrypto/signature/ECDSAVerifyTestFile.py", this); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + if (findingId == 2) { + // detection store + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOf(SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()).isEqualTo("ECDSA"); + + DetectionStore sigStore = + getStoreOfValueType(SignatureAction.class, detectionStore.getChildren()); + assertThat(sigStore).isNotNull(); + assertThat(sigStore.getDetectionValues()).hasSize(1); + assertThat(sigStore.getDetectionValueContext()).isInstanceOf(SignatureContext.class); + IValue sigValue = sigStore.getDetectionValues().get(0); + assertThat(sigValue).isInstanceOf(SignatureAction.class); + assertThat(sigValue.asString()).isEqualTo("VERIFY"); + + // translation + assertThat(nodes).hasSize(1); + INode sig = nodes.get(0); + assertThat(sig.getKind()).isEqualTo(Signature.class); + assertThat(sig.getChildren()).hasSize(4); + assertThat(sig.asString()).isEqualTo("ECDSA-SHA-256"); + + INode oid = sig.getChildren().get(Oid.class); + assertThat(oid).isNotNull(); + assertThat(oid.getChildren()).isEmpty(); + assertThat(oid.asString()).isEqualTo("1.2.840.10045.4.3.2"); + + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("EC"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren().get(Oid.class).asString()).isEqualTo("1.2.840.10045.2.1"); + + INode md = sig.getChildren().get(MessageDigest.class); + assertThat(md).isNotNull(); + assertThat(md.asString()).isEqualTo("SHA-256"); + assertThat(md.getChildren()).hasSize(4); + INode mdOid = md.getChildren().get(Oid.class); + assertThat(mdOid).isNotNull(); + assertThat(mdOid.getChildren()).isEmpty(); + assertThat(mdOid.asString()).isEqualTo("2.16.840.1.101.3.4.2.1"); + INode digestSize = md.getChildren().get(DigestSize.class); + assertThat(digestSize).isNotNull(); + assertThat(digestSize.getChildren()).isEmpty(); + assertThat(digestSize.asString()).isEqualTo("256"); + INode blockSize = md.getChildren().get(BlockSize.class); + assertThat(blockSize).isNotNull(); + assertThat(blockSize.getChildren()).isEmpty(); + assertThat(blockSize.asString()).isEqualTo("512"); + INode digest = md.getChildren().get(Digest.class); + assertThat(digest).isNotNull(); + assertThat(digest.getChildren()).isEmpty(); + assertThat(digest.asString()).isEqualTo("DIGEST"); + + INode verify = sig.getChildren().get(Verify.class); + assertThat(verify).isNotNull(); + assertThat(verify.getChildren()).isEmpty(); + assertThat(verify.asString()).isEqualTo("VERIFY"); + } + } +} diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java index 65be61906..8f4f6d267 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSASignTest.java @@ -29,10 +29,13 @@ import com.ibm.mapper.model.BlockSize; import com.ibm.mapper.model.DigestSize; import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; import com.ibm.mapper.model.MessageDigest; import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; import com.ibm.mapper.model.Signature; import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; import com.ibm.mapper.model.functionality.Sign; import com.ibm.plugin.TestBase; import java.util.List; @@ -79,9 +82,21 @@ public void asserts( assertThat(nodes).hasSize(1); INode sig = nodes.get(0); assertThat(sig.getKind()).isEqualTo(Signature.class); - assertThat(sig.getChildren()).hasSize(2); + assertThat(sig.getChildren()).hasSize(3); assertThat(sig.asString()).isEqualTo("EdDSA"); + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("EC"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren().get(Oid.class).asString()).isEqualTo("1.2.840.10045.2.1"); + INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); assertThat(md.asString()).isEqualTo("SHA-512"); diff --git a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java index 729be1221..12582c85d 100644 --- a/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java +++ b/python/src/test/java/com/ibm/plugin/rules/detection/pycrypto/signature/EdDSAVerifyTest.java @@ -29,10 +29,13 @@ import com.ibm.mapper.model.BlockSize; import com.ibm.mapper.model.DigestSize; import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Key; import com.ibm.mapper.model.MessageDigest; import com.ibm.mapper.model.Oid; +import com.ibm.mapper.model.PublicKeyEncryption; import com.ibm.mapper.model.Signature; import com.ibm.mapper.model.functionality.Digest; +import com.ibm.mapper.model.functionality.KeyGeneration; import com.ibm.mapper.model.functionality.Verify; import com.ibm.plugin.TestBase; import java.util.List; @@ -79,9 +82,21 @@ public void asserts( assertThat(nodes).hasSize(1); INode sig = nodes.get(0); assertThat(sig.getKind()).isEqualTo(Signature.class); - assertThat(sig.getChildren()).hasSize(2); + assertThat(sig.getChildren()).hasSize(3); assertThat(sig.asString()).isEqualTo("EdDSA"); + INode key = sig.getChildren().get(Key.class); + assertThat(key).isNotNull(); + assertThat(key.asString()).isEqualTo("EC"); + assertThat(key.getChildren()).hasSize(2); + INode keyGen = key.getChildren().get(KeyGeneration.class); + assertThat(keyGen).isNotNull(); + assertThat(keyGen.getChildren()).isEmpty(); + assertThat(keyGen.asString()).isEqualTo("KEYGENERATION"); + INode pke = key.getChildren().get(PublicKeyEncryption.class); + assertThat(pke).isNotNull(); + assertThat(pke.getChildren().get(Oid.class).asString()).isEqualTo("1.2.840.10045.2.1"); + INode md = sig.getChildren().get(MessageDigest.class); assertThat(md).isNotNull(); assertThat(md.asString()).isEqualTo("SHA-512"); From a448f65be79e2787d49a8c087b54f1b7084a0154 Mon Sep 17 00:00:00 2001 From: san-zrl Date: Thu, 23 Jul 2026 14:13:43 +0200 Subject: [PATCH 9/9] Added optional iv parameter to block ciphers Signed-off-by: san-zrl --- .../pycrypto/cipher/PythonCryptoCipher.java | 148 +++++++++++++++--- 1 file changed, 122 insertions(+), 26 deletions(-) diff --git a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java index 7a2e24b04..892cdf56e 100644 --- a/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java +++ b/python/src/main/java/com/ibm/plugin/rules/detection/pycrypto/cipher/PythonCryptoCipher.java @@ -66,7 +66,7 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); - private static final IDetectionRule AES_NEW = + private static final IDetectionRule AES_2 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.AES") @@ -80,7 +80,22 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule DES_NEW = + private static final IDetectionRule AES_3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.AES") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("AES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.AES.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // optional iv + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES_2 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.DES") @@ -94,7 +109,36 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule DES3_NEW = + private static final IDetectionRule DES_3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.DES") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("DES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.DES.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // optional iv + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES3_2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.DES3") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("3DES")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.DES3.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule DES3_3 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.DES3") @@ -104,11 +148,12 @@ private PythonCryptoCipher() { .withMethodParameter("Crypto.Cipher.DES3.*") .shouldBeDetectedAs(new ModeFactory<>()) .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // optional iv .buildForContext(new CipherContext()) .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule BLOWFISH_NEW = + private static final IDetectionRule BLOWFISH_2 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.Blowfish") @@ -122,7 +167,22 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule CAST_NEW = + private static final IDetectionRule BLOWFISH_3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.Blowfish") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("Blowfish")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.Blowfish.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // optional iv + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule CAST_2 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.CAST") @@ -136,7 +196,36 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule ARC2_NEW = + private static final IDetectionRule CAST_3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.CAST") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.CAST.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // optional iv + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule ARC2_2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("Crypto.Cipher.ARC2") + .forMethods("new") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2")) + .withMethodParameter(ANY) + .withMethodParameter("Crypto.Cipher.ARC2.*") + .shouldBeDetectedAs(new ModeFactory<>()) + .asChildOfParameterWithId(-1) + .buildForContext(new CipherContext()) + .inBundle(() -> "PyCrypto") + .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); + + private static final IDetectionRule ARC2_3 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.ARC2") @@ -146,11 +235,12 @@ private PythonCryptoCipher() { .withMethodParameter("Crypto.Cipher.ARC2.*") .shouldBeDetectedAs(new ModeFactory<>()) .asChildOfParameterWithId(-1) + .withMethodParameter(ANY) // optional iv .buildForContext(new CipherContext()) .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule ARC4_NEW = + private static final IDetectionRule ARC4 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.ARC4") @@ -161,7 +251,7 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule CHACHA20_NEW = + private static final IDetectionRule CHACHA20 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.ChaCha20") @@ -172,7 +262,7 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); - private static final IDetectionRule CHACHA20_POLY1305_NEW = + private static final IDetectionRule CHACHA20_POLY1305 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.ChaCha20_Poly1305") @@ -183,7 +273,7 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); - private static final IDetectionRule SALSA20_NEW = + private static final IDetectionRule SALSA20 = new DetectionRuleBuilder() .createDetectionRule() .forObjectTypes("Crypto.Cipher.Salsa20") @@ -194,7 +284,7 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule PKCS1_OAEP_NEW = + private static final IDetectionRule PKCS1_OAEP = new DetectionRuleBuilder() .createDetectionRule() .forObjectExactTypes("Crypto.Cipher.PKCS1_OAEP") @@ -220,7 +310,7 @@ private PythonCryptoCipher() { // .inBundle(() -> "PyCrypto") // .withDependingDetectionRules(List.of(ENCRYPT, DECRYPT)); - private static final IDetectionRule PKCS1_V1_5_NEW = + private static final IDetectionRule PKCS1_V1_5 = new DetectionRuleBuilder() .createDetectionRule() .forObjectExactTypes("Crypto.Cipher.PKCS1_v1_5") @@ -253,7 +343,7 @@ private PythonCryptoCipher() { .inBundle(() -> "PyCrypto") .withoutDependingDetectionRules(); - private static final IDetectionRule HPKE_NEW = + private static final IDetectionRule HPKE = new DetectionRuleBuilder() .createDetectionRule() .forObjectExactTypes("Crypto.Protocol.HPKE") @@ -282,19 +372,25 @@ public static List> rules() { @Nonnull private static List> buildRules() { return List.of( - AES_NEW, - DES_NEW, - DES3_NEW, - BLOWFISH_NEW, - CAST_NEW, - ARC2_NEW, - ARC4_NEW, - CHACHA20_NEW, - CHACHA20_POLY1305_NEW, - SALSA20_NEW, - PKCS1_OAEP_NEW, + AES_2, + AES_3, + DES_2, + DES_3, + DES3_2, + DES3_3, + BLOWFISH_2, + BLOWFISH_3, + CAST_2, + CAST_3, + ARC2_2, + ARC2_3, + ARC4, + CHACHA20, + CHACHA20_POLY1305, + SALSA20, + PKCS1_OAEP, // PKCS1_OAEP_NEW_WITH_HASH, - PKCS1_V1_5_NEW, - HPKE_NEW); + PKCS1_V1_5, + HPKE); } }