Binaries and Compiled Artefacts
Binaries and Compiled Artefacts
Inventory the cryptography that ships inside executables, libraries, .NET assemblies and Java archives, when you do not have the source code.
Overview
The binary scan finds cryptography inside compiled artefacts. It complements the source code scan, which needs the source, and the container image scan, which on its own sees package names, libraries and configuration files.
Nothing is executed or loaded. Files are read as bytes and parsed with read-only parsers for ELF, PE / COFF and Mach-O, plus a bounded reader for Java class files and .NET metadata.
What is read
| Artefact | Evidence | Confidence |
|---|---|---|
| ELF, PE / COFF, Mach-O | Linked crypto libraries: ELF DT_NEEDED entries, PE import and delay-import tables, Mach-O dylib load commands. OpenSSL, BoringSSL, LibreSSL, libgcrypt, libsodium, Mbed TLS, wolfSSL, GnuTLS, NSS, CommonCrypto, Security.framework, Windows CNG (bcrypt.dll, ncrypt.dll), crypt32.dll and the advapi32.dll Crypt* functions. | import |
Imported, dynamic and (when the binary is not stripped) static symbols mapped to algorithms, for example RSA_*, EC_KEY_*, ECDSA_*, DH_*, EVP_md5, mbedtls_*, wc_*, crypto_sign_*, BCryptSecretAgreement, CryptGenKey, CC_MD5, SecKeyCreate*. | symbol | |
Embedded OIDs: RSA and its signature OIDs, EC public key, ECDSA, DSA, DH, MD5, SHA-1, ML-DSA, SLH-DSA and ML-KEM. PQC algorithm names such as ML-KEM-768, ML-DSA-65 or X25519MLKEM768. | constant | |
Windows CNG algorithm identifiers (RSA, ECDH_P256, ML-KEM...), counted only when the image actually uses CNG. | constant | |
Library version strings (OpenSSL 1.1.1w, LibreSSL, BoringSSL, Mbed TLS, wolfSSL). When the library is not dynamically linked, it is reported as statically linked. | constant | |
| .NET assemblies | Crypto type names from the assembly metadata (RSACryptoServiceProvider, RSACng, ECDsa, ECDiffieHellman, DSA, MD5, SHA1, TripleDES, MLDsa, MLKem, SlhDsa...), only when the assembly references System.Security.Cryptography. | symbol |
| Java class, JAR / WAR / EAR | Archives are opened recursively, including nested libraries (WEB-INF/lib, BOOT-INF/lib...). Class references to javax.crypto, java.security (KeyPairGenerator, Signature, MessageDigest, KeyFactory, KeyStore...) and Bouncy Castle; the algorithm is taken from the class name (RSAPublicKey, ECGenParameterSpec, MLDSA*...). | symbol |
String constants passed to the Java crypto API ("RSA", "RSA/ECB/OAEPWith...", "SHA1withRSA", "EC", "DESede", "MD5", "ML-DSA-65", "ML-KEM-768"...), only in classes that use a crypto API. JAR signature blocks (META-INF/*.RSA, *.DSA, *.EC); Bouncy Castle identified from the manifest. | constant | |
| Keystores | Keystores bundled in archives (.jks, .jceks, .p12, .pfx, .keystore, .truststore) are reported as keystore findings; PKCS#12 files are parsed. | - |
| Native libraries in archives | .so, .dll, .dylib and .jnilib files inside an archive are scanned as native artefacts. | as above |
The classes of a crypto provider itself (Bouncy Castle) are reported once, as a library, rather than as every algorithm the provider implements.
Confidence levels
Every finding carries the strongest confidence seen for that artefact and algorithm:
| Level | Meaning | Confidence score |
|---|---|---|
import | The artefact links a crypto library or uses a crypto API family. Which algorithm it uses is not established. | 0.5 |
symbol | The artefact references an algorithm-specific function, class or type. | 0.7 |
constant | The artefact embeds a constant naming the algorithm: OID, algorithm identifier, Java transformation string, signature block or library version string. | 0.9 |
Findings and CBOM
- One finding per artefact and algorithm, and per artefact and library, with up to eight lines of evidence (for example
[symbol] imports RSA_new from libcrypto.so.3, or[constant] com/acme/Signer passes "SHA1withRSA"). - The location is the artefact path; members of an archive are shown with
!/, for exampleapp.war!/WEB-INF/lib/legacy.jar. - Algorithm, library, confidence and evidence feed the CycloneDX CBOM exactly like source-code findings.
- Risk: RSA, ECC, DH, DSA, Ed25519 and X25519 are quantum-vulnerable (High at
symbolorconstant, Medium atimport); MD5, SHA-1, DES, 3DES, RC4 and RC2 are reported as classically weak (Medium); ML-KEM, ML-DSA and SLH-DSA as quantum-safe (Info); AES, SHA-2 and ChaCha20 as Low; a library seen without a specific algorithm as Info.
How to run
| Where | How |
|---|---|
| Cockpit UI | In PQC Readiness, create a new scan and choose Binaries & Artefacts, then upload one file (up to 24 MiB). |
| Scanner agent | The binary command scans a file or a whole directory on the machine that holds the files. |
| Filesystem scan | Add --binaries to the agent's filesystem command to examine compiled artefacts during the certificate and keystore sweep. |
| Container image scans | Automatic: every Docker, OCI registry and Harbor image scan also runs the binary scan over the image file system. Results appear per container under Crypto in compiled artefacts and in the JSON report. |
| REST API | POST /api/pqc/scans with scan_type: "binary", the file in options.artifact_data (base64) and its name in options.artifact_name. Up to 24 MiB. |
# One file or a whole directory
dke-scanner-agent binary ./dist --format summary
dke-scanner-agent binary /opt/app/app.war --output app-binary.json
# Certificate and keystore sweep plus compiled artefacts
dke-scanner-agent filesystem --path /opt/app --binaries| Agent option (binary) | Description | Default |
|---|---|---|
<path> | File or directory to scan | - |
--max-depth <N> | Maximum directory depth (0 = unlimited) | 12 |
--exclude <LIST> | Comma-separated path substrings to skip | .git,node_modules |
--max-file-mb <MiB> | Largest file read | 128 |
--timeout <SECS> | Time budget for the whole scan | 300 |
--format <FMT> | json or summary | json |
-o, --output <FILE> | Write to a file instead of standard output | - |
The Cockpit never reads a path on its own host for this scan: over the UI and the API the artefact is always an upload, as for packet captures. Larger artefacts and whole directories go through the scanner agent, which runs on the machine that holds the files.
Safety caps
Every limit is enforced. A limit that is hit is recorded as a note on the scan, so a partial result shows as partial.
| Limit | Scanner agent | Cockpit upload |
|---|---|---|
| File read from disk | 128 MiB (--max-file-mb) | 24 MiB (upload cap) |
| Decompressed size of one archive entry | 32 MiB | 32 MiB |
| Uncompressed bytes per top-level archive (nested included) | 512 MiB | 256 MiB |
| Entries per top-level archive (nested included) | 50,000 | 30,000 |
| Archive nesting depth | 3 | 3 |
| Compression ratio per entry | 100:1 (above: refused as a decompression bomb) | same |
| Files examined per directory walk | 20,000 | n/a |
| Symbols per native object | 500,000 | same |
| Total time | 300 s (--timeout) | 120 s |
The declared size of an archive entry is checked before reading and the actual read is capped too, so an entry that lies about its size cannot grow past the limit. Directory walks never follow symbolic links.
Limits
The scan shows what an artefact links, references or embeds. It does not trace which code paths call which algorithm at run time.
| Limit | Details |
|---|---|
| Stripped, statically linked binaries | Without a symbol table, a statically linked library is found only through its version string and its compiled-in OID table. Both show that the library is present and what it can do, not which algorithms the program calls. A crypto library's own OID table lists every algorithm it supports, so constant-level evidence from a crypto library means capability, not use. |
| Obfuscated, packed or encrypted code | Packed executables (for example UPX), Java string encryption (ProGuard / R8), .NET obfuscators and native packers hide symbols and constants. The scanner reports what is visible and does not unpack. |
| .NET depth | Only type names from the metadata are read. Method bodies (IL), user strings (such as algorithm names passed as strings) and native imports declared with DllImport are not analysed. Native AOT and ReadyToRun images are treated as native code. |
| Java depth | String constants are attributed to the class that holds them, not to the call site. A value built at run time (concatenation, configuration file) is not seen. Kotlin and Scala are covered, because they compile to the same class format. |
| Dynamic loading | Libraries loaded at run time (dlopen, LoadLibrary, Java crypto providers chosen by configuration) leave no import entry. |
| Formats not covered | WebAssembly, Python bytecode, Go and Rust module metadata, static .a / .lib archives and firmware images. Go and Rust binaries are still analysed as ordinary ELF / PE / Mach-O. |
| Short OIDs | Ed25519 and X25519 OIDs are too short to match safely; these algorithms are found through symbols and names instead. |
| Cockpit uploads | One file of at most 24 MiB per scan. Use the scanner agent for larger artefacts and directories. |