Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0236660
feat(mapper): extend model for PyCryptodome support
san-zrl Oct 1, 2026
5ddb380
feat(mapper): extend pyca mappers with new algorithm entries
san-zrl Oct 1, 2026
5e8baef
feat(mapper/python): add ECDH→XDH and signature reorganizer rules, wi…
san-zrl Oct 1, 2026
9e97579
chore(python): reorganise pyca detection rules into pyca/ subpackage
san-zrl Oct 1, 2026
80efc72
feat(python): add PyCryptodome (pycryptodome/pycrypto) detection rules
san-zrl Oct 1, 2026
e5a70b0
feat(python): wire new translator contexts for key and random
san-zrl Oct 1, 2026
b7bc7c4
feat(python): update existing context translators for PyCryptodome
san-zrl Oct 1, 2026
e99c3c9
chore(python): move pyca test fixtures and test classes into pyca/ su…
san-zrl Oct 1, 2026
71d1ff1
test(python): add PyCryptodome test fixtures and test classes
san-zrl Oct 1, 2026
83c7681
fix/DH.key_agreement detection rule
san-zrl Oct 5, 2026
343be20
fix/MGF1 parameter name is mgfSeed
san-zrl Oct 5, 2026
40d4374
fix/place holder size in X25519TestFile.py and X448TestFile.py
san-zrl Oct 5, 2026
612572f
fix/PSS option is salt_bytes
san-zrl Oct 5, 2026
8710625
fix/PCD SHA512 requires truncate as str parameter
san-zrl Oct 5, 2026
42957e7
fix/PKCS1_OAEP option is spelled mgfunc
san-zrl Oct 5, 2026
dab8ca3
fix/allow named parameters for key and mode in AES, DES, 3DES, Blowfi…
san-zrl Oct 6, 2026
64d51b6
style: apply spotless formatting
san-zrl Oct 6, 2026
98586ad
fix/simplify enrcypt and decrpyt rules
san-zrl Oct 6, 2026
fd61210
fix/add EdDSA-specific sign/verify rules without requiring a hash child
san-zrl Oct 6, 2026
a84fa00
fix/use RFC 8410 OIDs for Ed25519, Ed448, X25519, X448 in PycaCurveMa…
san-zrl Oct 6, 2026
b7f0849
fix: stop exporting KMAC security strength as a digest size
san-zrl Oct 16, 2026
d05bd7a
fix: model TupleHash128/256 as a parameter set, not a digest size
san-zrl Oct 16, 2026
fc0ace2
test: check KMAC and TupleHash parameter set identifiers in the CBOM
san-zrl Oct 16, 2026
ceca12d
feat: use named parameters for PyCryptodome MAC rules
san-zrl Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion engine/src/main/java/com/ibm/engine/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ public static <O, T> Optional<Integer> bitSizeValueToBitSizeInteger(
if (resolvedValue.value() instanceof Integer i) {
return Optional.of(i);
} else if (resolvedValue.value() instanceof String str) {
return Optional.of(Utils.byteSizeToBitSize(str.getBytes().length));
try {
return Optional.of(Integer.parseInt(str));
} catch (NumberFormatException e) {
return Optional.of(Utils.byteSizeToBitSize(str.getBytes().length));
}
} else {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -53,17 +56,21 @@ 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));
case "CHACHA20POLY1305", "CHACHA20_POLY1305" ->
Optional.of(new ChaCha20Poly1305(detectionLocation));
default -> Optional.empty();
};
}
Expand Down
109 changes: 109 additions & 0 deletions mapper/src/main/java/com/ibm/mapper/mapper/pyca/PycaCurveMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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.algorithms.Ed25519;
import com.ibm.mapper.model.algorithms.Ed448;
import com.ibm.mapper.model.algorithms.X25519;
import com.ibm.mapper.model.algorithms.X448;
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.utils.DetectionLocation;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public final class PycaCurveMapper implements IMapper {

@Nonnull
@Override
public Optional<? extends Algorithm> parse(
@Nullable String str, @Nonnull DetectionLocation detectionLocation) {
if (str == null) {
return Optional.empty();
}

return switch (str.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 "SECP521R1", "PRIME521V1", "P-521", "P521", "NIST P-521" ->
Optional.of(new EllipticCurveAlgorithm(new Secp521r1(detectionLocation)));
case "SECP256K1" ->
Optional.of(new EllipticCurveAlgorithm(new Secp256k1(detectionLocation)));
case "CURVE25519" -> Optional.of(new X25519(detectionLocation));
case "ED25519" -> Optional.of(new Ed25519(detectionLocation));
case "CURVE448" -> Optional.of(new X448(detectionLocation));
case "ED448" -> Optional.of(new Ed448(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();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@

import com.ibm.mapper.mapper.IMapper;
import com.ibm.mapper.model.MessageDigest;
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;
Expand Down Expand Up @@ -59,11 +65,19 @@ 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));
Comment thread
san-zrl marked this conversation as resolved.
Resolved
case "TUPLEHASH256" -> Optional.of(new TupleHash(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();
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.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.algorithms.DH;
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.Fernet;
import com.ibm.mapper.model.algorithms.RSA;
import com.ibm.mapper.model.curves.Curve25519;
import com.ibm.mapper.model.curves.Curve448;
import com.ibm.mapper.utils.DetectionLocation;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public final class PycaKeyBasedAlgorithmMapper implements IMapper {

@Override
public @Nonnull Optional<Algorithm> parse(
@Nullable String str, @Nonnull DetectionLocation detectionLocation) {
if (str == null) {
return Optional.empty();
}

return switch (str.toUpperCase().trim()) {
case "RSA" -> Optional.of(new RSA(detectionLocation));
case "DSA" -> Optional.of(new DSA(detectionLocation));
case "DH" -> Optional.of(new DH(detectionLocation));
case "EC" -> Optional.of(new EllipticCurveAlgorithm(detectionLocation));
case "CURVE25519" ->
Optional.of(new EllipticCurveAlgorithm(new Curve25519(detectionLocation)));
case "CURVE448" ->
Optional.of(new EllipticCurveAlgorithm(new Curve448(detectionLocation)));
case "ED25519" -> Optional.of(new Ed25519(detectionLocation));
case "ED448" -> Optional.of(new Ed448(detectionLocation));
case "ELGAMAL" -> Optional.of(new ElGamal(detectionLocation));
case "FERNET" -> Optional.of(new Fernet(detectionLocation));
default -> Optional.empty();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@
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.KMAC;
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;
Expand All @@ -42,6 +45,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;
Expand Down Expand Up @@ -104,13 +108,22 @@ 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" ->
Optional.of(new BLAKE2s(Mac.class, new BLAKE2s(false, detectionLocation)));
case "SM3" -> Optional.of(new SM3(Mac.class, new SM3(detectionLocation)));
case "KMAC128" -> Optional.of(new KMAC(Mac.class, new KMAC(128, detectionLocation)));
Comment thread
san-zrl marked this conversation as resolved.
Resolved
case "KMAC256" -> Optional.of(new KMAC(Mac.class, new KMAC(256, 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();
};
}
Expand Down
24 changes: 23 additions & 1 deletion mapper/src/main/java/com/ibm/mapper/model/DigestSize.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,33 @@ public DigestSize(@Nonnull Integer value, @Nonnull DetectionLocation detectionLo
this.value = value;
}

private DigestSize(
@Nonnull Integer value,
@Nonnull DetectionLocation detectionLocation,
@Nonnull NodeOrigin origin) {
super(DigestSize.class, detectionLocation, origin);
this.value = value;
}

private DigestSize(@Nonnull DigestSize digestSize) {
super(digestSize.type, digestSize.detectionLocation, digestSize.children);
super(
digestSize.type,
digestSize.detectionLocation,
digestSize.children,
digestSize.origin);
this.value = digestSize.value;
}

/**
* Creates a DigestSize with DEFAULT origin, for use in algorithm constructors where the size is
* a known constant rather than something directly detected in source code.
*/
@Nonnull
public static DigestSize ofDefault(
@Nonnull Integer value, @Nonnull DetectionLocation detectionLocation) {
return new DigestSize(value, detectionLocation, NodeOrigin.DEFAULT);
}

@Nonnull
public Integer getValue() {
return value;
Expand Down
4 changes: 4 additions & 0 deletions mapper/src/main/java/com/ibm/mapper/model/PrivateKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public PrivateKey(@Nonnull Signature signature) {
super(signature, PrivateKey.class);
}

public PrivateKey(@Nonnull KeyAgreement keyAgreement) {
super(keyAgreement, PrivateKey.class);
}

public PrivateKey(@Nonnull Key key) {
super(key, key.detectionLocation, PrivateKey.class);
}
Expand Down
4 changes: 4 additions & 0 deletions mapper/src/main/java/com/ibm/mapper/model/PublicKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public PublicKey(@Nonnull Signature signature) {
super(signature, PublicKey.class);
}

public PublicKey(@Nonnull KeyAgreement keyAgreement) {
super(keyAgreement, PublicKey.class);
}

public PublicKey(@Nonnull Key key) {
super(key, key.detectionLocation, PublicKey.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package com.ibm.mapper.model.algorithms;

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.Mac;
Expand Down Expand Up @@ -71,14 +70,17 @@ public KMAC(@Nonnull DetectionLocation detectionLocation) {
this.put(new CSHAKE(detectionLocation));
}

/**
* The parameter set identifier (128 or 256) denotes the security strength only. The output
* length is independent of it and its default differs between libraries, so it is not modelled.
*/
public KMAC(int parameterSetIdentifier, @Nonnull DetectionLocation detectionLocation) {
/* KMAC is a hash function mostly used as a MAC */
super(NAME, Mac.class, detectionLocation);
this.put(
new ParameterSetIdentifier(
String.valueOf(parameterSetIdentifier), detectionLocation));
this.put(new CSHAKE(parameterSetIdentifier, detectionLocation));
this.put(new DigestSize(2 * parameterSetIdentifier, detectionLocation));
}

public KMAC(@Nonnull final Class<? extends IPrimitive> asKind, @Nonnull KMAC kmac) {
Expand Down
Loading
Loading