Code Scanning

Cryptography Bill of Materials (CBOM)

Generate a CycloneDX 1.6 Cryptography Bill of Materials — an inventory of the cryptographic assets in your code — with xgrep sbom --cbom.

Cryptography Bill of Materials (CBOM)

xgrep sbom --cbom .
xgrep sbom --cbom -o cbom.json .

A Cryptography Bill of Materials (CBOM) is a machine-readable inventory of the cryptographic assets your code uses — algorithms, key material, and protocols — and the relationships between them. It answers a question a vulnerability scan does not: "what cryptography do we use, and where?" That inventory is the starting point for post-quantum-cryptography (PQC) migration and for cryptographic compliance and audit.

xgrep emits a CBOM in the CycloneDX 1.6 format, produced with the upstream CycloneDX Go library, so the output conforms to the official CycloneDX 1.6 schema and is consumable by the broader CycloneDX ecosystem (CBOMkit, CBOM viewers, PQC-migration tooling).

Inventory, not findings

A CBOM is fundamentally different from a vulnerability report. It is a complete inventory: strong, correctly-used cryptography (for example AES-256-GCM) is listed as an asset, not flagged as a problem. Each asset is enriched so you can tell the strong from the weak at a glance — see asset fields below.

Because of that, a CBOM is generated by the sbom command (it is a bill of materials, like the dependency SBOM), not by xgrep scan. Detection runs as its own rule category (cbom) that is off in a normal scan, so it never adds inventory noise to your findings — and your existing weak-crypto security rules (weak-cipher, weak-hash, insecure-TLS, …) keep reporting vulnerabilities in xgrep scan exactly as before.

Scope: crypto only

sbom --cbom and plain sbom produce two distinct bills of materials:

  • xgrep sbom — a Software BoM: your third-party dependencies.
  • xgrep sbom --cbom — a Cryptography BoM: the cryptographic assets in your source, and only those. It does not include software dependencies.

So --cbom selects the BOM type; it does not add crypto to the dependency SBOM. It always emits CycloneDX 1.6 JSON, and the dependency-SBOM flags (--format, --ref, --ecosystem, --direct-only) do not apply to it. Emitting a single combined document (dependencies and crypto assets together) is a planned enhancement.

What gets detected

Detection is language- and library-aware. The table below lists the libraries covered and the detected API surface per library:

LanguageLibraryDetected API surface
JavaJCA (javax.crypto / java.security)Cipher, MessageDigest, Mac, Signature, KeyGenerator, KeyPairGenerator, SecretKeyFactory, SSLContext, CertificateFactory
JavaBouncyCastle (lightweight API)Engines & digests (AESEngine, SHA256Digest, …), HMac
KotlinJCAas Java JCA
ScalaJCAas Java JCA
Pythonstdlib hashlib / hmacmd5/sha1/sha256/sha512, hashlib.new, pbkdf2_hmac, hmac
Pythonpyca/cryptography (hazmat)hashes.*, ciphers.algorithms.*, HMAC, RSA/EC/Ed25519/DSA keygen, PBKDF2HMAC/Scrypt/HKDF, x509 certificates
Gocrypto/* (stdlib)aes, des, rc4, md5, sha1, sha256, sha512, hmac, rsa, ecdsa, ed25519, x509/tls certificates
Gogolang.org/x/cryptosha3, chacha20poly1305, pbkdf2, hkdf, bcrypt, scrypt, argon2, blake2b, ripemd160
C#System.Security.Cryptography (.NET)hash Create/HashData, Aes/AesGcm/AesCcm/TripleDES/DES/RC2, RSA/ECDsa/ECDiffieHellman/DSA, HMAC*, Rfc2898DeriveBytes (PBKDF2), X509Certificate2
JavaScript / TypeScriptNode.js cryptocreateHash, createHmac, createCipheriv, generateKeyPair[Sync], pbkdf2, scrypt, hkdf, createSign
JavaScript / TypeScriptCryptoJS, bcrypt, argon2CryptoJS.AES/SHA256/MD5/HmacSHA256, bcrypt.hash, argon2.hash
RubyOpenSSL, Digest, bcryptOpenSSL::Cipher/Digest/HMAC/PKey (RSA/EC/DSA)/PKCS5, Digest::*, BCrypt
PHPopenssl_*, hash, sodium, password_hashopenssl_encrypt/openssl_pkey_new, hash/hash_hmac/hash_pbkdf2, sodium_*, password_hash (bcrypt/Argon2)
RustRustCrypto, ring, rsasha2/sha1/md-5/sha3, aes-gcm/aes, chacha20poly1305, des, hmac, hkdf, pbkdf2, argon2, bcrypt, rsa, ed25519-dalek, p256 ECDSA, x25519; ring digest/HMAC
SwiftCryptoKit, CommonCryptoSHA256/384/512, Insecure.MD5/SHA1, AES.GCM, ChaChaPoly, HMAC, HKDF, Curve25519, P256/384/521; CC_MD5/CC_SHA256/CCHmac
Dartcrypto, PointyCastlesha256/sha512/sha1/md5/Hmac; PointyCastle engines/digests, PBKDF2/scrypt derivators
Elixir:crypto, Comeonin:crypto hash/mac/crypto_one_time/generate_key; Bcrypt/Argon2/Pbkdf2
Erlangcryptocrypto:hash/mac/crypto_one_time/generate_key

Detected assets span symmetric and asymmetric ciphers, hashes, MACs, signatures, key-agreement schemes, KDFs, TLS, and X.509 certificates — all four CycloneDX asset types (algorithm, protocol, related-crypto-material, certificate). Coverage of additional languages and libraries is expanding. Because a CBOM's value depends on completeness, treat the absence of an asset as "not yet detected," not "no crypto."

xgrep also resolves constant references: when an algorithm is passed as an upper-case constant (e.g. Cipher.getInstance(ALGO) where static final String ALGO = "AES/GCM/NoPadding"), the constant is resolved to its string literal within the same file so the real algorithm is inventoried. A reference that cannot be resolved to a literal is dropped rather than recorded as an unnamed asset.

Output

The document is a CycloneDX 1.6 BOM whose components are cryptographic-asset entries. A single detected call becomes a fully-specified asset:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "metadata": {
    "timestamp": "2026-07-01T00:00:00Z",
    "component": { "type": "application", "bom-ref": "root:my-project", "name": "my-project" },
    "tools": { "components": [{ "type": "application", "name": "xgrep" }] },
  },
  "components": [
    {
      "type": "cryptographic-asset",
      "bom-ref": "crypto/algorithm/aes-128-gcm@2.16.840.1.101.3.4.1.6",
      "name": "AES-128-GCM",
      "cryptoProperties": {
        "assetType": "algorithm",
        "oid": "2.16.840.1.101.3.4.1.6",
        "algorithmProperties": {
          "primitive": "ae",
          "mode": "gcm",
          "parameterSetIdentifier": "128",
          "cryptoFunctions": ["encrypt", "decrypt", "tag"],
          "classicalSecurityLevel": 128,
          "nistQuantumSecurityLevel": 1,
        },
      },
      "evidence": {
        "occurrences": [
          {
            "location": "src/Crypto.java",
            "line": 12,
            "additionalContext": "javax.crypto.Cipher#getInstance",
          },
        ],
      },
    },
  ],
  "dependencies": [
    {
      "ref": "root:my-project",
      "dependsOn": ["crypto/algorithm/aes-128-gcm@2.16.840.1.101.3.4.1.6"],
    },
  ],
}

Understanding an asset

  • assetTypealgorithm, related-crypto-material, protocol, or certificate.
  • primitive — the algorithm's role: block-cipher, stream-cipher, ae (authenticated encryption), hash, mac, signature, pke, key-agree, kdf, …
  • oid — the algorithm's object identifier, when known.
  • parameterSetIdentifier — key or digest size (e.g. 128, 256).
  • mode / padding — for ciphers (e.g. gcm, cbc; pkcs5, oaep).
  • classicalSecurityLevel — security strength in bits against classical attacks.
  • nistQuantumSecurityLevel — NIST post-quantum category 05. 0 means quantum-vulnerable — the field to scan for when planning PQC migration (RSA/ECDSA/DH are 0; broken primitives like MD5/SHA-1 are also 0).
  • evidence.occurrences — every source location (file, line) and the detected API that produced the asset.

The dependency graph

Assets are cross-linked in the CycloneDX dependencies graph. The scanned application depends on each detected asset, and composite algorithms are decomposed into their parts — for example HMAC-SHA256 dependsOn SHA-256, and SHA256withRSA dependsOn both SHA-256 and RSA. Identical assets seen at many call sites collapse to a single component that accumulates all occurrences.

Consuming the CBOM

Write the document to a file and hand it to any CycloneDX-aware tool:

xgrep sbom --cbom -o cbom.json .

For example, load it into a CBOM viewer, diff it across releases to track crypto drift, or feed it to PQC-readiness tooling that flags every nistQuantumSecurityLevel: 0 asset.

On this page