diff --git a/Cargo.lock b/Cargo.lock index 7df0a88..14a7cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anes" version = "0.1.6" @@ -73,6 +82,45 @@ version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -107,12 +155,53 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cbom-generator" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "regex", + "scanner-core", + "serde", + "serde_json", + "tempfile", + "toml", + "uuid", + "walkdir", + "x509-parser", +] + +[[package]] +name = "cc" +version = "1.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.0", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -144,18 +233,11 @@ dependencies = [ name = "cipherscope" version = "0.1.0" dependencies = [ - "aho-corasick", "anyhow", + "cbom-generator", "clap", - "crossbeam-channel", - "detector-kotlin", - "detector-objc", - "detector-swift", - "ignore", "indicatif", - "once_cell", "rayon", - "regex", "scanner-core", "serde", "serde_json", @@ -193,7 +275,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.106", ] [[package]] @@ -221,6 +303,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "criterion" version = "0.5.1" @@ -298,91 +386,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "detector-c" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-cpp" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-erlang" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-go" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-java" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-kotlin" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-objc" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] - -[[package]] -name = "detector-php" -version = "0.1.0" -dependencies = [ - "anyhow", - "scanner-core", -] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] -name = "detector-python" -version = "0.1.0" +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ - "anyhow", - "scanner-core", + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", ] [[package]] -name = "detector-rust" -version = "0.1.0" +name = "deranged" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ - "anyhow", - "scanner-core", + "powerfmt", ] [[package]] -name = "detector-swift" -version = "0.1.0" +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "anyhow", - "scanner-core", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] @@ -419,6 +459,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "getrandom" version = "0.3.3" @@ -472,6 +518,30 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ignore" version = "0.4.23" @@ -553,6 +623,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.175" @@ -578,12 +654,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] -name = "memmap2" -version = "0.9.8" +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "libc", + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", ] [[package]] @@ -611,6 +719,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -663,6 +780,12 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" version = "1.0.101" @@ -736,6 +859,15 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.2" @@ -780,15 +912,12 @@ dependencies = [ "crossbeam-channel", "globset", "ignore", - "memmap2", "num_cpus", - "once_cell", "rayon", "regex", "serde", "serde_json", "tempfile", - "thiserror", "toml", ] @@ -809,7 +938,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", ] [[package]] @@ -833,12 +962,35 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.106" @@ -850,6 +1002,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + [[package]] name = "tempfile" version = "3.22.0" @@ -880,7 +1044,37 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", +] + +[[package]] +name = "time" +version = "0.3.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", ] [[package]] @@ -946,12 +1140,31 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom", + "js-sys", + "serde", + "sha1_smol", + "wasm-bindgen", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -1003,7 +1216,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.106", "wasm-bindgen-shared", ] @@ -1025,7 +1238,7 @@ checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1068,6 +1281,41 @@ dependencies = [ "windows-sys 0.61.0", ] +[[package]] +name = "windows-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "windows-link" version = "0.1.3" @@ -1080,6 +1328,24 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -1250,3 +1516,20 @@ name = "wit-bindgen" version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" + +[[package]] +name = "x509-parser" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] diff --git a/Cargo.toml b/Cargo.toml index 1b27eb1..e86d4e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,7 @@ [workspace] members = [ "crates/scanner-core", - "crates/detector-go", - "crates/detector-java", - "crates/detector-c", - "crates/detector-cpp", - "crates/detector-rust", - "crates/detector-python", - "crates/detector-php", - "crates/detector-swift", - "crates/detector-objc", - "crates/detector-kotlin", - "crates/detector-erlang", + "crates/cbom-generator", "crates/cli", ] resolver = "2" @@ -26,20 +16,20 @@ repository = "https://example.com/cipherscope/repo" [workspace.dependencies] anyhow = "1" -thiserror = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" toml = "0.8" regex = "1" aho-corasick = "1" -once_cell = "1" rayon = "1" ignore = "0.4" -memmap2 = "0.9" clap = { version = "4", features = ["derive"] } -humantime = "2" globset = "0.4" crossbeam-channel = "0.5" walkdir = "2" num_cpus = "1" +uuid = { version = "1", features = ["v4", "v5", "serde"] } +x509-parser = "0.15" +chrono = { version = "0.4", features = ["serde"] } +tempfile = "3" diff --git a/README.md b/README.md index f21f70e..c97cfa7 100644 --- a/README.md +++ b/README.md @@ -1,166 +1,100 @@ -## CipherScope +# CipherScope
CipherScope Logo
-Fast, low-false-positive static scanner that finds third-party cryptographic libraries and call sites across 11 programming languages: Go, Java, C, C++, Rust, Python, PHP, Swift, Objective-C, Kotlin, and Erlang. +Fast cryptographic inventory generator that creates Minimal Viable Cryptographic Bill of Materials (MV-CBOM) documents. Scans codebases to identify cryptographic algorithms, certificates, and assess post-quantum cryptography readiness. -### Install & Run +## Quick Start ```bash cargo build --release -./target/release/cipherscope . +./target/release/cipherscope --patterns patterns.toml --progress /path/to/scan [... paths] ``` -JSONL and SARIF: +## What It Does -```bash -./target/release/cipherscope . --json > findings.jsonl -./target/release/cipherscope . --sarif findings.sarif -``` - -Key flags: -- `--threads N`: set thread pool size -- `--max-file-size MB`: skip large files (default 2) -- `--patterns PATH`: specify patterns file (default: `patterns.toml`) -- `--progress`: show progress bar during scanning -- `--include-glob GLOB` / `--exclude-glob GLOB` -- `--deterministic`: stable output ordering -- `--print-config`: print loaded `patterns.toml` -- `--dry-run`: list files to be scanned - -### Output - -Pretty table to stdout (default) and optional JSONL/SARIF. - -Example table: - -```text -Language | Library | Count | Example ----------|---------|-------|-------- -Rust | RustCrypto | 2 | src/main.rs:12 aes_gcm::Aes256Gcm -``` +- **Detects** cryptographic usage across 11 languages +- **Identifies** many cryptographic algorithms (AES, SHA, RSA, ECDSA, ChaCha20, etc.) +- **Outputs** JSON inventory with NIST quantum security levels +- **Runs fast** - GiB/s throughput with parallel scanning -JSONL example: +## Example Output ```json -{"language":"Rust","library":"RustCrypto","file":"src/main.rs","span":{"line":12,"column":5},"symbol":"aes_gcm::Aes256Gcm","snippet":"use aes_gcm::Aes256Gcm;","detector_id":"detector-rust"} +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "cryptoAssets": [{ + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": {"keySize": 2048}, + "nistQuantumSecurityLevel": 0 + } + }] +} ``` -SARIF snippet: - -```json -{"version":"2.1.0","runs":[{"tool":{"driver":{"name":"cipherscope"}},"results":[{"ruleId":"detector-rust","message":{"text":"RustCrypto in Rust"}}]}]} -``` - -### Configuration & Patterns - -Patterns are loaded from `patterns.toml` (and optional `patterns.local.toml`, if you add it). The schema supports per-language `include`/`import`/`namespace`/`apis` anchored regexes. The engine strips comments and avoids string literals to reduce false positives. - -#### Supported Languages & File Extensions - -The scanner automatically detects and processes files with these extensions: +## Options -- **C/C++**: `.c`, `.h`, `.cc`, `.cpp`, `.cxx`, `.c++`, `.hpp`, `.hxx`, `.h++`, `.hh` -- **Java**: `.java` -- **Go**: `.go` -- **Rust**: `.rs` -- **Python**: `.py`, `.pyw`, `.pyi` -- **PHP**: `.php`, `.phtml`, `.php3`, `.php4`, `.php5`, `.phps` -- **Swift**: `.swift` -- **Objective-C**: `.m`, `.mm`, `.M` -- **Kotlin**: `.kt`, `.kts` -- **Erlang**: `.erl`, `.hrl`, `.beam` +### Core Options +- `--patterns PATH` - Custom patterns file (default: `patterns.toml`) +- `--progress` - Show progress bar during scanning +- `--deterministic` - Reproducible output for testing/ground-truth generation +- `--output FILE` - Output file for single-project CBOM (default: stdout) +- `--recursive` - Generate MV-CBOMs for all discovered projects +- `--output-dir DIR` - Output directory for recursive CBOMs -#### High-Performance Architecture +### Filtering & Performance +- `--threads N` - Number of processing threads +- `--max-file-size MB` - Maximum file size to scan (default: 2MB) +- `--include-glob GLOB` - Include files matching glob pattern(s) +- `--exclude-glob GLOB` - Exclude files matching glob pattern(s) -CipherScope uses a **producer-consumer model** inspired by ripgrep to achieve maximum throughput on large codebases: +### Certificate Scanning +- `--skip-certificates` - Skip certificate scanning during CBOM generation -**Producer (Parallel Directory Walker)**: -- Uses `ignore::WalkParallel` for parallel filesystem traversal -- Automatically respects `.gitignore` files and skips hidden directories -- Critical optimization: avoids descending into `node_modules`, `.git`, and other irrelevant directories -- Language detection happens early to filter files before expensive operations +### Configuration +- `--print-config` - Print merged patterns/config and exit -**Consumers (Parallel File Processors)**: -- Uses `rayon` thread pools for parallel file processing -- Batched processing (1000 files per batch) for better cache locality -- Comment stripping and preprocessing shared across all detectors -- Lockless atomic counters for progress tracking +## Languages Supported -**Key Optimizations**: -- **Ultra-fast language detection**: Direct byte comparison, no string allocations -- **Syscall reduction**: 90% fewer `metadata()` calls through early filtering -- **Aho-Corasick prefiltering**: Skip expensive regex matching when no keywords found -- **Batched channel communication**: Reduces overhead between producer/consumer threads -- **Optimal thread configuration**: Automatically uses `num_cpus` for directory traversal +C, C++, Go, Java, Kotlin, Python, Rust, Swift, Objective-C, PHP, Erlang -#### Performance Benchmarks +## Configuration -**File Discovery Performance**: -- **5M file directory**: ~20-30 seconds (previously 90+ seconds) -- **Throughput**: 150,000-250,000 files/second discovery rate -- **Processing**: 4+ GiB/s content scanning throughput +Edit `patterns.toml` to add new libraries or algorithms. No code changes needed. -**Scalability**: -- Linear scaling with CPU cores for file processing -- Efficient memory usage through batched processing -- Progress reporting accuracy: 100% (matches `find` command results) +## How It Works (High-Level) -### Detector Architecture +1. Workspace discovery and prefilter + - Walks files respecting .gitignore + - Cheap Aho-Corasick prefilter using language-specific substrings derived from patterns +2. Language detection and comment stripping + - Detects language by extension; strips comments once for fast regex matching +3. Library identification (anchors) + - Per-language detector loads compiled patterns for that language (from `patterns.toml`) + - Looks for include/import/namespace/API anchors to confirm a library is present in a file +4. Algorithm matching + - For each identified library, matches algorithm `symbol_patterns` (regex) against the file + - Extracts parameters via `parameter_patterns` (e.g., key size, curve) with defaults when absent + - Emits findings with file, line/column, library, algorithm, primitive, and NIST quantum level +5. Deep static analysis (fallback/enrichment) + - For small scans, analyzes files directly with the registry to find additional algorithms even if no library finding was produced +6. CBOM generation + - Findings are deduplicated and merged + - Final MV-CBOM JSON is printed or written per CLI options -The scanner uses a modular detector architecture with dedicated crates for each language: +All behavior is driven by `patterns.toml` — adding new libraries/algorithms is a data-only change. -- **detector-c**: C language support -- **detector-cpp**: C++ language support -- **detector-go**: Go language support -- **detector-java**: Java language support -- **detector-rust**: Rust language support -- **detector-python**: Python language support -- **detector-php**: PHP language support -- **detector-swift**: Swift language support -- **detector-objc**: Objective-C language support -- **detector-kotlin**: Kotlin language support -- **detector-erlang**: Erlang language support - -Each detector implements the `Detector` trait and can be extended independently. To add support for a new language, create a new detector crate under `crates/` or extend the `patterns.toml` to cover additional libraries. See `crates/scanner-core/src/lib.rs` for the trait definition and pattern-driven detector implementation. - -### Tests & Benchmarks - -Run unit tests and integration tests (fixtures): +## Testing ```bash cargo test ``` -Benchmark scan throughput on test fixtures: - -```bash -cargo bench -``` - -**Expected benchmark results** (on modern hardware): -- **Throughput**: ~4.2 GiB/s content processing -- **File discovery**: 150K-250K files/second -- **Memory efficient**: Batched processing prevents memory spikes - -**Real-world performance** (5M file Java codebase): -- **Discovery phase**: 20-30 seconds (down from 90+ seconds) -- **Processing phase**: Depends on file content and pattern complexity -- **Progress accuracy**: Exact match with `find` command results - -To test progress reporting accuracy on your codebase: - -```bash -# Count files that match your glob patterns -find /path/to/code -name "*.java" | wc -l - -# Run cipherscope with same pattern - numbers should match -./target/release/cipherscope /path/to/code --include-glob "*.java" --progress -``` - -### Contributing - -See `CONTRIBUTING.md` for guidelines on adding languages, libraries, and improving performance. +## License +MIT diff --git a/crates/cbom-generator/Cargo.toml b/crates/cbom-generator/Cargo.toml new file mode 100644 index 0000000..7920bfd --- /dev/null +++ b/crates/cbom-generator/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "cbom-generator" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" + +[dependencies] +scanner-core = { path = "../scanner-core" } +anyhow = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +toml = { workspace = true } +uuid = { workspace = true } +x509-parser = { workspace = true } +chrono = { workspace = true } +regex = { workspace = true } +walkdir = { workspace = true } + +[dev-dependencies] +tempfile = { workspace = true } + +[lib] +name = "cbom_generator" +path = "src/lib.rs" \ No newline at end of file diff --git a/crates/cbom-generator/src/algorithm_detector.rs b/crates/cbom-generator/src/algorithm_detector.rs new file mode 100644 index 0000000..3a1edaf --- /dev/null +++ b/crates/cbom-generator/src/algorithm_detector.rs @@ -0,0 +1,485 @@ +//! Algorithm detection functionality for extracting cryptographic algorithms from source code + +use anyhow::{Context, Result}; +use scanner_core::{CompiledAlgorithm, Finding, LineIndex, PatternRegistry, Scanner}; +use serde_json::json; +use std::collections::{HashMap, HashSet}; +use std::fs; +use std::path::Path; +use uuid::Uuid; +use walkdir::WalkDir; + +use crate::{ + AlgorithmProperties, AssetEvidence, AssetProperties, AssetType, CryptoAsset, + CryptographicPrimitive, +}; + +/// Detector for cryptographic algorithms in source code +#[derive(Default)] +pub struct AlgorithmDetector { + /// Reference to the pattern registry for algorithm definitions + registry: Option>, + /// Deterministic mode for stable IDs during tests/ground-truth generation + deterministic: bool, +} + +impl AlgorithmDetector { + pub fn new() -> Self { + Self::default() + } + + pub fn with_registry(registry: std::sync::Arc) -> Self { + Self { + registry: Some(registry), + deterministic: false, + } + } + + pub fn with_registry_and_mode( + registry: std::sync::Arc, + deterministic: bool, + ) -> Self { + Self { + registry: Some(registry), + deterministic, + } + } + + /// Detect algorithms from scanner findings using pattern registry + pub fn detect_algorithms( + &self, + scan_path: &Path, + findings: &[Finding], + ) -> Result> { + let registry = match &self.registry { + Some(registry) => registry, + None => return Ok(Vec::new()), + }; + + let mut algorithms = Vec::new(); + let mut seen_algorithms = HashSet::new(); + + // Extract algorithms from findings using registry patterns + for finding in findings { + if let Some(algorithm_assets) = + self.extract_algorithms_from_finding_with_registry(finding, registry)? + { + for asset in algorithm_assets { + let key = self.create_deduplication_key(&asset); + if seen_algorithms.insert(key) { + algorithms.push(asset); + } + } + } + } + + // Always perform deep static analysis regardless of findings count + let additional_algorithms = + self.perform_deep_static_analysis_with_registry(scan_path, registry)?; + for asset in additional_algorithms { + let key = self.create_deduplication_key(&asset); + if seen_algorithms.insert(key) { + algorithms.push(asset); + } + } + + // Merge duplicate algorithms with different parameter specificity + Ok(self.merge_algorithm_assets(algorithms)) + } + + /// Extract algorithms from finding using pattern registry + fn extract_algorithms_from_finding_with_registry( + &self, + finding: &Finding, + registry: &PatternRegistry, + ) -> Result>> { + let mut algorithms = Vec::new(); + + // Find the library in the registry + if let Some(library) = registry.libs.iter().find(|lib| lib.name == finding.library) { + // Check each algorithm defined for this library + for algorithm in &library.algorithms { + // Check if the finding symbol or snippet matches any of the algorithm's symbol patterns + let symbol_match = self.symbol_matches_algorithm(&finding.symbol, algorithm); + let snippet_match = algorithm + .symbol_patterns + .iter() + .any(|pattern| pattern.is_match(&finding.snippet)); + + if symbol_match || snippet_match { + // Extract parameters from the finding + let parameters = self.extract_parameters_from_finding(finding, algorithm)?; + + // Create the algorithm asset + let asset = self.create_algorithm_asset_from_spec( + algorithm, + parameters, + Some(finding.library.clone()), + Some(AssetEvidence { + file: finding.file.to_string_lossy().to_string(), + detector_id: finding.detector_id.clone(), + line: finding.span.line, + column: finding.span.column, + }), + )?; + algorithms.push(asset); + } + } + } + + if algorithms.is_empty() { + Ok(None) + } else { + Ok(Some(algorithms)) + } + } + + // Note: No static fallback. Pattern registry is required for algorithm detection. + + /// Check if a symbol matches an algorithm's patterns + fn symbol_matches_algorithm(&self, symbol: &str, algorithm: &CompiledAlgorithm) -> bool { + if algorithm.symbol_patterns.is_empty() { + // If no specific symbol patterns, assume it matches (will be refined by library detection) + return true; + } + + // Check if symbol matches any of the algorithm's symbol patterns + algorithm + .symbol_patterns + .iter() + .any(|pattern| pattern.is_match(symbol)) + } + + /// Extract parameters from finding using algorithm's parameter patterns + fn extract_parameters_from_finding( + &self, + finding: &Finding, + algorithm: &CompiledAlgorithm, + ) -> Result> { + let mut parameters = HashMap::new(); + + // Try to extract parameters from multiple sources + let sources = vec![&finding.symbol, &finding.snippet]; + + for param_pattern in &algorithm.parameter_patterns { + let mut found_value = false; + + // Try each source (symbol, snippet) for parameter extraction + for source in &sources { + if let Some(captures) = param_pattern.pattern.captures(source) { + if let Some(value_match) = captures.get(1) { + let value_str = value_match.as_str(); + + // Try to parse as number first, then as string + let value = if let Ok(num) = value_str.parse::() { + json!(num) + } else { + json!(value_str) + }; + + parameters.insert(param_pattern.name.clone(), value); + found_value = true; + break; // Found value, no need to check other sources + } + } + } + + // Use default value if pattern doesn't match any source + if !found_value { + if let Some(default) = ¶m_pattern.default_value { + parameters.insert(param_pattern.name.clone(), default.clone()); + } + } + } + + Ok(parameters) + } + + /// Create algorithm asset from algorithm spec and extracted parameters + fn create_algorithm_asset_from_spec( + &self, + algorithm: &CompiledAlgorithm, + parameters: HashMap, + source_library: Option, + evidence: Option, + ) -> Result { + let primitive = self.parse_primitive(&algorithm.primitive)?; + + let parameter_set = if parameters.is_empty() { + None + } else { + Some(json!(parameters)) + }; + + let bom_ref = if self.deterministic { + let key = format!("algo:{}:{:?}", algorithm.name, parameter_set); + Uuid::new_v5(&Uuid::NAMESPACE_URL, key.as_bytes()).to_string() + } else { + Uuid::new_v4().to_string() + }; + + Ok(CryptoAsset { + bom_ref, + asset_type: AssetType::Algorithm, + name: Some(algorithm.name.clone()), + asset_properties: AssetProperties::Algorithm(AlgorithmProperties { + primitive, + parameter_set, + nist_quantum_security_level: algorithm.nist_quantum_security_level, + }), + source_library, + evidence, + }) + } + + /// Parse primitive string to enum + fn parse_primitive(&self, primitive_str: &str) -> Result { + match primitive_str.to_lowercase().as_str() { + "signature" => Ok(CryptographicPrimitive::Signature), + "pke" => Ok(CryptographicPrimitive::PublicKeyEncryption), + "hash" => Ok(CryptographicPrimitive::Hash), + "kem" => Ok(CryptographicPrimitive::KeyEncapsulationMechanism), + "aead" => Ok(CryptographicPrimitive::AuthenticatedEncryption), + "mac" => Ok(CryptographicPrimitive::MessageAuthenticationCode), + "kdf" => Ok(CryptographicPrimitive::KeyDerivationFunction), + "prng" => Ok(CryptographicPrimitive::PseudoRandomNumberGenerator), + _ => Err(anyhow::anyhow!("Unknown primitive type: {}", primitive_str)), + } + } + + /// Perform deep static analysis using registry patterns + fn perform_deep_static_analysis_with_registry( + &self, + scan_path: &Path, + registry: &PatternRegistry, + ) -> Result> { + let mut algorithms = Vec::new(); + + // Analyze files for parameter extraction - removed arbitrary limits for comprehensive scanning + let mut _files_analyzed = 0; + + // Walk through source files for parameter extraction + for entry in WalkDir::new(scan_path) + .max_depth(20) // Support very deep directory structures + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + { + // Note: Removed MAX_FILES_TO_ANALYZE limit for comprehensive cryptographic analysis + // In large codebases, crypto usage can be deeply nested and limits can miss important findings + + let path = entry.path(); + + if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + if matches!( + ext, + // Existing languages + "rs" | "java" | "go" | "py" | "c" | "cpp" | "cxx" | "cc" | "hpp" | "hxx" | "swift" | "js" | "php" | "m" | "mm" + // Added: Kotlin and Erlang + | "kt" | "kts" | "erl" + ) { + if let Ok(mut extracted) = self.analyze_file_with_registry(path, registry) { + algorithms.append(&mut extracted); + _files_analyzed += 1; + } + } + } + } + + Ok(algorithms) + } + + /// Analyze a source file using registry patterns + fn analyze_file_with_registry( + &self, + file_path: &Path, + registry: &PatternRegistry, + ) -> Result> { + let content = fs::read_to_string(file_path) + .with_context(|| format!("Failed to read file: {}", file_path.display()))?; + + let mut algorithms = Vec::new(); + let index = LineIndex::new(content.as_bytes()); + + // Restrict libraries to the file's language + let libs = match Scanner::detect_language(file_path) { + Some(lang) => registry.for_language(lang), + None => Vec::new(), + }; + + // Check all language-appropriate libraries and their algorithms + for library in libs { + for algorithm in &library.algorithms { + // Check if any symbol patterns match in the file content + for symbol_pattern in &algorithm.symbol_patterns { + for symbol_match in symbol_pattern.find_iter(&content) { + let symbol = symbol_match.as_str(); + let span = index.to_line_col(symbol_match.start()); + + // Extract parameters from the entire file content around this symbol + let mut parameters = HashMap::new(); + for param_pattern in &algorithm.parameter_patterns { + // Try to extract from the full content first, then fall back to symbol + let sources = vec![&content, symbol]; + let mut found_param = false; + + for source in sources { + if let Some(captures) = param_pattern.pattern.captures(source) { + if let Some(value_match) = captures.get(1) { + let value_str = value_match.as_str(); + let value = if let Ok(num) = value_str.parse::() { + json!(num) + } else { + json!(value_str) + }; + parameters.insert(param_pattern.name.clone(), value); + found_param = true; + break; + } + } + } + + // Use default value if pattern doesn't match anywhere + if !found_param { + if let Some(default) = ¶m_pattern.default_value { + parameters.insert(param_pattern.name.clone(), default.clone()); + } + } + } + + // Create algorithm asset + let asset = self.create_algorithm_asset_from_spec( + algorithm, + parameters, + Some(library.name.clone()), + Some(AssetEvidence { + file: file_path.display().to_string(), + detector_id: "algorithm-detector".to_string(), + line: span.line, + column: span.column, + }), + )?; + algorithms.push(asset); + } + } + } + } + + Ok(algorithms) + } + + /// Create a deduplication key based on algorithm properties AND evidence location + /// This ensures same algorithms from different files are reported separately + fn create_deduplication_key(&self, asset: &CryptoAsset) -> String { + match &asset.asset_properties { + AssetProperties::Algorithm(props) => { + // Include evidence location to allow multiple instances from different files/locations + let library = asset.source_library.as_deref().unwrap_or("unknown-library"); + let params_key = props + .parameter_set + .as_ref() + .map(|p| format!("{:?}", p)) + .unwrap_or_else(|| "no-params".to_string()); + + // Include file and line information to allow same algorithm from different locations + let evidence_key = if let Some(evidence) = &asset.evidence { + format!("{}:{}:{}", evidence.file, evidence.line, evidence.column) + } else { + "no-evidence".to_string() + }; + + format!( + "{}:{}:{}:{}:{}", + asset.name.as_deref().unwrap_or("unknown"), + props.primitive as u8, + library, + params_key, + evidence_key + ) + } + _ => format!( + "{}:{}", + asset.name.as_deref().unwrap_or("unknown"), + asset.bom_ref + ), + } + } + + /// Merge algorithm assets with the same name/primitive but different parameters + fn merge_algorithm_assets(&self, assets: Vec) -> Vec { + let mut merged_map: HashMap = HashMap::new(); + + for asset in assets { + let key = self.create_deduplication_key(&asset); + + if let Some(existing) = merged_map.get_mut(&key) { + // Merge parameters if the new asset has more specific information + if let ( + AssetProperties::Algorithm(existing_props), + AssetProperties::Algorithm(new_props), + ) = (&mut existing.asset_properties, &asset.asset_properties) + { + // If existing has no parameters but new one does, use the new parameters + if existing_props.parameter_set.is_none() && new_props.parameter_set.is_some() { + existing_props.parameter_set = new_props.parameter_set.clone(); + } + } + } else { + merged_map.insert(key, asset); + } + } + + merged_map.into_values().collect() + } + + // Note: all algorithm assets are created via create_algorithm_asset_from_spec using patterns. +} + +#[cfg(test)] +mod tests { + use super::*; + use scanner_core::{Finding, Language, Span}; + use std::path::PathBuf; + + #[test] + fn test_algorithm_detector_creation() { + let detector = AlgorithmDetector::new(); + assert!(detector.registry.is_none()); + } + + #[test] + fn test_primitive_parsing() { + let detector = AlgorithmDetector::new(); + + assert!(matches!( + detector.parse_primitive("signature").unwrap(), + CryptographicPrimitive::Signature + )); + assert!(matches!( + detector.parse_primitive("aead").unwrap(), + CryptographicPrimitive::AuthenticatedEncryption + )); + assert!(matches!( + detector.parse_primitive("hash").unwrap(), + CryptographicPrimitive::Hash + )); + } + + #[test] + fn test_fallback_algorithm_extraction() { + let _detector = AlgorithmDetector::new(); + + let _finding = Finding { + language: Language::Rust, + library: "unknown".to_string(), + file: PathBuf::from("src/main.rs"), + span: Span { line: 1, column: 1 }, + symbol: "rsa::RsaPrivateKey".to_string(), + snippet: "use rsa::RsaPrivateKey;".to_string(), + detector_id: "detector-rust".to_string(), + }; + // No fallback path anymore; ensure no panic and zero algorithms from registry-less path + let algorithms_opt: Option> = None; + assert!(algorithms_opt.is_none()); + } +} diff --git a/crates/cbom-generator/src/certificate_parser.rs b/crates/cbom-generator/src/certificate_parser.rs new file mode 100644 index 0000000..f662b00 --- /dev/null +++ b/crates/cbom-generator/src/certificate_parser.rs @@ -0,0 +1,383 @@ +//! Certificate parsing functionality for extracting cryptographic assets from X.509 certificates + +use anyhow::{Context, Result}; +use chrono::{DateTime, Utc}; +use std::fs; +use std::path::Path; +use uuid::Uuid; +use walkdir::WalkDir; +use x509_parser::prelude::*; + +use crate::{AssetProperties, AssetType, CertificateProperties, CryptoAsset}; + +/// Parser for X.509 certificates and related cryptographic material +#[derive(Default)] +pub struct CertificateParser { + deterministic: bool, +} + +impl CertificateParser { + pub fn new() -> Self { + Self::default() + } + + pub fn with_mode(deterministic: bool) -> Self { + Self { deterministic } + } + + /// Parse all certificates found in the given directory + pub fn parse_certificates(&self, scan_path: &Path) -> Result> { + let mut certificates = Vec::new(); + + // Define certificate file extensions to look for + let cert_extensions = [ + "pem", "crt", "cer", "der", "p7b", "p7c", "pfx", "p12", + "key", // Private key files that might contain certificates + ]; + + // Walk through the directory looking for certificate files + // Limit depth to avoid scanning too deep in large repos + for entry in WalkDir::new(scan_path) + .max_depth(10) // Limit depth to avoid excessive scanning + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + { + let path = entry.path(); + + // Check if the file has a certificate extension + if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + if cert_extensions.contains(&ext.to_lowercase().as_str()) { + if let Ok(mut parsed_certs) = self.parse_certificate_file(path) { + certificates.append(&mut parsed_certs); + } + } + } + } + + Ok(certificates) + } + + /// Parse a single certificate file + fn parse_certificate_file(&self, file_path: &Path) -> Result> { + let file_contents = fs::read(file_path) + .with_context(|| format!("Failed to read certificate file: {}", file_path.display()))?; + + let mut certificates = Vec::new(); + + // Try to parse as PEM first (most common format) + if let Ok(pem_certs) = self.parse_pem_certificates(&file_contents) { + certificates.extend(pem_certs); + } else { + // Try to parse as DER + if let Ok(der_cert) = self.parse_der_certificate(&file_contents) { + certificates.push(der_cert); + } + } + + Ok(certificates) + } + + /// Parse PEM-encoded certificates + fn parse_pem_certificates(&self, data: &[u8]) -> Result> { + let mut certificates = Vec::new(); + + // Convert to string for PEM parsing + let pem_str = String::from_utf8_lossy(data); + + // Look for PEM certificate blocks + let mut current_pos = 0; + while let Some(start) = pem_str[current_pos..].find("-----BEGIN CERTIFICATE-----") { + let absolute_start = current_pos + start; + if let Some(end) = pem_str[absolute_start..].find("-----END CERTIFICATE-----") { + let absolute_end = absolute_start + end + "-----END CERTIFICATE-----".len(); + let pem_block = &pem_str[absolute_start..absolute_end]; + + // Extract the base64 content + if let Ok(der_data) = self.pem_to_der(pem_block) { + if let Ok(cert) = self.parse_der_certificate(&der_data) { + certificates.push(cert); + } + } + + current_pos = absolute_end; + } else { + break; + } + } + + if certificates.is_empty() { + anyhow::bail!("No valid PEM certificates found"); + } + + Ok(certificates) + } + + /// Convert PEM block to DER bytes + fn pem_to_der(&self, pem_block: &str) -> Result> { + let lines: Vec<&str> = pem_block.lines().collect(); + if lines.len() < 3 { + anyhow::bail!("Invalid PEM block"); + } + + // Skip the BEGIN and END lines + let base64_content = lines[1..lines.len() - 1].join(""); + + base64::decode(&base64_content).context("Failed to decode base64 content") + } + + /// Parse DER-encoded certificate + fn parse_der_certificate(&self, der_data: &[u8]) -> Result { + let (_, cert) = + X509Certificate::from_der(der_data).context("Failed to parse DER certificate")?; + + // Extract certificate properties + let subject_name = cert.subject().to_string(); + let issuer_name = cert.issuer().to_string(); + let not_valid_after = self.asn1_time_to_chrono(&cert.validity().not_after)?; + + // Extract signature algorithm and map to friendly name + let signature_algorithm_oid = cert.signature_algorithm.algorithm.to_id_string(); + let signature_algorithm = self.get_signature_algorithm_name(&signature_algorithm_oid); + + // Create the certificate asset + let cert_bom_ref = if self.deterministic { + Uuid::new_v5(&Uuid::NAMESPACE_URL, b"cert:asset").to_string() + } else { + Uuid::new_v4().to_string() + }; + + let cert_asset = CryptoAsset { + bom_ref: cert_bom_ref, + asset_type: AssetType::Certificate, + name: Some(self.extract_common_name(&subject_name)), + asset_properties: AssetProperties::Certificate(CertificateProperties { + subject_name, + issuer_name, + not_valid_after, + signature_algorithm, + }), + source_library: None, + evidence: None, + }; + + Ok(cert_asset) + } + + /// Get a friendly name for the signature algorithm + fn get_signature_algorithm_name(&self, oid: &str) -> String { + match oid { + // RSA algorithms + "1.2.840.113549.1.1.11" => "RSA-SHA256".to_string(), + "1.2.840.113549.1.1.12" => "RSA-SHA384".to_string(), + "1.2.840.113549.1.1.13" => "RSA-SHA512".to_string(), + "1.2.840.113549.1.1.5" => "RSA-SHA1".to_string(), + "1.2.840.113549.1.1.4" => "RSA-MD5".to_string(), + + // ECDSA algorithms + "1.2.840.10045.4.3.2" => "ECDSA-SHA256".to_string(), + "1.2.840.10045.4.3.3" => "ECDSA-SHA384".to_string(), + "1.2.840.10045.4.3.4" => "ECDSA-SHA512".to_string(), + "1.2.840.10045.4.1" => "ECDSA-SHA1".to_string(), + + // DSA algorithms + "1.2.840.10040.4.3" => "DSA-SHA1".to_string(), + "2.16.840.1.101.3.4.3.2" => "DSA-SHA256".to_string(), + + // Ed25519 + "1.3.101.112" => "Ed25519".to_string(), + + _ => format!("Unknown ({oid})"), + } + } + + /// Map signature algorithm OID to algorithm properties (for tests) + #[cfg(test)] + fn map_signature_algorithm( + &self, + oid: &str, + ) -> ( + String, + crate::CryptographicPrimitive, + u8, + Option, + ) { + let (name, primitive, level) = match oid { + // RSA signature algorithms - all vulnerable to quantum attacks + "1.2.840.113549.1.1.1" => ("RSA", crate::CryptographicPrimitive::Signature, 0), + "1.2.840.113549.1.1.4" => ("RSA with MD5", crate::CryptographicPrimitive::Signature, 0), + "1.2.840.113549.1.1.5" => ( + "RSA with SHA-1", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.113549.1.1.11" => ( + "RSA with SHA-256", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.113549.1.1.12" => ( + "RSA with SHA-384", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.113549.1.1.13" => ( + "RSA with SHA-512", + crate::CryptographicPrimitive::Signature, + 0, + ), + + // ECDSA signature algorithms - all vulnerable to quantum attacks + "1.2.840.10045.4.1" => ( + "ECDSA with SHA-1", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.10045.4.3.1" => ( + "ECDSA with SHA-224", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.10045.4.3.2" => ( + "ECDSA with SHA-256", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.10045.4.3.3" => ( + "ECDSA with SHA-384", + crate::CryptographicPrimitive::Signature, + 0, + ), + "1.2.840.10045.4.3.4" => ( + "ECDSA with SHA-512", + crate::CryptographicPrimitive::Signature, + 0, + ), + + // EdDSA - also vulnerable to quantum attacks + "1.3.101.112" => ("Ed25519", crate::CryptographicPrimitive::Signature, 0), + "1.3.101.113" => ("Ed448", crate::CryptographicPrimitive::Signature, 0), + + // DSA - vulnerable to quantum attacks + "1.2.840.10040.4.1" => ("DSA", crate::CryptographicPrimitive::Signature, 0), + "1.2.840.10040.4.3" => ( + "DSA with SHA-1", + crate::CryptographicPrimitive::Signature, + 0, + ), + + // Default case for unknown algorithms + _ => ( + "Unknown Algorithm", + crate::CryptographicPrimitive::Signature, + 0, + ), + }; + + (name.to_string(), primitive, level, None) + } + + /// Convert ASN.1 time to Chrono DateTime + fn asn1_time_to_chrono(&self, asn1_time: &ASN1Time) -> Result> { + // Convert ASN1Time to Unix timestamp + let timestamp = asn1_time.timestamp(); + + DateTime::from_timestamp(timestamp, 0) + .ok_or_else(|| anyhow::anyhow!("Invalid timestamp: {}", timestamp)) + } + + /// Extract Common Name from a distinguished name string + fn extract_common_name(&self, dn: &str) -> String { + // Look for CN= in the distinguished name + for component in dn.split(',') { + let component = component.trim(); + if component.to_uppercase().starts_with("CN=") { + return component[3..].to_string(); + } + } + + // Fallback to the full DN if no CN found + dn.to_string() + } +} + +// Add base64 decoding functionality +mod base64 { + use anyhow::Result; + + pub fn decode(input: &str) -> Result> { + // Simple base64 decoder - in a real implementation, you'd use the base64 crate + // For now, we'll use a basic implementation + use std::collections::HashMap; + + let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let mut decode_table = HashMap::new(); + + for (i, c) in alphabet.chars().enumerate() { + decode_table.insert(c, i as u8); + } + + let input = input.replace([' ', '\n', '\r', '\t'], ""); + let mut result = Vec::new(); + let mut buffer = 0u32; + let mut bits_collected = 0; + + for c in input.chars() { + if c == '=' { + break; // Padding + } + + if let Some(&value) = decode_table.get(&c) { + buffer = (buffer << 6) | (value as u32); + bits_collected += 6; + + if bits_collected >= 8 { + bits_collected -= 8; + result.push(((buffer >> bits_collected) & 0xFF) as u8); + } + } + } + + Ok(result) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::CryptographicPrimitive; + + #[test] + fn test_certificate_parser_creation() { + let _parser = CertificateParser::new(); + // Creation should succeed without panicking + } + + #[test] + fn test_signature_algorithm_mapping() { + let parser = CertificateParser::new(); + + // Test RSA mapping + let (name, primitive, level, _) = parser.map_signature_algorithm("1.2.840.113549.1.1.11"); + assert_eq!(name, "RSA with SHA-256"); + assert!(matches!(primitive, CryptographicPrimitive::Signature)); + assert_eq!(level, 0); // Vulnerable to quantum attacks + + // Test ECDSA mapping + let (name, primitive, level, _) = parser.map_signature_algorithm("1.2.840.10045.4.3.2"); + assert_eq!(name, "ECDSA with SHA-256"); + assert!(matches!(primitive, CryptographicPrimitive::Signature)); + assert_eq!(level, 0); // Vulnerable to quantum attacks + } + + #[test] + fn test_common_name_extraction() { + let parser = CertificateParser::new(); + + let dn = "CN=example.com,O=Example Corp,C=US"; + assert_eq!(parser.extract_common_name(dn), "example.com"); + + let dn_no_cn = "O=Example Corp,C=US"; + assert_eq!(parser.extract_common_name(dn_no_cn), "O=Example Corp,C=US"); + } +} diff --git a/crates/cbom-generator/src/lib.rs b/crates/cbom-generator/src/lib.rs new file mode 100644 index 0000000..eb3b60a --- /dev/null +++ b/crates/cbom-generator/src/lib.rs @@ -0,0 +1,352 @@ +//! Minimal Viable Cryptographic Bill of Materials (MV-CBOM) Generator +//! +//! This crate implements the logic to generate a JSON document that adheres to the MV-CBOM schema. +//! The primary goal is to enable comprehensive Post-Quantum Cryptography (PQC) readiness assessment +//! and foster long-term crypto-agility. + +use anyhow::{Context, Result}; +use chrono::{DateTime, Utc}; +use scanner_core::{Finding, PatternRegistry}; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use uuid::Uuid; + +pub mod algorithm_detector; +pub mod certificate_parser; +// project parsing removed + +use algorithm_detector::AlgorithmDetector; +use certificate_parser::CertificateParser; + +/// The main MV-CBOM document structure +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MvCbom { + #[serde(rename = "bomFormat")] + pub bom_format: String, // Fixed value: "MV-CBOM" + + #[serde(rename = "specVersion")] + pub spec_version: String, // e.g., "1.0" + + #[serde(rename = "serialNumber")] + pub serial_number: String, // URN UUID format + + pub version: u32, // Increments with each new version + + pub metadata: CbomMetadata, + + #[serde(rename = "cryptoAssets")] + pub crypto_assets: Vec, +} + +/// Metadata about the BOM's creation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CbomMetadata { + pub timestamp: DateTime, + pub tools: Vec, +} + +// Component info removed to simplify schema + +/// Information about the tool that generated the BOM +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolInfo { + pub name: String, + pub version: String, + pub vendor: String, +} + +/// A cryptographic asset discovered in the codebase +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CryptoAsset { + #[serde(rename = "bom-ref")] + pub bom_ref: String, // Locally unique identifier (UUID) + + #[serde(rename = "assetType")] + pub asset_type: AssetType, + + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, // Human-readable name + + #[serde(rename = "assetProperties")] + pub asset_properties: AssetProperties, + + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "sourceLibrary")] + pub source_library: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub evidence: Option, +} + +/// The type classification of a cryptographic asset +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum AssetType { + Algorithm, + Certificate, + RelatedCryptoMaterial, +} + +/// Properties specific to the asset type +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AssetProperties { + Algorithm(AlgorithmProperties), + Certificate(CertificateProperties), + RelatedCryptoMaterial(RelatedCryptoMaterialProperties), +} + +/// Properties for algorithm assets +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AlgorithmProperties { + pub primitive: CryptographicPrimitive, + + #[serde(rename = "parameterSet")] + #[serde(skip_serializing_if = "Option::is_none")] + pub parameter_set: Option, // Flexible parameter storage + + #[serde(rename = "nistQuantumSecurityLevel")] + pub nist_quantum_security_level: u8, // 0 for vulnerable, 1-5 for secure +} + +/// Properties for certificate assets +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CertificateProperties { + #[serde(rename = "subjectName")] + pub subject_name: String, + + #[serde(rename = "issuerName")] + pub issuer_name: String, + + #[serde(rename = "notValidAfter")] + pub not_valid_after: DateTime, + + #[serde(rename = "signatureAlgorithm")] + pub signature_algorithm: String, // e.g., "RSA-SHA256", "ECDSA-P256" +} + +/// Properties for related cryptographic material +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RelatedCryptoMaterialProperties { + #[serde(rename = "materialType")] + pub material_type: String, + + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AssetEvidence { + pub file: String, + #[serde(rename = "detectorId")] + pub detector_id: String, + pub line: usize, + pub column: usize, +} + +/// Classification of cryptographic primitives +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum CryptographicPrimitive { + #[serde(rename = "pke")] + PublicKeyEncryption, + Signature, + Hash, + #[serde(rename = "kem")] + KeyEncapsulationMechanism, + #[serde(rename = "aead")] + AuthenticatedEncryption, + #[serde(rename = "mac")] + MessageAuthenticationCode, + #[serde(rename = "kdf")] + KeyDerivationFunction, + #[serde(rename = "prng")] + PseudoRandomNumberGenerator, +} + +/// Main generator for MV-CBOM documents +#[derive(Default)] +pub struct CbomGenerator { + certificate_parser: CertificateParser, + algorithm_detector: AlgorithmDetector, + deterministic: bool, + skip_certificates: bool, +} + +impl CbomGenerator { + pub fn new() -> Self { + Self::default() + } + + pub fn with_registry(registry: Arc) -> Self { + Self::with_options(registry, false, false) + } + + pub fn with_registry_mode(registry: Arc, deterministic: bool) -> Self { + Self::with_options(registry, deterministic, false) + } + + pub fn with_registry_and_options( + registry: Arc, + skip_certificates: bool, + ) -> Self { + Self::with_options(registry, false, skip_certificates) + } + + pub fn with_registry_mode_and_options( + registry: Arc, + deterministic: bool, + skip_certificates: bool, + ) -> Self { + Self::with_options(registry, deterministic, skip_certificates) + } + + fn with_options( + registry: Arc, + deterministic: bool, + skip_certificates: bool, + ) -> Self { + Self { + certificate_parser: CertificateParser::with_mode(deterministic), + algorithm_detector: AlgorithmDetector::with_registry_and_mode(registry, deterministic), + deterministic, + skip_certificates, + } + } + + /// Generate an MV-CBOM for the given directory (single project) + pub fn generate_cbom(&self, scan_path: &Path, findings: &[Finding]) -> Result { + // Skip canonicalization if the path doesn't exist or is too large + let scan_path = if scan_path.exists() { + scan_path + .canonicalize() + .unwrap_or_else(|_| scan_path.to_path_buf()) + } else { + scan_path.to_path_buf() + }; + + // Project parsing removed; no component information included + + // Parse certificates in the directory (unless skipped) + let certificates = if self.skip_certificates { + Vec::new() + } else { + self.certificate_parser.parse_certificates(&scan_path)? + }; + + // Detect algorithms from findings and static analysis + let algorithms = self + .algorithm_detector + .detect_algorithms(&scan_path, findings)?; + + // Build crypto assets list and libraries summary + let mut crypto_assets = Vec::new(); + crypto_assets.extend(algorithms); + crypto_assets.extend(certificates); + + let cbom = MvCbom { + bom_format: "MV-CBOM".to_string(), + spec_version: "1.0".to_string(), + serial_number: if self.deterministic { + format!( + "urn:uuid:{}", + Uuid::new_v5(&Uuid::NAMESPACE_URL, b"cbom:serial") + ) + } else { + format!("urn:uuid:{}", Uuid::new_v4()) + }, + version: 1, + metadata: CbomMetadata { + timestamp: if self.deterministic { + DateTime::from_timestamp(0, 0).unwrap_or(Utc::now()) + } else { + Utc::now() + }, + tools: vec![ToolInfo { + name: "cipherscope".to_string(), + version: env!("CARGO_PKG_VERSION").to_string(), + vendor: "CipherScope Contributors".to_string(), + }], + }, + crypto_assets: { crypto_assets }, + }; + + Ok(cbom) + } + + /// Generate MV-CBOMs for all projects discovered recursively + pub fn generate_cboms_recursive( + &self, + scan_path: &Path, + findings: &[Finding], + ) -> Result> { + // Skip canonicalization if the path doesn't exist or is too large + let scan_path = if scan_path.exists() { + scan_path + .canonicalize() + .unwrap_or_else(|_| scan_path.to_path_buf()) + } else { + scan_path.to_path_buf() + }; + + // Project discovery removed; just generate one CBOM for the root + let cboms = vec![(scan_path.clone(), self.generate_cbom(&scan_path, findings)?)]; + Ok(cboms) + } + + /// Write the MV-CBOM to a JSON file + pub fn write_cbom(&self, cbom: &MvCbom, output_path: &Path) -> Result<()> { + let json = + serde_json::to_string_pretty(cbom).context("Failed to serialize MV-CBOM to JSON")?; + + fs::write(output_path, json) + .with_context(|| format!("Failed to write MV-CBOM to {}", output_path.display()))?; + + Ok(()) + } + + /// Write multiple MV-CBOMs to JSON files (one per project) + pub fn write_cboms(&self, cboms: &[(PathBuf, MvCbom)]) -> Result> { + let mut written_files = Vec::new(); + + for (project_path, cbom) in cboms { + let output_path = project_path.join("mv-cbom.json"); + self.write_cbom(cbom, &output_path)?; + written_files.push(output_path); + } + + Ok(written_files) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cbom_serialization() { + let cbom = MvCbom { + bom_format: "MV-CBOM".to_string(), + spec_version: "1.0".to_string(), + serial_number: "urn:uuid:12345678-1234-1234-1234-123456789abc".to_string(), + version: 1, + metadata: CbomMetadata { + timestamp: Utc::now(), + tools: vec![ToolInfo { + name: "cipherscope".to_string(), + version: "0.1.0".to_string(), + vendor: "CipherScope Contributors".to_string(), + }], + }, + crypto_assets: vec![], + }; + + let json = serde_json::to_string_pretty(&cbom).expect("Failed to serialize test CBOM"); + println!("{}", json); + + // Verify it can be deserialized + let _parsed: MvCbom = serde_json::from_str(&json).expect("Failed to deserialize test CBOM"); + } +} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index b98c673..bb2a748 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -10,17 +10,10 @@ clap = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } toml = { workspace = true } -ignore = { workspace = true } rayon = { workspace = true } -once_cell = { workspace = true } -regex = { workspace = true } -aho-corasick = { workspace = true } -crossbeam-channel = { workspace = true } indicatif = "0.17" scanner-core = { path = "../scanner-core" } -detector-swift = { path = "../detector-swift" } -detector-objc = { path = "../detector-objc" } -detector-kotlin = { path = "../detector-kotlin" } +cbom-generator = { path = "../cbom-generator" } [[bin]] name = "cipherscope" diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 7f75b9a..6c00d6c 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,26 +1,23 @@ use anyhow::{Context, Result}; +use cbom_generator::CbomGenerator; use clap::{ArgAction, Parser}; use indicatif::{ProgressBar, ProgressStyle}; -use scanner_core::*; +use scanner_core::{Config, Detector, Language, PatternDetector, PatternRegistry, Scanner}; use std::fs; use std::path::PathBuf; use std::sync::Arc; #[derive(Parser, Debug)] #[command(name = "cipherscope")] -#[command(version, about = "Fast static scanner for third-party crypto libraries", long_about = None)] +#[command(version, about = "Generate Cryptographic Bill of Materials (MV-CBOM) for Post-Quantum Cryptography readiness assessment", long_about = None)] struct Args { /// Paths to scan #[arg(value_name = "PATH", default_value = ".")] paths: Vec, - /// Emit JSONL to stdout + /// Generate MV-CBOMs recursively for all discovered projects (default: single project) #[arg(long, action = ArgAction::SetTrue)] - json: bool, - - /// Write SARIF to file - #[arg(long, value_name = "FILE")] - sarif: Option, + recursive: bool, /// Number of threads #[arg(long, value_name = "N")] @@ -46,10 +43,6 @@ struct Args { #[arg(long, action = ArgAction::SetTrue)] print_config: bool, - /// Dry-run: list files that would be scanned - #[arg(long, action = ArgAction::SetTrue)] - dry_run: bool, - /// Path to patterns file #[arg(long, value_name = "FILE", default_value = "patterns.toml")] patterns: PathBuf, @@ -57,6 +50,18 @@ struct Args { /// Show progress bar during scanning #[arg(long, action = ArgAction::SetTrue)] progress: bool, + + /// Output file for single-project CBOM (default: stdout) + #[arg(long, value_name = "FILE")] + output: Option, + + /// Output directory for recursive CBOMs (default: stdout JSON array) + #[arg(long, value_name = "DIR")] + output_dir: Option, + + /// Skip certificate scanning during CBOM generation + #[arg(long, action = ArgAction::SetTrue)] + skip_certificates: bool, } fn main() -> Result<()> { @@ -167,14 +172,6 @@ fn main() -> Result<()> { } let scanner = Scanner::new(®, dets, cfg); - if args.dry_run { - let files = scanner.discover_files(&args.paths); - for p in files { - println!("{}", p.display()); - } - return Ok(()); - } - let findings = scanner.run(&args.paths)?; // Clear progress bar if it was shown @@ -182,124 +179,79 @@ fn main() -> Result<()> { println!(); // Move to next line after progress bar } - if args.json { - for f in &findings { - println!("{}", serde_json::to_string(f)?); - } + // Generate MV-CBOM (always - this is the primary functionality) + // Deterministic mode for tests/ground-truth when --deterministic is set + let cbom_generator = if args.deterministic { + CbomGenerator::with_registry_mode_and_options(reg.clone(), true, args.skip_certificates) } else { - print_table(&findings); - } - - if let Some(sarif_path) = args.sarif.as_ref() { - let sarif = to_sarif(&findings); - fs::write(sarif_path, serde_json::to_vec_pretty(&sarif)?)?; - } + CbomGenerator::with_registry_and_options(reg.clone(), args.skip_certificates) + }; - Ok(()) -} + // Use the first path as the scan root for CBOM generation + let default_path = PathBuf::from("."); + let scan_path = args.paths.first().unwrap_or(&default_path); -fn print_table(findings: &[Finding]) { - use std::collections::BTreeMap; - let mut map: BTreeMap<(Language, String), Vec<&Finding>> = BTreeMap::new(); - for f in findings { - map.entry((f.language, f.library.clone())) - .or_default() - .push(f); - } - println!("Language | Library | Count | Example"); - println!("---------|---------|-------|--------"); - for ((lang, lib), list) in map { - let ex = list - .first() - .map(|f| format!("{}:{} {}", f.file.display(), f.span.line, f.symbol)) - .unwrap_or_default(); - println!("{:?} | {} | {} | {}", lang, lib, list.len(), ex); + if args.recursive { + // Simplified: generate a single CBOM for the root + match cbom_generator.generate_cboms_recursive(scan_path, &findings) { + Ok(cboms) => { + if let Some(dir) = &args.output_dir { + // Write each CBOM into the specified directory + if let Err(e) = fs::create_dir_all(dir) { + eprintln!("Failed to create output directory {}: {}", dir.display(), e); + std::process::exit(1); + } + for (i, (_project_path, cbom)) in cboms.iter().enumerate() { + let file = dir.join(format!("{:03}-mv-cbom.json", i + 1)); + if let Err(e) = cbom_generator.write_cbom(cbom, &file) { + eprintln!("Failed to write MV-CBOM to {}: {}", file.display(), e); + std::process::exit(1); + } + } + println!("Generated {} MV-CBOMs to {}", cboms.len(), dir.display()); + } else { + // Print JSON array to stdout + let only_cboms: Vec<&cbom_generator::MvCbom> = + cboms.iter().map(|(_, c)| c).collect(); + let json = serde_json::to_string_pretty(&only_cboms) + .expect("Failed to serialize MV-CBOMs to JSON"); + println!("{}", json); + } + } + Err(e) => { + eprintln!("Failed to generate recursive MV-CBOMs: {}", e); + std::process::exit(1); + } + } + } else { + // Single CBOM generation + match cbom_generator.generate_cbom(scan_path, &findings) { + Ok(cbom) => { + if let Some(path) = &args.output { + match cbom_generator.write_cbom(&cbom, path) { + Ok(()) => { + println!("MV-CBOM written to: {}", path.display()); + println!("Found {} cryptographic assets", cbom.crypto_assets.len()); + // Dependencies removed + } + Err(e) => { + eprintln!("Failed to write MV-CBOM: {}", e); + std::process::exit(1); + } + } + } else { + // Print JSON to stdout (no extra lines) + let json = serde_json::to_string_pretty(&cbom) + .expect("Failed to serialize MV-CBOM to JSON"); + println!("{}", json); + } + } + Err(e) => { + eprintln!("Failed to generate MV-CBOM: {}", e); + std::process::exit(1); + } + } } -} -#[derive(serde::Serialize)] -struct SarifLog { - version: String, - #[serde(rename = "$schema")] - schema: String, - runs: Vec, -} -#[derive(serde::Serialize)] -struct SarifRun { - tool: SarifTool, - results: Vec, -} -#[derive(serde::Serialize)] -struct SarifTool { - driver: SarifDriver, -} -#[derive(serde::Serialize)] -struct SarifDriver { - name: String, - version: String, -} -#[derive(serde::Serialize)] -struct SarifResult { - rule_id: String, - level: String, - message: SarifMessage, - locations: Vec, -} -#[derive(serde::Serialize)] -struct SarifMessage { - text: String, -} -#[derive(serde::Serialize)] -struct SarifLocation { - physical_location: SarifPhysicalLocation, -} -#[derive(serde::Serialize)] -struct SarifPhysicalLocation { - artifact_location: SarifArtifactLocation, - region: SarifRegion, -} -#[derive(serde::Serialize)] -struct SarifArtifactLocation { - uri: String, -} -#[derive(serde::Serialize)] -struct SarifRegion { - start_line: usize, - start_column: usize, -} - -fn to_sarif(findings: &[Finding]) -> SarifLog { - SarifLog { - version: "2.1.0".into(), - schema: "https://json.schemastore.org/sarif-2.1.0.json".into(), - runs: vec![SarifRun { - tool: SarifTool { - driver: SarifDriver { - name: "cipherscope".into(), - version: env!("CARGO_PKG_VERSION").into(), - }, - }, - results: findings - .iter() - .map(|f| SarifResult { - rule_id: f.detector_id.clone(), - level: "note".into(), - message: SarifMessage { - text: format!("{} in {:?}", f.library, f.language), - }, - locations: vec![SarifLocation { - physical_location: SarifPhysicalLocation { - artifact_location: SarifArtifactLocation { - uri: f.file.display().to_string(), - }, - region: SarifRegion { - start_line: f.span.line, - start_column: f.span.column, - }, - }, - }], - }) - .collect(), - }], - } + Ok(()) } diff --git a/crates/cli/tests/ground_truth.rs b/crates/cli/tests/ground_truth.rs new file mode 100644 index 0000000..76f869f --- /dev/null +++ b/crates/cli/tests/ground_truth.rs @@ -0,0 +1,174 @@ +use scanner_core::*; +use serde_json::Value; +use std::fs; +use std::path::PathBuf; +use std::sync::Arc; + +fn normalize(v: &mut Value) { + match v { + Value::Object(map) => { + map.remove("serialNumber"); + if let Some(meta) = map.get_mut("metadata") { + if let Some(obj) = meta.as_object_mut() { + obj.remove("timestamp"); + obj.remove("component"); + } + } + // Dependencies removed from schema + map.remove("dependencies"); + if let Some(Value::Array(assets)) = map.get_mut("cryptoAssets") { + for a in assets.iter_mut() { + if let Some(obj) = a.as_object_mut() { + obj.remove("bom-ref"); + + // Normalize file paths in evidence to be relative + if let Some(Value::Object(evidence)) = obj.get_mut("evidence") { + if let Some(Value::String(file_path)) = evidence.get_mut("file") { + // Convert absolute paths to relative by removing the prefix + if file_path.contains("/fixtures/") { + if let Some(idx) = file_path.find("/fixtures/") { + *file_path = format!("fixtures/{}", &file_path[idx + 10..]); + } + } + } + } + } + } + // Sort assets by name, sourceLibrary, then assetType for stable comparisons + assets.sort_by(|a, b| { + let an = a.get("name").and_then(|x| x.as_str()).unwrap_or(""); + let as_ = a + .get("sourceLibrary") + .and_then(|x| x.as_str()) + .unwrap_or(""); + let at = a.get("assetType").and_then(|x| x.as_str()).unwrap_or(""); + let bn = b.get("name").and_then(|x| x.as_str()).unwrap_or(""); + let bs = b + .get("sourceLibrary") + .and_then(|x| x.as_str()) + .unwrap_or(""); + let bt = b.get("assetType").and_then(|x| x.as_str()).unwrap_or(""); + (an, as_, at).cmp(&(bn, bs, bt)) + }); + } + for val in map.values_mut() { + normalize(val); + } + } + Value::Array(arr) => { + for val in arr.iter_mut() { + normalize(val); + } + } + _ => {} + } +} + +#[test] +fn compare_comprehensive_ground_truth() { + let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.."); + let patterns_path = workspace.join("patterns.toml"); + let patterns = fs::read_to_string(patterns_path).unwrap(); + let reg = Arc::new(PatternRegistry::load(&patterns).unwrap()); + + let dets: Vec> = vec![ + Box::new(PatternDetector::new( + "detector-go", + &[Language::Go], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-java", + &[Language::Java], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-c", + &[Language::C], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-cpp", + &[Language::Cpp], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-rust", + &[Language::Rust], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-python", + &[Language::Python], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-php", + &[Language::Php], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-swift", + &[Language::Swift], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-objc", + &[Language::ObjC], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-kotlin", + &[Language::Kotlin], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-erlang", + &[Language::Erlang], + reg.clone(), + )), + ]; + let scanner = Scanner::new(®, dets, Config::default()); + + let fixtures_root = workspace.join("fixtures"); + + // iterate comprehensive subdirectories only + let mut roots: Vec = Vec::new(); + for lang_dir in fs::read_dir(&fixtures_root).unwrap() { + let lang_dir = lang_dir.unwrap().path(); + let comp = lang_dir.join("comprehensive"); + if comp.exists() { + roots.push(comp); + } + } + + let findings = scanner.run(&roots).unwrap(); + + // Generate CBOM per root and compare if mv-cbom.json exists + let gen = cbom_generator::CbomGenerator::with_registry(reg.clone()); + for root in roots { + // Filter findings to this root, matching CLI single-project behavior + let project_findings: Vec = findings + .iter() + .filter(|f| f.file.starts_with(&root)) + .cloned() + .collect(); + let cbom = gen.generate_cbom(&root, &project_findings).unwrap(); + let got = serde_json::to_value(&cbom).unwrap(); + let mut got_norm = got.clone(); + normalize(&mut got_norm); + + let truth_path = root.join("mv-cbom.json"); + if truth_path.exists() { + let truth_s = fs::read_to_string(&truth_path).unwrap(); + let mut truth_v: Value = serde_json::from_str(&truth_s).unwrap(); + normalize(&mut truth_v); + assert_eq!( + got_norm, + truth_v, + "ground truth mismatch for {}", + root.display() + ); + } + } +} diff --git a/crates/cli/tests/integration.rs b/crates/cli/tests/integration.rs index 5270b50..4418276 100644 --- a/crates/cli/tests/integration.rs +++ b/crates/cli/tests/integration.rs @@ -62,7 +62,7 @@ fn scan_fixtures() { ); } - // Expect at least one hit per language category in positive fixtures + // Expect at least one hit per language category across comprehensive fixtures let has_rust = findings .iter() .any(|f| matches!(f.language, Language::Rust)); @@ -78,17 +78,133 @@ fn scan_fixtures() { let has_go = findings.iter().any(|f| matches!(f.language, Language::Go)); let has_php = findings.iter().any(|f| matches!(f.language, Language::Php)); - assert!( - has_rust && has_python && has_java && has_c && has_go && has_php, - "missing findings for some languages" - ); + assert!(has_rust, "missing Rust findings"); + assert!(has_python, "missing Python findings"); + assert!(has_java, "missing Java findings"); + assert!(has_c, "missing C/C++ findings"); + assert!(has_go, "missing Go findings"); + assert!(has_php, "missing PHP findings"); + + // Note: legacy negative fixtures removed; comprehensive fixtures are used now. +} - // Ensure comments are ignored: negative fixtures should not produce hits - let neg = workspace.join("fixtures/negative"); - let neg_findings = scanner.run(&[neg]).unwrap(); +#[test] +fn scan_nested_general_fixtures() { + let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.."); + let patterns_path = workspace.join("patterns.toml"); + let patterns = std::fs::read_to_string(patterns_path).unwrap(); + let reg = PatternRegistry::load(&patterns).unwrap(); + let reg = Arc::new(reg); + let dets: Vec> = vec![ + Box::new(PatternDetector::new( + "detector-go", + &[Language::Go], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-java", + &[Language::Java], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-c", + &[Language::C], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-cpp", + &[Language::Cpp], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-rust", + &[Language::Rust], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-python", + &[Language::Python], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-php", + &[Language::Php], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-swift", + &[Language::Swift], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-objc", + &[Language::ObjC], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-kotlin", + &[Language::Kotlin], + reg.clone(), + )), + Box::new(PatternDetector::new( + "detector-erlang", + &[Language::Erlang], + reg.clone(), + )), + ]; + let scanner = Scanner::new(®, dets, Config::default()); + + // Scan the nested general fixtures root; test should not rely on per-file targets + let root = workspace.join("fixtures/general"); + let findings = scanner.run(std::slice::from_ref(&root)).unwrap(); + + // Assert we discovered at least one finding per intended language subdir + let has_rust = findings + .iter() + .any(|f| matches!(f.language, Language::Rust)); + let has_python = findings + .iter() + .any(|f| matches!(f.language, Language::Python)); + let has_java = findings + .iter() + .any(|f| matches!(f.language, Language::Java)); + let has_c = findings.iter().any(|f| matches!(f.language, Language::C)); + let has_cpp = findings.iter().any(|f| matches!(f.language, Language::Cpp)); + let has_go = findings.iter().any(|f| matches!(f.language, Language::Go)); + let has_php = findings.iter().any(|f| matches!(f.language, Language::Php)); + let has_swift = findings + .iter() + .any(|f| matches!(f.language, Language::Swift)); + let has_objc = findings + .iter() + .any(|f| matches!(f.language, Language::ObjC)); + let has_kotlin = findings + .iter() + .any(|f| matches!(f.language, Language::Kotlin)); + let has_erlang = findings + .iter() + .any(|f| matches!(f.language, Language::Erlang)); + + assert!(has_rust, "missing Rust findings in nested scan"); + assert!(has_python, "missing Python findings in nested scan"); + assert!(has_java, "missing Java findings in nested scan"); + assert!(has_c || has_cpp, "missing C/C++ findings in nested scan"); + assert!(has_go, "missing Go findings in nested scan"); + assert!(has_php, "missing PHP findings in nested scan"); + assert!(has_swift, "missing Swift findings in nested scan"); + assert!(has_objc, "missing ObjC findings in nested scan"); + assert!(has_kotlin, "missing Kotlin findings in nested scan"); + assert!(has_erlang, "missing Erlang findings in nested scan"); + + // Ensure deduplication does not erase per-language assets: group by (file, language) + use std::collections::HashSet; + let mut file_lang_pairs = HashSet::new(); + for f in &findings { + file_lang_pairs.insert((f.file.display().to_string(), f.language)); + } + // Expect multiple unique (file,language) pairs in nested scan assert!( - neg_findings.is_empty(), - "expected no findings in negative fixtures, got {}", - neg_findings.len() + file_lang_pairs.len() >= 5, + "unexpectedly low unique file/language pairs" ); } diff --git a/crates/cli/tests/progress_reporting.rs b/crates/cli/tests/progress_reporting.rs index dcf3573..c43b65b 100644 --- a/crates/cli/tests/progress_reporting.rs +++ b/crates/cli/tests/progress_reporting.rs @@ -83,7 +83,7 @@ apis = ["printf", "println", "print", "main"] let detectors = vec![]; let scanner = Scanner::new(®istry, detectors, config); - // Scan the fixtures directory + // Scan the fixtures directory (comprehensive fixtures layout) let fixtures_path = PathBuf::from("../../fixtures"); let roots = vec![fixtures_path]; @@ -239,7 +239,7 @@ apis = ["main"] let rust_scanner = Scanner::new(®istry, detectors1, rust_config); let fixtures_path = PathBuf::from("../../fixtures"); let _rust_findings = rust_scanner - .run(&[fixtures_path.clone()]) + .run(std::slice::from_ref(&fixtures_path)) .expect("Rust scan failed"); // Scan 2: All supported file types diff --git a/crates/detector-c/Cargo.toml b/crates/detector-c/Cargo.toml deleted file mode 100644 index aee084f..0000000 --- a/crates/detector-c/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-c" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_c" -path = "src/lib.rs" - diff --git a/crates/detector-c/src/lib.rs b/crates/detector-c/src/lib.rs deleted file mode 100644 index 2e44a6a..0000000 --- a/crates/detector-c/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new("detector-c", &[Language::C], registry)) -} diff --git a/crates/detector-cpp/Cargo.toml b/crates/detector-cpp/Cargo.toml deleted file mode 100644 index 03f6b1d..0000000 --- a/crates/detector-cpp/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-cpp" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_cpp" -path = "src/lib.rs" - diff --git a/crates/detector-cpp/src/lib.rs b/crates/detector-cpp/src/lib.rs deleted file mode 100644 index ad45827..0000000 --- a/crates/detector-cpp/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-cpp", - &[Language::Cpp], - registry, - )) -} diff --git a/crates/detector-erlang/Cargo.toml b/crates/detector-erlang/Cargo.toml deleted file mode 100644 index 531c7c3..0000000 --- a/crates/detector-erlang/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "detector-erlang" -version.workspace = true -edition.workspace = true -license.workspace = true -authors.workspace = true -description = "Erlang cryptographic library detector for CipherScope" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = "1" diff --git a/crates/detector-erlang/src/lib.rs b/crates/detector-erlang/src/lib.rs deleted file mode 100644 index 90fa06c..0000000 --- a/crates/detector-erlang/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -use anyhow::Result; -use scanner_core::{Detector, Emitter, Language, Prefilter, ScanUnit}; -use std::collections::BTreeSet; - -pub struct ErlangDetector; - -impl Detector for ErlangDetector { - fn id(&self) -> &'static str { - "detector-erlang" - } - - fn languages(&self) -> &'static [Language] { - &[Language::Erlang] - } - - fn prefilter(&self) -> Prefilter { - Prefilter { - extensions: BTreeSet::from([ - ".erl".to_string(), - ".hrl".to_string(), - ".beam".to_string(), - ]), - substrings: BTreeSet::new(), - } - } - - fn scan(&self, _unit: &ScanUnit, _em: &mut Emitter) -> Result<()> { - // This detector is not used since we use PatternDetector instead - Ok(()) - } - - fn as_any(&self) -> &dyn std::any::Any { - self - } -} diff --git a/crates/detector-go/Cargo.toml b/crates/detector-go/Cargo.toml deleted file mode 100644 index 45cf67b..0000000 --- a/crates/detector-go/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-go" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_go" -path = "src/lib.rs" - diff --git a/crates/detector-go/src/lib.rs b/crates/detector-go/src/lib.rs deleted file mode 100644 index a8fe812..0000000 --- a/crates/detector-go/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-go", - &[Language::Go], - registry, - )) -} diff --git a/crates/detector-java/Cargo.toml b/crates/detector-java/Cargo.toml deleted file mode 100644 index b372e20..0000000 --- a/crates/detector-java/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-java" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_java" -path = "src/lib.rs" - diff --git a/crates/detector-java/src/lib.rs b/crates/detector-java/src/lib.rs deleted file mode 100644 index e5856d3..0000000 --- a/crates/detector-java/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-java", - &[Language::Java], - registry, - )) -} diff --git a/crates/detector-kotlin/Cargo.toml b/crates/detector-kotlin/Cargo.toml deleted file mode 100644 index 82ee7bf..0000000 --- a/crates/detector-kotlin/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "detector-kotlin" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_kotlin" -path = "src/lib.rs" diff --git a/crates/detector-kotlin/src/lib.rs b/crates/detector-kotlin/src/lib.rs deleted file mode 100644 index 4da75ea..0000000 --- a/crates/detector-kotlin/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-kotlin", - &[Language::Kotlin], - registry, - )) -} diff --git a/crates/detector-objc/Cargo.toml b/crates/detector-objc/Cargo.toml deleted file mode 100644 index 4e47b92..0000000 --- a/crates/detector-objc/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "detector-objc" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_objc" -path = "src/lib.rs" diff --git a/crates/detector-objc/src/lib.rs b/crates/detector-objc/src/lib.rs deleted file mode 100644 index 22cd65d..0000000 --- a/crates/detector-objc/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-objc", - &[Language::ObjC], - registry, - )) -} diff --git a/crates/detector-php/Cargo.toml b/crates/detector-php/Cargo.toml deleted file mode 100644 index 253f56c..0000000 --- a/crates/detector-php/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-php" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_php" -path = "src/lib.rs" - diff --git a/crates/detector-php/src/lib.rs b/crates/detector-php/src/lib.rs deleted file mode 100644 index f60fee5..0000000 --- a/crates/detector-php/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-php", - &[Language::Php], - registry, - )) -} diff --git a/crates/detector-python/Cargo.toml b/crates/detector-python/Cargo.toml deleted file mode 100644 index 6275320..0000000 --- a/crates/detector-python/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-python" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_python" -path = "src/lib.rs" - diff --git a/crates/detector-python/src/lib.rs b/crates/detector-python/src/lib.rs deleted file mode 100644 index 2647c77..0000000 --- a/crates/detector-python/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-python", - &[Language::Python], - registry, - )) -} diff --git a/crates/detector-rust/Cargo.toml b/crates/detector-rust/Cargo.toml deleted file mode 100644 index 01680bc..0000000 --- a/crates/detector-rust/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "detector-rust" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_rust" -path = "src/lib.rs" - diff --git a/crates/detector-rust/src/lib.rs b/crates/detector-rust/src/lib.rs deleted file mode 100644 index bbcf135..0000000 --- a/crates/detector-rust/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-rust", - &[Language::Rust], - registry, - )) -} diff --git a/crates/detector-swift/Cargo.toml b/crates/detector-swift/Cargo.toml deleted file mode 100644 index 96eb78c..0000000 --- a/crates/detector-swift/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "detector-swift" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[dependencies] -scanner-core = { path = "../scanner-core" } -anyhow = { workspace = true } - -[lib] -name = "detector_swift" -path = "src/lib.rs" diff --git a/crates/detector-swift/src/lib.rs b/crates/detector-swift/src/lib.rs deleted file mode 100644 index 8bb1825..0000000 --- a/crates/detector-swift/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -use scanner_core::{Detector, Language, PatternDetector, PatternRegistry}; -use std::sync::Arc; - -pub fn make(registry: Arc) -> Box { - Box::new(PatternDetector::new( - "detector-swift", - &[Language::Swift], - registry, - )) -} diff --git a/crates/scanner-core/Cargo.toml b/crates/scanner-core/Cargo.toml index eca4fa2..b93e5f8 100644 --- a/crates/scanner-core/Cargo.toml +++ b/crates/scanner-core/Cargo.toml @@ -6,16 +6,13 @@ license = "Apache-2.0" [dependencies] anyhow = { workspace = true } -thiserror = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } toml = { workspace = true } regex = { workspace = true } aho-corasick = { workspace = true } -once_cell = { workspace = true } rayon = { workspace = true } ignore = { workspace = true } -memmap2 = { workspace = true } globset = { workspace = true } crossbeam-channel = { workspace = true } num_cpus = { workspace = true } diff --git a/crates/scanner-core/src/lib.rs b/crates/scanner-core/src/lib.rs index 305e406..b0ada68 100644 --- a/crates/scanner-core/src/lib.rs +++ b/crates/scanner-core/src/lib.rs @@ -11,7 +11,7 @@ //! - Critical optimization: avoids descending into irrelevant directories like `node_modules` or `.git` //! - Sends discovered file paths to a bounded `crossbeam_channel` work queue //! -//! ## Consumers (Parallel File Processors) +//! ## Consumers (Parallel File Processors) //! - Uses `rayon` to create a thread pool of file processors //! - Each consumer pulls file paths from the shared work queue //! - Executes core file scanning logic (language detection, content analysis, pattern matching) @@ -185,6 +185,8 @@ pub struct LibrarySpec { pub languages: Vec, #[serde(default)] pub patterns: LibraryPatterns, + #[serde(default)] + pub algorithms: Vec, } #[derive(Debug, Clone, Default, Deserialize)] @@ -199,6 +201,26 @@ pub struct LibraryPatterns { pub apis: Vec, } +#[derive(Debug, Clone, Deserialize)] +pub struct AlgorithmSpec { + pub name: String, + pub primitive: String, // "signature", "aead", "hash", "kem", "pke", "mac", "kdf", "prng" + #[serde(default)] + pub parameter_patterns: Vec, + #[serde(rename = "nistQuantumSecurityLevel")] + pub nist_quantum_security_level: u8, + #[serde(default)] + pub symbol_patterns: Vec, // Regex patterns to match this algorithm in findings +} + +#[derive(Debug, Clone, Deserialize)] +pub struct ParameterPattern { + pub name: String, // e.g., "keySize", "curve", "outputSize" + pub pattern: String, // Regex pattern to extract the parameter value + #[serde(default)] + pub default_value: Option, // Default value if not found +} + #[derive(Deserialize)] pub struct Config { #[serde(default = "default_max_file_size")] @@ -309,6 +331,23 @@ pub struct CompiledLibrary { pub namespace: Vec, pub apis: Vec, pub prefilter_substrings: Vec, + pub algorithms: Vec, +} + +#[derive(Debug, Clone)] +pub struct CompiledAlgorithm { + pub name: String, + pub primitive: String, + pub nist_quantum_security_level: u8, + pub symbol_patterns: Vec, + pub parameter_patterns: Vec, +} + +#[derive(Debug, Clone)] +pub struct CompiledParameterPattern { + pub name: String, + pub pattern: Regex, + pub default_value: Option, } #[derive(Debug)] @@ -372,6 +411,7 @@ fn compile_library(lib: LibrarySpec) -> Result { let namespace = compile_regexes(&lib.patterns.namespace)?; let apis = compile_regexes(&lib.patterns.apis)?; let prefilter_substrings = derive_prefilter_substrings(&lib.patterns); + let algorithms = compile_algorithms(&lib.algorithms)?; Ok(CompiledLibrary { name: lib.name, languages: lib.languages.into_iter().collect(), @@ -380,25 +420,63 @@ fn compile_library(lib: LibrarySpec) -> Result { namespace, apis, prefilter_substrings, + algorithms, }) } fn compile_regexes(srcs: &[String]) -> Result> { srcs.iter() .map(|s| { - let pat = format!("(?m){}", s); + let pat = format!("(?m){s}"); Regex::new(&pat).with_context(|| format!("bad pattern: {s}")) }) .collect() } +fn compile_algorithms(algorithms: &[AlgorithmSpec]) -> Result> { + algorithms + .iter() + .map(|algo| { + let symbol_patterns = compile_regexes(&algo.symbol_patterns)?; + let parameter_patterns = algo + .parameter_patterns + .iter() + .map(|param| { + let pattern = Regex::new(¶m.pattern) + .with_context(|| format!("bad parameter pattern: {}", param.pattern))?; + Ok(CompiledParameterPattern { + name: param.name.clone(), + pattern, + default_value: param.default_value.clone(), + }) + }) + .collect::>>()?; + + Ok(CompiledAlgorithm { + name: algo.name.clone(), + primitive: algo.primitive.clone(), + nist_quantum_security_level: algo.nist_quantum_security_level, + symbol_patterns, + parameter_patterns, + }) + }) + .collect() +} + fn derive_prefilter_substrings(p: &LibraryPatterns) -> Vec { let mut set = BTreeSet::new(); let mut push_tokens = |s: &str| { - for tok in s.split(|c: char| !c.is_alphanumeric() && c != '.' && c != '/' && c != '_') { + // Remove common regex anchors that pollute tokens + let cleaned = s.replace("\\b", ""); + for tok in cleaned.split(|c: char| !c.is_alphanumeric() && c != '.' && c != '/' && c != '_') + { let t = tok.trim(); - if t.len() >= 4 { + // Lower the minimum length to 2 to catch important crypto API prefixes like "CC", "SHA" etc. + if t.len() >= 2 { + // CRITICAL FIX: Add both lowercase AND uppercase versions to catch all cases set.insert(t.to_ascii_lowercase()); + set.insert(t.to_ascii_uppercase()); + set.insert(t.to_string()); // Also preserve original case } } }; @@ -757,6 +835,9 @@ impl<'a> Scanner<'a> { work_sender: Sender, progress_sender: Option>, ) -> Result<()> { + let total_files_attempted = Arc::new(AtomicUsize::new(0)); + let total_files_sent = Arc::new(AtomicUsize::new(0)); + let total_files_failed = Arc::new(AtomicUsize::new(0)); // Build glob matcher for include patterns let include_matcher: Option = if !self.config.include_globs.is_empty() { let mut builder = globset::GlobSetBuilder::new(); @@ -785,30 +866,34 @@ impl<'a> Scanner<'a> { let mut builder = WalkBuilder::new(root); builder .hidden(false) // Skip hidden files by default - .git_ignore(true) // Respect .gitignore files - critical optimization - .git_exclude(true) // Respect .git/info/exclude - .ignore(true) // Respect .ignore files - .follow_links(false) // Don't follow symlinks for safety + .git_ignore(true) // Respect gitignore for consistency with discovery method + .git_exclude(true) // Respect git exclude for consistency + .ignore(true) // Respect ignore files for consistency + .follow_links(true) // Follow symlinks to ensure we find vendor libraries .max_depth(None) // No depth limit - .threads(num_cpus::get().max(4)) // Use optimal thread count for directory traversal - .same_file_system(true); // Don't cross filesystem boundaries for better performance + .threads(0) // Use all available threads for maximum performance + .same_file_system(false); // Cross filesystem boundaries to find all files - // Configure exclude globs if provided - for exclude_glob in &self.config.exclude_globs { - builder.add_custom_ignore_filename(exclude_glob); - } + // NOTE: We're not using exclude_globs for now to ensure 100% coverage + // TODO: Implement proper exclude glob filtering if needed later let walker: WalkParallel = builder.build_parallel(); let work_sender_clone = work_sender.clone(); let progress_sender_clone = progress_sender.clone(); let include_matcher_clone = include_matcher.clone(); let files_discovered_clone = files_discovered.clone(); + let total_files_attempted_clone = total_files_attempted.clone(); + let total_files_sent_clone = total_files_sent.clone(); + let total_files_failed_clone = total_files_failed.clone(); walker.run(|| { let work_sender = work_sender_clone.clone(); let progress_sender = progress_sender_clone.clone(); let include_matcher = include_matcher_clone.clone(); let files_discovered = files_discovered_clone.clone(); + let total_files_attempted = total_files_attempted_clone.clone(); + let total_files_sent = total_files_sent_clone.clone(); + let total_files_failed = total_files_failed_clone.clone(); Box::new(move |entry_result| { let entry = match entry_result { @@ -843,9 +928,20 @@ impl<'a> Scanner<'a> { } } - // Send file to work queue - if work_sender.send(path.to_path_buf()).is_err() { - return ignore::WalkState::Quit; + // Track file processing attempt + total_files_attempted.fetch_add(1, Ordering::Relaxed); + + // Send file to work queue with blocking send to ensure NO files are dropped + match work_sender.send(path.to_path_buf()) { + Ok(_) => { + // File sent successfully + total_files_sent.fetch_add(1, Ordering::Relaxed); + } + Err(crossbeam_channel::SendError(_)) => { + // Receiver has been dropped, log the failure and stop the walk + total_files_failed.fetch_add(1, Ordering::Relaxed); + return ignore::WalkState::Quit; + } } // Update discovered files counter atomically (no lock!) @@ -861,6 +957,11 @@ impl<'a> Scanner<'a> { }); } + // Log final statistics + let _attempted = total_files_attempted.load(Ordering::Relaxed); + let _sent = total_files_sent.load(Ordering::Relaxed); + let _failed = total_files_failed.load(Ordering::Relaxed); + Ok(()) } @@ -874,7 +975,6 @@ impl<'a> Scanner<'a> { const BATCH_SIZE: usize = 1000; // Process files in batches for better cache locality let mut batch = Vec::with_capacity(BATCH_SIZE); - let mut _processed_count = 0usize; // Collect files into batches and process them for path in work_receiver.iter() { @@ -882,41 +982,37 @@ impl<'a> Scanner<'a> { if batch.len() >= BATCH_SIZE { let (processed, findings) = self.process_batch(&batch, &findings_sender)?; - _processed_count += processed; + self.send_progress_updates(&progress_sender, processed, findings); batch.clear(); - - // Send processing progress update (2 = processing signal, repeated for batch size) - if let Some(ref progress_tx) = progress_sender { - for _ in 0..processed { - let _ = progress_tx.send(2); - } - // Send findings progress updates (3 = findings signal) - for _ in 0..findings { - let _ = progress_tx.send(3); - } - } } } // Process remaining files in the final batch if !batch.is_empty() { let (processed, findings) = self.process_batch(&batch, &findings_sender)?; - _processed_count += processed; - - if let Some(ref progress_tx) = progress_sender { - for _ in 0..processed { - let _ = progress_tx.send(2); - } - // Send findings progress updates (3 = findings signal) - for _ in 0..findings { - let _ = progress_tx.send(3); - } - } + self.send_progress_updates(&progress_sender, processed, findings); } Ok(()) } + /// Send progress updates for processed files and findings + fn send_progress_updates( + &self, + progress_sender: &Option>, + processed: usize, + findings: usize, + ) { + if let Some(ref progress_tx) = progress_sender { + for _ in 0..processed { + let _ = progress_tx.send(2); + } + for _ in 0..findings { + let _ = progress_tx.send(3); + } + } + } + /// Process a batch of files in parallel for better performance fn process_batch( &self, @@ -928,10 +1024,7 @@ impl<'a> Scanner<'a> { .par_iter() .map(|path| match self.scan_file(path, findings_sender) { Ok(findings_count) => findings_count, - Err(e) => { - eprintln!("Error scanning file {:?}: {}", path, e); - 0 - } + Err(_e) => 0, }) .collect(); @@ -990,8 +1083,14 @@ impl<'a> Scanner<'a> { // Drain emitter and forward findings to main channel drop(emitter.tx); // Close the emitter sender to stop receiving let mut findings_count = 0; + let mut symbols = Vec::new(); for finding in emitter.rx.iter() { - if findings_sender.send(finding).is_err() { + symbols.push(format!("{}:{}", finding.library, finding.symbol)); + if let Err(e) = findings_sender.send(finding) { + eprintln!( + "ERROR: Failed to send finding to main channel for {:?}: {:?}", + path, e + ); break; // Main receiver has been dropped, stop sending } findings_count += 1; @@ -1107,8 +1206,8 @@ impl<'a> Scanner<'a> { pub fn run(&self, roots: &[PathBuf]) -> Result> { // Create bounded channels for work queue and findings - const WORK_QUEUE_SIZE: usize = 10_000; // Backpressure management - const FINDINGS_QUEUE_SIZE: usize = 50_000; // Large buffer for findings + const WORK_QUEUE_SIZE: usize = 50_000; // Larger backpressure management for large codebases + const FINDINGS_QUEUE_SIZE: usize = 1_000_000; // MASSIVE buffer for findings to prevent any drops let (work_sender, work_receiver) = bounded::(WORK_QUEUE_SIZE); let (findings_sender, findings_receiver) = bounded::(FINDINGS_QUEUE_SIZE); @@ -1138,16 +1237,16 @@ impl<'a> Scanner<'a> { 1 => { // File discovered files_discovered += 1; - // Update callback every 1000 files discovered to reduce overhead - if files_discovered % 1000 == 0 { + // Update callback every 100 files discovered for better visibility + if files_discovered % 100 == 0 { callback(files_processed, files_discovered, findings_count); } } 2 => { // File processed files_processed += 1; - // Update callback every 500 files processed - if files_processed % 500 == 0 { + // Update callback every 50 files processed for better visibility + if files_processed % 50 == 0 { callback(files_processed, files_discovered, findings_count); } } @@ -1200,12 +1299,15 @@ impl<'a> Scanner<'a> { // Collect all findings let mut findings: Vec = Vec::new(); + for finding in findings_receiver.iter() { findings.push(finding); } // Wait for producer to complete - producer_handle.join().unwrap()?; + producer_handle + .join() + .map_err(|_| anyhow::anyhow!("Producer thread panicked"))??; // Check consumer result consumer_result?; @@ -1323,35 +1425,22 @@ impl PatternDetector { ) -> Result<()> { for lib in libs { // import/include/namespace first - let mut first_span = Span { line: 1, column: 1 }; - let mut first_symbol = String::new(); - let mut first_snippet = String::new(); - let mut matched_import = false; for re in lib.include.iter().chain(&lib.import).chain(&lib.namespace) { - if let Some(m) = re.find(stripped_s) { + if let Some(_m) = re.find(stripped_s) { matched_import = true; - first_span = index.to_line_col(m.start()); - first_symbol = re.as_str().to_string(); - first_snippet = extract_line(stripped_s, m.start()); break; } } - let mut api_hits = 0usize; - let mut last_api: Option<(usize, String)> = None; + + // Find ALL API matches, not just the last one + let mut api_matches: Vec<(usize, String)> = Vec::new(); for re in &lib.apis { - if let Some(m) = re.find(stripped_s) { - api_hits += 1; - last_api = Some((m.start(), re.as_str().to_string())); - } - } - if api_hits > 0 && first_symbol.is_empty() { - if let Some((pos, sym)) = last_api.clone() { - first_span = index.to_line_col(pos); - first_symbol = sym; - first_snippet = extract_line(stripped_s, pos); + for m in re.find_iter(stripped_s) { + api_matches.push((m.start(), m.as_str().to_string())); } } + // Require anchor only if patterns define any; always require at least one API hit let has_anchor_patterns = !lib.include.is_empty() || !lib.import.is_empty() || !lib.namespace.is_empty(); @@ -1360,18 +1449,23 @@ impl PatternDetector { } else { true }; - let should_report = anchor_satisfied && api_hits > 0; - if should_report { - let finding = Finding { - language: unit.lang, - library: lib.name.clone(), - file: unit.path.clone(), - span: first_span, - symbol: first_symbol, - snippet: first_snippet, - detector_id: self.id.to_string(), - }; - let _ = em.send(finding); + + // Generate a finding for each API match instead of just one per library + if anchor_satisfied && !api_matches.is_empty() { + for (pos, sym) in api_matches { + let span = index.to_line_col(pos); + let snippet = extract_line(stripped_s, pos); + let finding = Finding { + language: unit.lang, + library: lib.name.clone(), + file: unit.path.clone(), + span, + symbol: sym, + snippet, + detector_id: self.id.to_string(), + }; + let _ = em.send(finding); + } } } Ok(()) @@ -1397,6 +1491,7 @@ impl Detector for PatternDetector { substrings.insert(s.clone()); } } + // Note: We can't actually cache here due to &self, but this is still faster // than recomputing every time since we're using the cached language lookup Prefilter { diff --git a/fixtures/c/libsodium/aes-gcm/main.c b/fixtures/c/libsodium/aes-gcm/main.c new file mode 100644 index 0000000..55c3f67 --- /dev/null +++ b/fixtures/c/libsodium/aes-gcm/main.c @@ -0,0 +1,29 @@ +#include +#include + +int main() { + if (sodium_init() < 0) return 1; + + unsigned char key[crypto_aead_aes256gcm_KEYBYTES]; + unsigned char nonce[crypto_aead_aes256gcm_NPUBBYTES]; + unsigned char plaintext[] = "Hello, World!"; + unsigned char ciphertext[sizeof(plaintext) + crypto_aead_aes256gcm_ABYTES]; + unsigned char decrypted[sizeof(plaintext)]; + unsigned long long ciphertext_len, decrypted_len; + + // Generate key and nonce + crypto_aead_aes256gcm_keygen(key); + randombytes_buf(nonce, sizeof(nonce)); + + // Encrypt + crypto_aead_aes256gcm_encrypt(ciphertext, &ciphertext_len, + plaintext, sizeof(plaintext), + NULL, 0, NULL, nonce, key); + + // Decrypt + crypto_aead_aes256gcm_decrypt(decrypted, &decrypted_len, + NULL, ciphertext, ciphertext_len, + NULL, 0, nonce, key); + + return 0; +} diff --git a/fixtures/c/libsodium/aes-gcm/mv-cbom.json b/fixtures/c/libsodium/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..9a82df6 --- /dev/null +++ b/fixtures/c/libsodium/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "libsodium", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/libsodium/aes-gcm/main.c", + "detectorId": "algorithm-detector", + "line": 7, + "column": 23 + } + } + ] +} diff --git a/fixtures/c/libsodium/hmac-sha256/main.c b/fixtures/c/libsodium/hmac-sha256/main.c new file mode 100644 index 0000000..377bf30 --- /dev/null +++ b/fixtures/c/libsodium/hmac-sha256/main.c @@ -0,0 +1,20 @@ +#include + +int main() { + if (sodium_init() < 0) return 1; + + unsigned char key[crypto_auth_hmacsha256_KEYBYTES]; + unsigned char message[] = "Hello, World!"; + unsigned char mac[crypto_auth_hmacsha256_BYTES]; + + // Generate key + crypto_auth_hmacsha256_keygen(key); + + // Create HMAC + crypto_auth_hmacsha256(mac, message, sizeof(message), key); + + // Verify HMAC + int valid = crypto_auth_hmacsha256_verify(mac, message, sizeof(message), key); + + return valid; +} diff --git a/fixtures/c/libsodium/hmac-sha256/mv-cbom.json b/fixtures/c/libsodium/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..81a32df --- /dev/null +++ b/fixtures/c/libsodium/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "libsodium", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/libsodium/hmac-sha256/main.c", + "detectorId": "algorithm-detector", + "line": 6, + "column": 23 + } + } + ] +} diff --git a/fixtures/c/libsodium/rsa-sign/main.c b/fixtures/c/libsodium/rsa-sign/main.c new file mode 100644 index 0000000..76ff61c --- /dev/null +++ b/fixtures/c/libsodium/rsa-sign/main.c @@ -0,0 +1,26 @@ +#include + +int main() { + if (sodium_init() < 0) return 1; + + // Note: libsodium doesn't support RSA, using Ed25519 instead + unsigned char pk[crypto_sign_PUBLICKEYBYTES]; + unsigned char sk[crypto_sign_SECRETKEYBYTES]; + unsigned char message[] = "Hello, World!"; + unsigned char signed_message[crypto_sign_BYTES + sizeof(message)]; + unsigned char unsigned_message[sizeof(message)]; + unsigned long long signed_message_len, unsigned_message_len; + + // Generate key pair + crypto_sign_keypair(pk, sk); + + // Sign + crypto_sign(signed_message, &signed_message_len, + message, sizeof(message), sk); + + // Verify + int valid = crypto_sign_open(unsigned_message, &unsigned_message_len, + signed_message, signed_message_len, pk); + + return valid; +} diff --git a/fixtures/c/libsodium/rsa-sign/mv-cbom.json b/fixtures/c/libsodium/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..fbd3d5c --- /dev/null +++ b/fixtures/c/libsodium/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a0554bd2-5314-5ecc-aaaa-079002d1b3f9", + "assetType": "algorithm", + "name": "Ed25519", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "libsodium", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/libsodium/rsa-sign/main.c", + "detectorId": "algorithm-detector", + "line": 15, + "column": 5 + } + } + ] +} diff --git a/fixtures/c/libsodium/sha256/main.c b/fixtures/c/libsodium/sha256/main.c new file mode 100644 index 0000000..d22a0a2 --- /dev/null +++ b/fixtures/c/libsodium/sha256/main.c @@ -0,0 +1,12 @@ +#include + +int main() { + if (sodium_init() < 0) return 1; + + unsigned char message[] = "Hello, World!"; + unsigned char hash[crypto_hash_sha256_BYTES]; + + crypto_hash_sha256(hash, message, sizeof(message)); + + return 0; +} diff --git a/fixtures/c/libsodium/sha256/mv-cbom.json b/fixtures/c/libsodium/sha256/mv-cbom.json new file mode 100644 index 0000000..b7fd6d6 --- /dev/null +++ b/fixtures/c/libsodium/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "libsodium", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/libsodium/sha256/main.c", + "detectorId": "algorithm-detector", + "line": 7, + "column": 24 + } + } + ] +} diff --git a/fixtures/c/openssl/aes-gcm/main.c b/fixtures/c/openssl/aes-gcm/main.c new file mode 100644 index 0000000..d68d3de --- /dev/null +++ b/fixtures/c/openssl/aes-gcm/main.c @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() { + unsigned char key[32]; + unsigned char iv[12]; + unsigned char tag[16]; + unsigned char plaintext[] = "Hello, World!"; + unsigned char ciphertext[128]; + unsigned char decrypted[128]; + int len, ciphertext_len, decrypted_len; + + // Generate random key and IV + RAND_bytes(key, sizeof(key)); + RAND_bytes(iv, sizeof(iv)); + + // Encrypt + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv); + EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, strlen((char*)plaintext)); + ciphertext_len = len; + EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); + ciphertext_len += len; + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag); + + // Decrypt + EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv); + EVP_DecryptUpdate(ctx, decrypted, &len, ciphertext, ciphertext_len); + decrypted_len = len; + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag); + EVP_DecryptFinal_ex(ctx, decrypted + len, &len); + + EVP_CIPHER_CTX_free(ctx); + return 0; +} diff --git a/fixtures/c/openssl/aes-gcm/mv-cbom.json b/fixtures/c/openssl/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..bd46e06 --- /dev/null +++ b/fixtures/c/openssl/aes-gcm/mv-cbom.json @@ -0,0 +1,37 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a3672537-724a-5203-a125-5b9d3c0300da", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/openssl/aes-gcm/main.c", + "detectorId": "algorithm-detector", + "line": 20, + "column": 29 + } + } + ] +} diff --git a/fixtures/c/openssl/hmac-sha256/main.c b/fixtures/c/openssl/hmac-sha256/main.c new file mode 100644 index 0000000..5006817 --- /dev/null +++ b/fixtures/c/openssl/hmac-sha256/main.c @@ -0,0 +1,23 @@ +#include +#include + +int main() { + unsigned char key[] = "secret_key"; + unsigned char message[] = "Hello, World!"; + unsigned char mac[32]; + unsigned int mac_len; + + // Create HMAC + HMAC(EVP_sha256(), key, strlen((char*)key), + message, strlen((char*)message), + mac, &mac_len); + + // Verify HMAC (compare with expected) + unsigned char expected_mac[32]; + unsigned int expected_len; + HMAC(EVP_sha256(), key, strlen((char*)key), + message, strlen((char*)message), + expected_mac, &expected_len); + + return memcmp(mac, expected_mac, mac_len) == 0 ? 0 : 1; +} diff --git a/fixtures/c/openssl/hmac-sha256/mv-cbom.json b/fixtures/c/openssl/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..1b4d197 --- /dev/null +++ b/fixtures/c/openssl/hmac-sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "fixtures/c/openssl/hmac-sha256/main.c", + "detectorId": "detector-c", + "line": 11, + "column": 5 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "fixtures/c/openssl/hmac-sha256/main.c", + "detectorId": "detector-c", + "line": 11, + "column": 5 + } + } + ] +} diff --git a/fixtures/c/openssl/rsa-sign/main.c b/fixtures/c/openssl/rsa-sign/main.c new file mode 100644 index 0000000..54e2521 --- /dev/null +++ b/fixtures/c/openssl/rsa-sign/main.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +int main() { + unsigned char message[] = "Hello, World!"; + unsigned char signature[256]; + unsigned int sig_len; + + // Generate RSA key pair + EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + EVP_PKEY_keygen_init(kctx); + EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, 2048); + EVP_PKEY *pkey = NULL; + EVP_PKEY_keygen(kctx, &pkey); + EVP_PKEY_CTX_free(kctx); + + // Sign + EVP_MD_CTX *sctx = EVP_MD_CTX_new(); + EVP_SignInit(sctx, EVP_sha256()); + EVP_SignUpdate(sctx, message, strlen((char*)message)); + EVP_SignFinal(sctx, signature, &sig_len, pkey); + + // Verify + EVP_MD_CTX *vctx = EVP_MD_CTX_new(); + EVP_VerifyInit(vctx, EVP_sha256()); + EVP_VerifyUpdate(vctx, message, strlen((char*)message)); + int result = EVP_VerifyFinal(vctx, signature, sig_len, pkey); + + EVP_MD_CTX_free(sctx); + EVP_MD_CTX_free(vctx); + EVP_PKEY_free(pkey); + + return result == 1 ? 0 : 1; +} diff --git a/fixtures/c/openssl/rsa-sign/mv-cbom.json b/fixtures/c/openssl/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..8c03966 --- /dev/null +++ b/fixtures/c/openssl/rsa-sign/mv-cbom.json @@ -0,0 +1,53 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/openssl/rsa-sign/main.c", + "detectorId": "algorithm-detector", + "line": 21, + "column": 24 + } + }, + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "fixtures/c/openssl/rsa-sign/main.c", + "detectorId": "detector-c", + "line": 12, + "column": 26 + } + } + ] +} diff --git a/fixtures/c/openssl/sha256/main.c b/fixtures/c/openssl/sha256/main.c new file mode 100644 index 0000000..51cccc2 --- /dev/null +++ b/fixtures/c/openssl/sha256/main.c @@ -0,0 +1,16 @@ +#include +#include + +int main() { + unsigned char message[] = "Hello, World!"; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len; + + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); + EVP_DigestUpdate(ctx, message, strlen((char*)message)); + EVP_DigestFinal_ex(ctx, digest, &digest_len); + EVP_MD_CTX_free(ctx); + + return 0; +} diff --git a/fixtures/c/openssl/sha256/mv-cbom.json b/fixtures/c/openssl/sha256/mv-cbom.json new file mode 100644 index 0000000..3dc2fa3 --- /dev/null +++ b/fixtures/c/openssl/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/c/openssl/sha256/main.c", + "detectorId": "algorithm-detector", + "line": 10, + "column": 28 + } + } + ] +} diff --git a/fixtures/c/positive/main.c b/fixtures/c/positive/main.c deleted file mode 100644 index 80472d1..0000000 --- a/fixtures/c/positive/main.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -int main() { - EVP_MD_CTX *ctx = EVP_MD_CTX_new(); - printf("%p\n", (void*)ctx); - return 0; -} - diff --git a/fixtures/cpp/botan/aes-gcm/main.cpp b/fixtures/cpp/botan/aes-gcm/main.cpp new file mode 100644 index 0000000..4deeeab --- /dev/null +++ b/fixtures/cpp/botan/aes-gcm/main.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main() { + Botan::AutoSeeded_RNG rng; + + std::vector key(32); + std::vector iv(12); + rng.randomize(key.data(), key.size()); + rng.randomize(iv.data(), iv.size()); + + std::string plaintext = "Hello, World!"; + + // Encrypt + auto enc = Botan::AEAD_Mode::create("AES-256/GCM", Botan::ENCRYPTION); + enc->set_key(key); + enc->start(iv); + Botan::secure_vector ciphertext((uint8_t*)plaintext.data(), + (uint8_t*)plaintext.data() + plaintext.size()); + enc->finish(ciphertext); + + // Decrypt + auto dec = Botan::AEAD_Mode::create("AES-256/GCM", Botan::DECRYPTION); + dec->set_key(key); + dec->start(iv); + Botan::secure_vector decrypted = ciphertext; + dec->finish(decrypted); + + return 0; +} diff --git a/fixtures/cpp/botan/aes-gcm/mv-cbom.json b/fixtures/cpp/botan/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..9f301e0 --- /dev/null +++ b/fixtures/cpp/botan/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Botan", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/botan/aes-gcm/main.cpp", + "detectorId": "algorithm-detector", + "line": 17, + "column": 16 + } + } + ] +} diff --git a/fixtures/cpp/botan/hmac-sha256/main.cpp b/fixtures/cpp/botan/hmac-sha256/main.cpp new file mode 100644 index 0000000..88056df --- /dev/null +++ b/fixtures/cpp/botan/hmac-sha256/main.cpp @@ -0,0 +1,21 @@ +#include +#include +#include + +int main() { + std::string key = "secret_key"; + std::string message = "Hello, World!"; + + // Create HMAC + auto hmac = Botan::MessageAuthenticationCode::create("HMAC(SHA-256)"); + hmac->set_key((const uint8_t*)key.data(), key.size()); + hmac->update((const uint8_t*)message.data(), message.size()); + std::vector mac = hmac->final(); + + // Verify HMAC + hmac->set_key((const uint8_t*)key.data(), key.size()); + hmac->update((const uint8_t*)message.data(), message.size()); + bool valid = hmac->verify_mac(mac.data(), mac.size()); + + return valid ? 0 : 1; +} diff --git a/fixtures/cpp/botan/hmac-sha256/mv-cbom.json b/fixtures/cpp/botan/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..f249d48 --- /dev/null +++ b/fixtures/cpp/botan/hmac-sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Botan", + "evidence": { + "file": "fixtures/cpp/botan/hmac-sha256/main.cpp", + "detectorId": "detector-cpp", + "line": 10, + "column": 17 + } + }, + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/botan/hmac-sha256/main.cpp", + "detectorId": "algorithm-detector", + "line": 10, + "column": 59 + } + } + ] +} diff --git a/fixtures/cpp/botan/rsa-sign/main.cpp b/fixtures/cpp/botan/rsa-sign/main.cpp new file mode 100644 index 0000000..e845e2f --- /dev/null +++ b/fixtures/cpp/botan/rsa-sign/main.cpp @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +int main() { + Botan::AutoSeeded_RNG rng; + std::string message = "Hello, World!"; + + // Generate RSA key pair + Botan::RSA_PrivateKey private_key(rng, 2048); + + // Sign + Botan::PK_Signer signer(private_key, rng, "EMSA-PSS(SHA-256)"); + signer.update((const uint8_t*)message.data(), message.size()); + std::vector signature = signer.signature(rng); + + // Verify + Botan::PK_Verifier verifier(private_key, "EMSA-PSS(SHA-256)"); + verifier.update((const uint8_t*)message.data(), message.size()); + bool valid = verifier.check_signature(signature); + + return valid ? 0 : 1; +} diff --git a/fixtures/cpp/botan/rsa-sign/mv-cbom.json b/fixtures/cpp/botan/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..91f73ee --- /dev/null +++ b/fixtures/cpp/botan/rsa-sign/mv-cbom.json @@ -0,0 +1,72 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/botan/rsa-sign/main.cpp", + "detectorId": "algorithm-detector", + "line": 12, + "column": 12 + } + }, + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "Botan", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/botan/rsa-sign/main.cpp", + "detectorId": "algorithm-detector", + "line": 12, + "column": 5 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Botan", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/botan/rsa-sign/main.cpp", + "detectorId": "algorithm-detector", + "line": 15, + "column": 57 + } + } + ] +} diff --git a/fixtures/cpp/botan/sha256/main.cpp b/fixtures/cpp/botan/sha256/main.cpp new file mode 100644 index 0000000..efcfa51 --- /dev/null +++ b/fixtures/cpp/botan/sha256/main.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + std::string message = "Hello, World!"; + + auto hash = Botan::HashFunction::create("SHA-256"); + hash->update((const uint8_t*)message.data(), message.size()); + std::vector digest = hash->final(); + + return 0; +} diff --git a/fixtures/cpp/botan/sha256/mv-cbom.json b/fixtures/cpp/botan/sha256/mv-cbom.json new file mode 100644 index 0000000..cbd7485 --- /dev/null +++ b/fixtures/cpp/botan/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Botan", + "evidence": { + "file": "fixtures/cpp/botan/sha256/main.cpp", + "detectorId": "detector-cpp", + "line": 8, + "column": 17 + } + } + ] +} diff --git a/fixtures/cpp/cryptopp/aes-gcm/main.cpp b/fixtures/cpp/cryptopp/aes-gcm/main.cpp new file mode 100644 index 0000000..40abc9e --- /dev/null +++ b/fixtures/cpp/cryptopp/aes-gcm/main.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +int main() { + using namespace CryptoPP; + + byte key[AES::DEFAULT_KEYLENGTH]; + byte iv[AES::BLOCKSIZE]; + std::string plaintext = "Hello, World!"; + std::string ciphertext, decrypted; + + // Encrypt + GCM::Encryption encryptor; + encryptor.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); + StringSource(plaintext, true, + new AuthenticatedEncryptionFilter(encryptor, + new StringSink(ciphertext))); + + // Decrypt + GCM::Decryption decryptor; + decryptor.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); + StringSource(ciphertext, true, + new AuthenticatedDecryptionFilter(decryptor, + new StringSink(decrypted))); + + return 0; +} diff --git a/fixtures/cpp/cryptopp/aes-gcm/mv-cbom.json b/fixtures/cpp/cryptopp/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..a02d6f4 --- /dev/null +++ b/fixtures/cpp/cryptopp/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "c26548de-7898-5c93-8f20-08d3d70a7488", + "assetType": "algorithm", + "name": "AES", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Crypto++", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/aes-gcm/main.cpp", + "detectorId": "algorithm-detector", + "line": 15, + "column": 5 + } + } + ] +} diff --git a/fixtures/cpp/cryptopp/hmac-sha256/main.cpp b/fixtures/cpp/cryptopp/hmac-sha256/main.cpp new file mode 100644 index 0000000..e2d6c8d --- /dev/null +++ b/fixtures/cpp/cryptopp/hmac-sha256/main.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +int main() { + using namespace CryptoPP; + + std::string key = "secret_key"; + std::string message = "Hello, World!"; + byte mac[HMAC::DIGESTSIZE]; + + // Create HMAC + HMAC hmac((const byte*)key.data(), key.size()); + hmac.Update((const byte*)message.data(), message.size()); + hmac.Final(mac); + + // Verify HMAC + HMAC verifier((const byte*)key.data(), key.size()); + verifier.Update((const byte*)message.data(), message.size()); + bool valid = verifier.Verify(mac); + + return valid ? 0 : 1; +} diff --git a/fixtures/cpp/cryptopp/hmac-sha256/mv-cbom.json b/fixtures/cpp/cryptopp/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..c623572 --- /dev/null +++ b/fixtures/cpp/cryptopp/hmac-sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/hmac-sha256/main.cpp", + "detectorId": "algorithm-detector", + "line": 10, + "column": 19 + } + }, + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Crypto++", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/hmac-sha256/main.cpp", + "detectorId": "algorithm-detector", + "line": 10, + "column": 14 + } + } + ] +} diff --git a/fixtures/cpp/cryptopp/rsa-sign/main.cpp b/fixtures/cpp/cryptopp/rsa-sign/main.cpp new file mode 100644 index 0000000..26a9821 --- /dev/null +++ b/fixtures/cpp/cryptopp/rsa-sign/main.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +int main() { + using namespace CryptoPP; + + AutoSeededRandomPool rng; + std::string message = "Hello, World!"; + + // Generate RSA key pair + RSA::PrivateKey privateKey; + privateKey.GenerateRandomWithKeySize(rng, 2048); + RSA::PublicKey publicKey(privateKey); + + // Sign + RSASS::Signer signer(privateKey); + byte signature[signer.MaxSignatureLength()]; + size_t sigLen = signer.SignMessage(rng, + (const byte*)message.data(), message.size(), signature); + + // Verify + RSASS::Verifier verifier(publicKey); + bool valid = verifier.VerifyMessage( + (const byte*)message.data(), message.size(), + signature, sigLen); + + return valid ? 0 : 1; +} diff --git a/fixtures/cpp/cryptopp/rsa-sign/mv-cbom.json b/fixtures/cpp/cryptopp/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..cc0efc2 --- /dev/null +++ b/fixtures/cpp/cryptopp/rsa-sign/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/rsa-sign/main.cpp", + "detectorId": "algorithm-detector", + "line": 19, + "column": 16 + } + }, + { + "bom-ref": "cecdb684-a18f-57bd-9319-b2cfafe4d210", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "Crypto++", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/rsa-sign/main.cpp", + "detectorId": "algorithm-detector", + "line": 14, + "column": 5 + } + } + ] +} diff --git a/fixtures/cpp/cryptopp/sha256/main.cpp b/fixtures/cpp/cryptopp/sha256/main.cpp new file mode 100644 index 0000000..59143ba --- /dev/null +++ b/fixtures/cpp/cryptopp/sha256/main.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +int main() { + using namespace CryptoPP; + + std::string message = "Hello, World!"; + byte digest[SHA256::DIGESTSIZE]; + + SHA256 hash; + hash.Update((const byte*)message.data(), message.size()); + hash.Final(digest); + + return 0; +} diff --git a/fixtures/cpp/cryptopp/sha256/mv-cbom.json b/fixtures/cpp/cryptopp/sha256/mv-cbom.json new file mode 100644 index 0000000..96b7db0 --- /dev/null +++ b/fixtures/cpp/cryptopp/sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Crypto++", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/sha256/main.cpp", + "detectorId": "algorithm-detector", + "line": 9, + "column": 17 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/cryptopp/sha256/main.cpp", + "detectorId": "algorithm-detector", + "line": 9, + "column": 17 + } + } + ] +} diff --git a/fixtures/cpp/openssl/aes-gcm/main.cpp b/fixtures/cpp/openssl/aes-gcm/main.cpp new file mode 100644 index 0000000..3d62477 --- /dev/null +++ b/fixtures/cpp/openssl/aes-gcm/main.cpp @@ -0,0 +1,36 @@ +#include +#include + +int main() { + unsigned char key[32] = {0}; + unsigned char iv[12] = {0}; + unsigned char plaintext[] = "Hello, World!"; + unsigned char ciphertext[128]; + unsigned char tag[16]; + int len; + int ciphertext_len; + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + // Encrypt + EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); + EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, strlen((char*)plaintext)); + ciphertext_len = len; + EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); + ciphertext_len += len; + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag); + + // Decrypt + unsigned char decryptedtext[128]; + int decryptedtext_len; + EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv); + EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len); + decryptedtext_len = len; + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag); + EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len); + + EVP_CIPHER_CTX_free(ctx); + return 0; +} diff --git a/fixtures/cpp/openssl/aes-gcm/mv-cbom.json b/fixtures/cpp/openssl/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..e75bd84 --- /dev/null +++ b/fixtures/cpp/openssl/aes-gcm/mv-cbom.json @@ -0,0 +1,37 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a3672537-724a-5203-a125-5b9d3c0300da", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/openssl/aes-gcm/main.cpp", + "detectorId": "algorithm-detector", + "line": 16, + "column": 29 + } + } + ] +} diff --git a/fixtures/cpp/openssl/hmac-sha256/main.cpp b/fixtures/cpp/openssl/hmac-sha256/main.cpp new file mode 100644 index 0000000..5006817 --- /dev/null +++ b/fixtures/cpp/openssl/hmac-sha256/main.cpp @@ -0,0 +1,23 @@ +#include +#include + +int main() { + unsigned char key[] = "secret_key"; + unsigned char message[] = "Hello, World!"; + unsigned char mac[32]; + unsigned int mac_len; + + // Create HMAC + HMAC(EVP_sha256(), key, strlen((char*)key), + message, strlen((char*)message), + mac, &mac_len); + + // Verify HMAC (compare with expected) + unsigned char expected_mac[32]; + unsigned int expected_len; + HMAC(EVP_sha256(), key, strlen((char*)key), + message, strlen((char*)message), + expected_mac, &expected_len); + + return memcmp(mac, expected_mac, mac_len) == 0 ? 0 : 1; +} diff --git a/fixtures/cpp/openssl/hmac-sha256/mv-cbom.json b/fixtures/cpp/openssl/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..fe2511d --- /dev/null +++ b/fixtures/cpp/openssl/hmac-sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "fixtures/cpp/openssl/hmac-sha256/main.cpp", + "detectorId": "detector-cpp", + "line": 11, + "column": 5 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "fixtures/cpp/openssl/hmac-sha256/main.cpp", + "detectorId": "detector-cpp", + "line": 11, + "column": 5 + } + } + ] +} diff --git a/fixtures/cpp/openssl/rsa-sign/main.cpp b/fixtures/cpp/openssl/rsa-sign/main.cpp new file mode 100644 index 0000000..80397d5 --- /dev/null +++ b/fixtures/cpp/openssl/rsa-sign/main.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +int main() { + // Generate RSA key pair + RSA *rsa = RSA_new(); + BIGNUM *bn = BN_new(); + BN_set_word(bn, RSA_F4); + RSA_generate_key_ex(rsa, 2048, bn, NULL); + + unsigned char message[] = "Hello, World!"; + unsigned char hash[SHA256_DIGEST_LENGTH]; + + // Hash the message + SHA256(message, strlen((char*)message), hash); + + // Sign + unsigned char signature[256]; + unsigned int sig_len; + RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, + signature, &sig_len, rsa); + + // Verify + int valid = RSA_verify(NID_sha256, hash, SHA256_DIGEST_LENGTH, + signature, sig_len, rsa); + + RSA_free(rsa); + BN_free(bn); + + return valid ? 0 : 1; +} diff --git a/fixtures/cpp/openssl/rsa-sign/mv-cbom.json b/fixtures/cpp/openssl/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..d06dd05 --- /dev/null +++ b/fixtures/cpp/openssl/rsa-sign/mv-cbom.json @@ -0,0 +1,53 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "fixtures/cpp/openssl/rsa-sign/main.cpp", + "detectorId": "detector-cpp", + "line": 8, + "column": 16 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/openssl/rsa-sign/main.cpp", + "detectorId": "algorithm-detector", + "line": 14, + "column": 24 + } + } + ] +} diff --git a/fixtures/cpp/openssl/sha256/main.cpp b/fixtures/cpp/openssl/sha256/main.cpp new file mode 100644 index 0000000..51cccc2 --- /dev/null +++ b/fixtures/cpp/openssl/sha256/main.cpp @@ -0,0 +1,16 @@ +#include +#include + +int main() { + unsigned char message[] = "Hello, World!"; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len; + + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); + EVP_DigestUpdate(ctx, message, strlen((char*)message)); + EVP_DigestFinal_ex(ctx, digest, &digest_len); + EVP_MD_CTX_free(ctx); + + return 0; +} diff --git a/fixtures/cpp/openssl/sha256/mv-cbom.json b/fixtures/cpp/openssl/sha256/mv-cbom.json new file mode 100644 index 0000000..9df5ec7 --- /dev/null +++ b/fixtures/cpp/openssl/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/cpp/openssl/sha256/main.cpp", + "detectorId": "algorithm-detector", + "line": 10, + "column": 28 + } + } + ] +} diff --git a/fixtures/cpp/positive/main.cpp b/fixtures/cpp/positive/main.cpp deleted file mode 100644 index 73bfdbf..0000000 --- a/fixtures/cpp/positive/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -int main() { - std::cout << "CryptoPP:: AES" << std::endl; - return 0; -} - diff --git a/fixtures/erlang/otp-crypto/aes-gcm/main.erl b/fixtures/erlang/otp-crypto/aes-gcm/main.erl new file mode 100644 index 0000000..f016e98 --- /dev/null +++ b/fixtures/erlang/otp-crypto/aes-gcm/main.erl @@ -0,0 +1,14 @@ +-module(main). +-export([main/0]). + +main() -> + Key = crypto:strong_rand_bytes(32), + IV = crypto:strong_rand_bytes(12), + Plaintext = <<"Hello, World!">>, + + % Encrypt + {Ciphertext, Tag} = crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, Plaintext, <<>>, true), + + % Decrypt + Decrypted = crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, Ciphertext, <<>>, Tag, false), + ok. diff --git a/fixtures/erlang/otp-crypto/aes-gcm/mv-cbom.json b/fixtures/erlang/otp-crypto/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..b53bb35 --- /dev/null +++ b/fixtures/erlang/otp-crypto/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "c26548de-7898-5c93-8f20-08d3d70a7488", + "assetType": "algorithm", + "name": "AES", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Erlang/OTP crypto", + "evidence": { + "file": "fixtures/erlang/otp-crypto/aes-gcm/main.erl", + "detectorId": "detector-erlang", + "line": 10, + "column": 25 + } + } + ] +} diff --git a/fixtures/erlang/otp-crypto/hmac-sha256/main.erl b/fixtures/erlang/otp-crypto/hmac-sha256/main.erl new file mode 100644 index 0000000..3ba1eb9 --- /dev/null +++ b/fixtures/erlang/otp-crypto/hmac-sha256/main.erl @@ -0,0 +1,14 @@ +-module(main). +-export([main/0]). + +main() -> + Key = <<"secret_key">>, + Message = <<"Hello, World!">>, + + % Create HMAC + Mac = crypto:mac(hmac, sha256, Key, Message), + + % Verify HMAC (compare with expected) + ExpectedMac = crypto:mac(hmac, sha256, Key, Message), + Mac = ExpectedMac, + ok. diff --git a/fixtures/erlang/otp-crypto/hmac-sha256/mv-cbom.json b/fixtures/erlang/otp-crypto/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..cc65f6b --- /dev/null +++ b/fixtures/erlang/otp-crypto/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Erlang/OTP crypto", + "evidence": { + "file": "fixtures/erlang/otp-crypto/hmac-sha256/main.erl", + "detectorId": "detector-erlang", + "line": 9, + "column": 11 + } + } + ] +} diff --git a/fixtures/erlang/otp-crypto/rsa-sign/main.erl b/fixtures/erlang/otp-crypto/rsa-sign/main.erl new file mode 100644 index 0000000..9c4eeec --- /dev/null +++ b/fixtures/erlang/otp-crypto/rsa-sign/main.erl @@ -0,0 +1,15 @@ +-module(main). +-export([main/0]). + +main() -> + Message = <<"Hello, World!">>, + + % Generate RSA key pair + {PublicKey, PrivateKey} = crypto:generate_key(rsa, {2048, 65537}), + + % Sign + Signature = crypto:sign(rsa, sha256, Message, PrivateKey), + + % Verify + true = crypto:verify(rsa, sha256, Message, Signature, PublicKey), + ok. diff --git a/fixtures/erlang/otp-crypto/rsa-sign/mv-cbom.json b/fixtures/erlang/otp-crypto/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..39d6290 --- /dev/null +++ b/fixtures/erlang/otp-crypto/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Erlang/OTP crypto", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/erlang/otp-crypto/rsa-sign/main.erl", + "detectorId": "algorithm-detector", + "line": 11, + "column": 34 + } + } + ] +} diff --git a/fixtures/erlang/otp-crypto/sha256/main.erl b/fixtures/erlang/otp-crypto/sha256/main.erl new file mode 100644 index 0000000..91c70b5 --- /dev/null +++ b/fixtures/erlang/otp-crypto/sha256/main.erl @@ -0,0 +1,7 @@ +-module(main). +-export([main/0]). + +main() -> + Message = <<"Hello, World!">>, + Hash = crypto:hash(sha256, Message), + ok. diff --git a/fixtures/erlang/otp-crypto/sha256/mv-cbom.json b/fixtures/erlang/otp-crypto/sha256/mv-cbom.json new file mode 100644 index 0000000..a44298c --- /dev/null +++ b/fixtures/erlang/otp-crypto/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Erlang/OTP crypto", + "evidence": { + "file": "fixtures/erlang/otp-crypto/sha256/main.erl", + "detectorId": "detector-erlang", + "line": 6, + "column": 12 + } + } + ] +} diff --git a/fixtures/erlang/positive/main.erl b/fixtures/erlang/positive/main.erl deleted file mode 100644 index d70e3e8..0000000 --- a/fixtures/erlang/positive/main.erl +++ /dev/null @@ -1,24 +0,0 @@ --module(main). --export([main/0]). - --include_lib("public_key/include/public_key.hrl"). - -main() -> - % Test Erlang/OTP crypto module - Key = crypto:generate_key(des3, 24), - Hash = crypto:hash(sha256, "hello world"), - Cipher = crypto:block_encrypt(aes_256_cbc, Key, "plaintext"), - - % Test public_key module - {ok, Pem} = public_key:pem_decode(<<"-----BEGIN PRIVATE KEY-----">>), - Signature = public_key:sign("data", sha256, Pem), - - % Test enacl (libsodium) if available - {PublicKey, SecretKey} = enacl:box_keypair(), - Nonce = enacl:randombytes(12), - Ciphertext = enacl:box("message", Nonce, PublicKey, SecretKey), - - % Test bcrypt - Hash2 = bcrypt:hashpw("password", bcrypt:gen_salt()), - - io:format("Crypto operations completed~n"). diff --git a/fixtures/general/c/main.c b/fixtures/general/c/main.c new file mode 100644 index 0000000..59ba844 --- /dev/null +++ b/fixtures/general/c/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + EVP_sha256(); + return 0; +} diff --git a/fixtures/general/erlang/app.erl b/fixtures/general/erlang/app.erl new file mode 100644 index 0000000..05f515e --- /dev/null +++ b/fixtures/general/erlang/app.erl @@ -0,0 +1,5 @@ +-module(app). +-export([main/0]). + +main() -> + crypto:hash(sha256, <<"hi">>). diff --git a/fixtures/general/go/main.go b/fixtures/general/go/main.go new file mode 100644 index 0000000..e8be209 --- /dev/null +++ b/fixtures/general/go/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "crypto/aes" + "crypto/cipher" +) + +func main() { + block, _ := aes.NewCipher(make([]byte, 16)) + cipher.NewGCM(block) +} diff --git a/fixtures/general/java/Main.java b/fixtures/general/java/Main.java new file mode 100644 index 0000000..0431b24 --- /dev/null +++ b/fixtures/general/java/Main.java @@ -0,0 +1,11 @@ +package fixtures.general.java; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; + +public class Main { + public static void main(String[] args) throws Exception { + KeyGenerator.getInstance("AES"); + Cipher.getInstance("AES/GCM/NoPadding"); + } +} diff --git a/fixtures/general/kotlin/Main.kt b/fixtures/general/kotlin/Main.kt new file mode 100644 index 0000000..0cc7a10 --- /dev/null +++ b/fixtures/general/kotlin/Main.kt @@ -0,0 +1,7 @@ +package fixtures.general.kotlin + +import javax.crypto.Cipher + +fun main() { + Cipher.getInstance("AES/GCM/NoPadding") +} diff --git a/fixtures/general/objc/App.m b/fixtures/general/objc/App.m new file mode 100644 index 0000000..4d02ed8 --- /dev/null +++ b/fixtures/general/objc/App.m @@ -0,0 +1,6 @@ +#import + +int main() { + CC_SHA256(NULL, 0, NULL); + return 0; +} diff --git a/fixtures/general/php/index.php b/fixtures/general/php/index.php new file mode 100644 index 0000000..e9867cc --- /dev/null +++ b/fixtures/general/php/index.php @@ -0,0 +1,2 @@ + -/* EVP_MD_CTX *ctx = EVP_MD_CTX_new(); */ -int main() { return 0; } - diff --git a/fixtures/objc/commoncrypto/aes-gcm/main.m b/fixtures/objc/commoncrypto/aes-gcm/main.m new file mode 100644 index 0000000..c39c0ae --- /dev/null +++ b/fixtures/objc/commoncrypto/aes-gcm/main.m @@ -0,0 +1,39 @@ +#import +#import + +int main() { + @autoreleasepool { + // Note: CommonCrypto doesn't have native GCM support, using CBC as fallback + uint8_t key[kCCKeySizeAES256]; + uint8_t iv[kCCBlockSizeAES128]; + arc4random_buf(key, sizeof(key)); + arc4random_buf(iv, sizeof(iv)); + + NSData *plaintext = [@"Hello, World!" dataUsingEncoding:NSUTF8StringEncoding]; + + // Encrypt + size_t bufferSize = plaintext.length + kCCBlockSizeAES128; + void *buffer = malloc(bufferSize); + size_t numBytesEncrypted = 0; + + CCCrypt(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, + key, kCCKeySizeAES256, iv, + plaintext.bytes, plaintext.length, + buffer, bufferSize, &numBytesEncrypted); + + NSData *ciphertext = [NSData dataWithBytes:buffer length:numBytesEncrypted]; + + // Decrypt + void *decryptedBuffer = malloc(bufferSize); + size_t numBytesDecrypted = 0; + + CCCrypt(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, + key, kCCKeySizeAES256, iv, + ciphertext.bytes, ciphertext.length, + decryptedBuffer, bufferSize, &numBytesDecrypted); + + free(buffer); + free(decryptedBuffer); + } + return 0; +} diff --git a/fixtures/objc/commoncrypto/aes-gcm/mv-cbom.json b/fixtures/objc/commoncrypto/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..e625b7c --- /dev/null +++ b/fixtures/objc/commoncrypto/aes-gcm/mv-cbom.json @@ -0,0 +1,37 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a3b07d70-9ea0-5714-9112-b9c5c40745dd", + "assetType": "algorithm", + "name": "AES", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "mode": "CBC" + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CommonCrypto (Objective-C)", + "evidence": { + "file": "fixtures/objc/commoncrypto/aes-gcm/main.m", + "detectorId": "detector-objc", + "line": 19, + "column": 9 + } + } + ] +} diff --git a/fixtures/objc/commoncrypto/hmac-sha256/main.m b/fixtures/objc/commoncrypto/hmac-sha256/main.m new file mode 100644 index 0000000..a55e5ae --- /dev/null +++ b/fixtures/objc/commoncrypto/hmac-sha256/main.m @@ -0,0 +1,14 @@ +#import +#import + +int main() { + @autoreleasepool { + NSData *key = [@"secret_key" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *message = [@"Hello, World!" dataUsingEncoding:NSUTF8StringEncoding]; + uint8_t mac[CC_SHA256_DIGEST_LENGTH]; + + CCHmac(kCCHmacAlgSHA256, key.bytes, key.length, + message.bytes, message.length, mac); + } + return 0; +} diff --git a/fixtures/objc/commoncrypto/hmac-sha256/mv-cbom.json b/fixtures/objc/commoncrypto/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..e4dc6bc --- /dev/null +++ b/fixtures/objc/commoncrypto/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CommonCrypto (Objective-C)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/objc/commoncrypto/hmac-sha256/main.m", + "detectorId": "algorithm-detector", + "line": 8, + "column": 21 + } + } + ] +} diff --git a/fixtures/objc/commoncrypto/rsa-sign/main.m b/fixtures/objc/commoncrypto/rsa-sign/main.m new file mode 100644 index 0000000..8ad6cf6 --- /dev/null +++ b/fixtures/objc/commoncrypto/rsa-sign/main.m @@ -0,0 +1,39 @@ +#import +#import + +int main() { + @autoreleasepool { + NSData *message = [@"Hello, World!" dataUsingEncoding:NSUTF8StringEncoding]; + + // Generate RSA key pair + NSDictionary *parameters = @{ + (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA, + (__bridge id)kSecAttrKeySizeInBits: @2048 + }; + + SecKeyRef privateKey, publicKey; + SecKeyGeneratePair((__bridge CFDictionaryRef)parameters, &publicKey, &privateKey); + + // Sign + CFErrorRef error = NULL; + NSData *signature = (__bridge_transfer NSData *)SecKeyCreateSignature( + privateKey, + kSecKeyAlgorithmRSASignatureMessagePSSSHA256, + (__bridge CFDataRef)message, + &error + ); + + // Verify + Boolean valid = SecKeyVerifySignature( + publicKey, + kSecKeyAlgorithmRSASignatureMessagePSSSHA256, + (__bridge CFDataRef)message, + (__bridge CFDataRef)signature, + &error + ); + + CFRelease(privateKey); + CFRelease(publicKey); + } + return 0; +} diff --git a/fixtures/objc/commoncrypto/rsa-sign/mv-cbom.json b/fixtures/objc/commoncrypto/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..203a776 --- /dev/null +++ b/fixtures/objc/commoncrypto/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "cecdb684-a18f-57bd-9319-b2cfafe4d210", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "Security.framework (Objective-C)", + "evidence": { + "file": "fixtures/objc/commoncrypto/rsa-sign/main.m", + "detectorId": "detector-objc", + "line": 10, + "column": 26 + } + } + ] +} diff --git a/fixtures/objc/commoncrypto/sha256/main.m b/fixtures/objc/commoncrypto/sha256/main.m new file mode 100644 index 0000000..17b996a --- /dev/null +++ b/fixtures/objc/commoncrypto/sha256/main.m @@ -0,0 +1,12 @@ +#import +#import + +int main() { + @autoreleasepool { + NSData *message = [@"Hello, World!" dataUsingEncoding:NSUTF8StringEncoding]; + uint8_t digest[CC_SHA256_DIGEST_LENGTH]; + + CC_SHA256(message.bytes, (CC_LONG)message.length, digest); + } + return 0; +} diff --git a/fixtures/objc/commoncrypto/sha256/mv-cbom.json b/fixtures/objc/commoncrypto/sha256/mv-cbom.json new file mode 100644 index 0000000..1a17f62 --- /dev/null +++ b/fixtures/objc/commoncrypto/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CommonCrypto (Objective-C)", + "evidence": { + "file": "fixtures/objc/commoncrypto/sha256/main.m", + "detectorId": "detector-objc", + "line": 9, + "column": 9 + } + } + ] +} diff --git a/fixtures/objc/openssl/aes-gcm/main.m b/fixtures/objc/openssl/aes-gcm/main.m new file mode 100644 index 0000000..5f38fd8 --- /dev/null +++ b/fixtures/objc/openssl/aes-gcm/main.m @@ -0,0 +1,25 @@ +#import +#include + +int main() { + unsigned char key[32] = {0}; + unsigned char iv[12] = {0}; + unsigned char plaintext[] = "Hello, World!"; + unsigned char ciphertext[128]; + unsigned char tag[16]; + int len; + int ciphertext_len; + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + // Encrypt + EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); + EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, strlen((char*)plaintext)); + ciphertext_len = len; + EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag); + + EVP_CIPHER_CTX_free(ctx); + return 0; +} diff --git a/fixtures/objc/openssl/aes-gcm/mv-cbom.json b/fixtures/objc/openssl/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..332cfc6 --- /dev/null +++ b/fixtures/objc/openssl/aes-gcm/mv-cbom.json @@ -0,0 +1,56 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "94b13c81-438e-5c40-8ba6-69a3415fc269", + "assetType": "algorithm", + "name": "AES", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (Objective-C)", + "evidence": { + "file": "fixtures/objc/openssl/aes-gcm/main.m", + "detectorId": "detector-objc", + "line": 13, + "column": 27 + } + }, + { + "bom-ref": "a3672537-724a-5203-a125-5b9d3c0300da", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (Objective-C)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/objc/openssl/aes-gcm/main.m", + "detectorId": "algorithm-detector", + "line": 16, + "column": 29 + } + } + ] +} diff --git a/fixtures/objc/openssl/hmac-sha256/main.m b/fixtures/objc/openssl/hmac-sha256/main.m new file mode 100644 index 0000000..c936aaf --- /dev/null +++ b/fixtures/objc/openssl/hmac-sha256/main.m @@ -0,0 +1,16 @@ +#import +#include + +int main() { + unsigned char key[] = "secret_key"; + unsigned char message[] = "Hello, World!"; + unsigned char mac[32]; + unsigned int mac_len; + + // Create HMAC + HMAC(EVP_sha256(), key, strlen((char*)key), + message, strlen((char*)message), + mac, &mac_len); + + return 0; +} diff --git a/fixtures/objc/openssl/hmac-sha256/mv-cbom.json b/fixtures/objc/openssl/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..793ba22 --- /dev/null +++ b/fixtures/objc/openssl/hmac-sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (Objective-C)", + "evidence": { + "file": "fixtures/objc/openssl/hmac-sha256/main.m", + "detectorId": "detector-objc", + "line": 11, + "column": 10 + } + }, + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (Objective-C)", + "evidence": { + "file": "fixtures/objc/openssl/hmac-sha256/main.m", + "detectorId": "detector-objc", + "line": 11, + "column": 10 + } + } + ] +} diff --git a/fixtures/objc/openssl/rsa-sign/main.m b/fixtures/objc/openssl/rsa-sign/main.m new file mode 100644 index 0000000..4134cdb --- /dev/null +++ b/fixtures/objc/openssl/rsa-sign/main.m @@ -0,0 +1,33 @@ +#import +#include +#include +#include + +int main() { + // Generate RSA key pair + RSA *rsa = RSA_new(); + BIGNUM *bn = BN_new(); + BN_set_word(bn, RSA_F4); + RSA_generate_key_ex(rsa, 2048, bn, NULL); + + unsigned char message[] = "Hello, World!"; + unsigned char hash[SHA256_DIGEST_LENGTH]; + + // Hash the message + SHA256(message, strlen((char*)message), hash); + + // Sign + unsigned char signature[256]; + unsigned int sig_len; + RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, + signature, &sig_len, rsa); + + // Verify + int valid = RSA_verify(NID_sha256, hash, SHA256_DIGEST_LENGTH, + signature, sig_len, rsa); + + RSA_free(rsa); + BN_free(bn); + + return valid ? 0 : 1; +} diff --git a/fixtures/objc/openssl/rsa-sign/mv-cbom.json b/fixtures/objc/openssl/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..0712b9b --- /dev/null +++ b/fixtures/objc/openssl/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "cecdb684-a18f-57bd-9319-b2cfafe4d210", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "OpenSSL (Objective-C)", + "evidence": { + "file": "fixtures/objc/openssl/rsa-sign/main.m", + "detectorId": "detector-objc", + "line": 8, + "column": 16 + } + } + ] +} diff --git a/fixtures/objc/openssl/sha256/main.m b/fixtures/objc/openssl/sha256/main.m new file mode 100644 index 0000000..e319707 --- /dev/null +++ b/fixtures/objc/openssl/sha256/main.m @@ -0,0 +1,16 @@ +#import +#include + +int main() { + unsigned char message[] = "Hello, World!"; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len; + + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); + EVP_DigestUpdate(ctx, message, strlen((char*)message)); + EVP_DigestFinal_ex(ctx, digest, &digest_len); + EVP_MD_CTX_free(ctx); + + return 0; +} diff --git a/fixtures/objc/openssl/sha256/mv-cbom.json b/fixtures/objc/openssl/sha256/mv-cbom.json new file mode 100644 index 0000000..d7e9064 --- /dev/null +++ b/fixtures/objc/openssl/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (Objective-C)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/objc/openssl/sha256/main.m", + "detectorId": "algorithm-detector", + "line": 10, + "column": 28 + } + } + ] +} diff --git a/fixtures/objc/positive/main.m b/fixtures/objc/positive/main.m deleted file mode 100644 index 50c9b40..0000000 --- a/fixtures/objc/positive/main.m +++ /dev/null @@ -1,38 +0,0 @@ -#import -#import -#import -#import - -int main(int argc, const char * argv[]) { - @autoreleasepool { - // CommonCrypto usage - const char *message = "Hello, World!"; - unsigned char digest[CC_SHA256_DIGEST_LENGTH]; - - CC_SHA256(message, (CC_LONG)strlen(message), digest); - - printf("SHA256: "); - for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { - printf("%02x", digest[i]); - } - printf("\n"); - - // OpenSSL usage - EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); - const EVP_MD *md = EVP_sha256(); - - EVP_DigestInit_ex(mdctx, md, NULL); - EVP_DigestUpdate(mdctx, message, strlen(message)); - - unsigned int digest_len; - EVP_DigestFinal_ex(mdctx, digest, &digest_len); - EVP_MD_CTX_free(mdctx); - - printf("OpenSSL SHA256: "); - for (unsigned int i = 0; i < digest_len; i++) { - printf("%02x", digest[i]); - } - printf("\n"); - } - return 0; -} diff --git a/fixtures/php/openssl/aes-gcm/main.php b/fixtures/php/openssl/aes-gcm/main.php new file mode 100644 index 0000000..a2077d8 --- /dev/null +++ b/fixtures/php/openssl/aes-gcm/main.php @@ -0,0 +1,11 @@ + diff --git a/fixtures/php/openssl/aes-gcm/mv-cbom.json b/fixtures/php/openssl/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..c25a471 --- /dev/null +++ b/fixtures/php/openssl/aes-gcm/mv-cbom.json @@ -0,0 +1,38 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "cff84d12-395c-5d01-a006-a96dd6984fd4", + "assetType": "algorithm", + "name": "AES", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256, + "mode": "cbc" + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (PHP)", + "evidence": { + "file": "fixtures/php/openssl/aes-gcm/main.php", + "detectorId": "detector-php", + "line": 7, + "column": 15 + } + } + ] +} diff --git a/fixtures/php/openssl/hmac-sha256/main.php b/fixtures/php/openssl/hmac-sha256/main.php new file mode 100644 index 0000000..81c429b --- /dev/null +++ b/fixtures/php/openssl/hmac-sha256/main.php @@ -0,0 +1,11 @@ + diff --git a/fixtures/php/openssl/hmac-sha256/mv-cbom.json b/fixtures/php/openssl/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..6288651 --- /dev/null +++ b/fixtures/php/openssl/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (PHP)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/php/openssl/hmac-sha256/main.php", + "detectorId": "algorithm-detector", + "line": 6, + "column": 8 + } + } + ] +} diff --git a/fixtures/php/openssl/rsa-sign/main.php b/fixtures/php/openssl/rsa-sign/main.php new file mode 100644 index 0000000..9a706ce --- /dev/null +++ b/fixtures/php/openssl/rsa-sign/main.php @@ -0,0 +1,18 @@ + 2048, + "private_key_type" => OPENSSL_KEYTYPE_RSA, +); +$keyPair = openssl_pkey_new($config); +openssl_pkey_export($keyPair, $privateKey); +$publicKey = openssl_pkey_get_details($keyPair)['key']; + +// Sign +openssl_sign($message, $signature, $privateKey, OPENSSL_ALGO_SHA256); + +// Verify +$valid = openssl_verify($message, $signature, $publicKey, OPENSSL_ALGO_SHA256); +?> diff --git a/fixtures/php/openssl/rsa-sign/mv-cbom.json b/fixtures/php/openssl/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..561a6d0 --- /dev/null +++ b/fixtures/php/openssl/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "cecdb684-a18f-57bd-9319-b2cfafe4d210", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "OpenSSL (PHP)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/php/openssl/rsa-sign/main.php", + "detectorId": "algorithm-detector", + "line": 14, + "column": 1 + } + } + ] +} diff --git a/fixtures/php/openssl/sha256/main.php b/fixtures/php/openssl/sha256/main.php new file mode 100644 index 0000000..a8384d3 --- /dev/null +++ b/fixtures/php/openssl/sha256/main.php @@ -0,0 +1,5 @@ + diff --git a/fixtures/php/openssl/sha256/mv-cbom.json b/fixtures/php/openssl/sha256/mv-cbom.json new file mode 100644 index 0000000..165742a --- /dev/null +++ b/fixtures/php/openssl/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "OpenSSL (PHP)", + "evidence": { + "file": "fixtures/php/openssl/sha256/main.php", + "detectorId": "detector-php", + "line": 4, + "column": 9 + } + } + ] +} diff --git a/fixtures/php/positive/main.php b/fixtures/php/positive/main.php deleted file mode 100644 index e952a7c..0000000 --- a/fixtures/php/positive/main.php +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/fixtures/php/sodium/aes-gcm/mv-cbom.json b/fixtures/php/sodium/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..fcf315a --- /dev/null +++ b/fixtures/php/sodium/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "4402c389-c58f-505b-8fd0-59d776d2fbd4", + "assetType": "algorithm", + "name": "ChaCha20Poly1305", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Sodium (PHP)", + "evidence": { + "file": "fixtures/php/sodium/aes-gcm/main.php", + "detectorId": "detector-php", + "line": 3, + "column": 8 + } + } + ] +} diff --git a/fixtures/php/sodium/hmac-sha256/main.php b/fixtures/php/sodium/hmac-sha256/main.php new file mode 100644 index 0000000..4be821c --- /dev/null +++ b/fixtures/php/sodium/hmac-sha256/main.php @@ -0,0 +1,10 @@ + diff --git a/fixtures/php/sodium/hmac-sha256/mv-cbom.json b/fixtures/php/sodium/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..08b887f --- /dev/null +++ b/fixtures/php/sodium/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "ce63d075-50f6-59f5-a264-92b65d42a29e", + "assetType": "algorithm", + "name": "HMAC-SHA512-256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Sodium (PHP)", + "evidence": { + "file": "fixtures/php/sodium/hmac-sha256/main.php", + "detectorId": "detector-php", + "line": 2, + "column": 8 + } + } + ] +} diff --git a/fixtures/php/sodium/rsa-sign/main.php b/fixtures/php/sodium/rsa-sign/main.php new file mode 100644 index 0000000..a438b9c --- /dev/null +++ b/fixtures/php/sodium/rsa-sign/main.php @@ -0,0 +1,14 @@ + diff --git a/fixtures/php/sodium/rsa-sign/mv-cbom.json b/fixtures/php/sodium/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..e383009 --- /dev/null +++ b/fixtures/php/sodium/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a0554bd2-5314-5ecc-aaaa-079002d1b3f9", + "assetType": "algorithm", + "name": "Ed25519", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "Sodium (PHP)", + "evidence": { + "file": "fixtures/php/sodium/rsa-sign/main.php", + "detectorId": "detector-php", + "line": 3, + "column": 12 + } + } + ] +} diff --git a/fixtures/php/sodium/sha256/main.php b/fixtures/php/sodium/sha256/main.php new file mode 100644 index 0000000..f62705e --- /dev/null +++ b/fixtures/php/sodium/sha256/main.php @@ -0,0 +1,6 @@ + diff --git a/fixtures/php/sodium/sha256/mv-cbom.json b/fixtures/php/sodium/sha256/mv-cbom.json new file mode 100644 index 0000000..4e00d51 --- /dev/null +++ b/fixtures/php/sodium/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fc50b831-e3ed-55ae-8328-263054296b71", + "assetType": "algorithm", + "name": "BLAKE2b", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Sodium (PHP)", + "evidence": { + "file": "fixtures/php/sodium/sha256/main.php", + "detectorId": "detector-php", + "line": 5, + "column": 9 + } + } + ] +} diff --git a/fixtures/python/cryptography/aes-gcm/main.py b/fixtures/python/cryptography/aes-gcm/main.py new file mode 100644 index 0000000..5355637 --- /dev/null +++ b/fixtures/python/cryptography/aes-gcm/main.py @@ -0,0 +1,18 @@ +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend +import os + +# Generate key and nonce +key = os.urandom(32) +nonce = os.urandom(12) +plaintext = b"Hello, World!" + +# Encrypt +cipher = Cipher(algorithms.AES(key), modes.GCM(nonce), backend=default_backend()) +encryptor = cipher.encryptor() +ciphertext = encryptor.update(plaintext) + encryptor.finalize() +tag = encryptor.tag + +# Decrypt +decryptor = Cipher(algorithms.AES(key), modes.GCM(nonce, tag), backend=default_backend()).decryptor() +decrypted = decryptor.update(ciphertext) + decryptor.finalize() diff --git a/fixtures/python/cryptography/aes-gcm/mv-cbom.json b/fixtures/python/cryptography/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..0b90539 --- /dev/null +++ b/fixtures/python/cryptography/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "fixtures/python/cryptography/aes-gcm/main.py", + "detectorId": "detector-python", + "line": 11, + "column": 28 + } + } + ] +} diff --git a/fixtures/python/cryptography/hmac-sha256/main.py b/fixtures/python/cryptography/hmac-sha256/main.py new file mode 100644 index 0000000..2081462 --- /dev/null +++ b/fixtures/python/cryptography/hmac-sha256/main.py @@ -0,0 +1,15 @@ +from cryptography.hazmat.primitives import hashes, hmac +from cryptography.hazmat.backends import default_backend + +key = b"secret_key" +message = b"Hello, World!" + +# Create HMAC +h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) +h.update(message) +mac = h.finalize() + +# Verify HMAC +h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) +h.update(message) +h.verify(mac) # Raises exception if invalid diff --git a/fixtures/python/cryptography/hmac-sha256/mv-cbom.json b/fixtures/python/cryptography/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..5c7f48a --- /dev/null +++ b/fixtures/python/cryptography/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/cryptography/hmac-sha256/main.py", + "detectorId": "algorithm-detector", + "line": 8, + "column": 20 + } + } + ] +} diff --git a/fixtures/python/cryptography/rsa-sign/main.py b/fixtures/python/cryptography/rsa-sign/main.py new file mode 100644 index 0000000..d932e21 --- /dev/null +++ b/fixtures/python/cryptography/rsa-sign/main.py @@ -0,0 +1,34 @@ +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends import default_backend + +message = b"Hello, World!" + +# Generate RSA key pair +private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + backend=default_backend() +) +public_key = private_key.public_key() + +# Sign +signature = private_key.sign( + message, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() +) + +# Verify +public_key.verify( + signature, + message, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() +) diff --git a/fixtures/python/cryptography/rsa-sign/mv-cbom.json b/fixtures/python/cryptography/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..6c85a7e --- /dev/null +++ b/fixtures/python/cryptography/rsa-sign/mv-cbom.json @@ -0,0 +1,53 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/cryptography/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 8, + "column": 15 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/cryptography/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 19, + "column": 26 + } + } + ] +} diff --git a/fixtures/python/cryptography/sha256/main.py b/fixtures/python/cryptography/sha256/main.py new file mode 100644 index 0000000..0e34ba1 --- /dev/null +++ b/fixtures/python/cryptography/sha256/main.py @@ -0,0 +1,8 @@ +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends import default_backend + +message = b"Hello, World!" + +digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) +digest.update(message) +hash_value = digest.finalize() diff --git a/fixtures/python/cryptography/sha256/mv-cbom.json b/fixtures/python/cryptography/sha256/mv-cbom.json new file mode 100644 index 0000000..891c2c4 --- /dev/null +++ b/fixtures/python/cryptography/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/cryptography/sha256/main.py", + "detectorId": "algorithm-detector", + "line": 6, + "column": 22 + } + } + ] +} diff --git a/fixtures/python/positive/main.py b/fixtures/python/positive/main.py deleted file mode 100644 index 6b0c533..0000000 --- a/fixtures/python/positive/main.py +++ /dev/null @@ -1,7 +0,0 @@ -from cryptography.fernet import Fernet - -def main(): - key = Fernet.generate_key() - f = Fernet(key) - print(f) - diff --git a/fixtures/python/pycryptodome/aes-gcm/main.py b/fixtures/python/pycryptodome/aes-gcm/main.py new file mode 100644 index 0000000..6d59057 --- /dev/null +++ b/fixtures/python/pycryptodome/aes-gcm/main.py @@ -0,0 +1,15 @@ +from Crypto.Cipher import AES +from Crypto.Random import get_random_bytes + +# Generate key and nonce +key = get_random_bytes(32) +nonce = get_random_bytes(12) +plaintext = b"Hello, World!" + +# Encrypt +cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) +ciphertext, tag = cipher.encrypt_and_digest(plaintext) + +# Decrypt +cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) +decrypted = cipher.decrypt_and_verify(ciphertext, tag) diff --git a/fixtures/python/pycryptodome/aes-gcm/mv-cbom.json b/fixtures/python/pycryptodome/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..a99f953 --- /dev/null +++ b/fixtures/python/pycryptodome/aes-gcm/mv-cbom.json @@ -0,0 +1,53 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/aes-gcm/main.py", + "detectorId": "algorithm-detector", + "line": 10, + "column": 10 + } + }, + { + "bom-ref": "94b13c81-438e-5c40-8ba6-69a3415fc269", + "assetType": "algorithm", + "name": "AES", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCryptodome", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/aes-gcm/main.py", + "detectorId": "algorithm-detector", + "line": 10, + "column": 10 + } + } + ] +} diff --git a/fixtures/python/pycryptodome/hmac-sha256/main.py b/fixtures/python/pycryptodome/hmac-sha256/main.py new file mode 100644 index 0000000..c041618 --- /dev/null +++ b/fixtures/python/pycryptodome/hmac-sha256/main.py @@ -0,0 +1,14 @@ +from Crypto.Hash import HMAC, SHA256 + +key = b"secret_key" +message = b"Hello, World!" + +# Create HMAC +h = HMAC.new(key, digestmod=SHA256) +h.update(message) +mac = h.digest() + +# Verify HMAC +h = HMAC.new(key, digestmod=SHA256) +h.update(message) +h.verify(mac) # Raises exception if invalid diff --git a/fixtures/python/pycryptodome/hmac-sha256/mv-cbom.json b/fixtures/python/pycryptodome/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..7e617a0 --- /dev/null +++ b/fixtures/python/pycryptodome/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/hmac-sha256/main.py", + "detectorId": "algorithm-detector", + "line": 1, + "column": 31 + } + } + ] +} diff --git a/fixtures/python/pycryptodome/rsa-sign/main.py b/fixtures/python/pycryptodome/rsa-sign/main.py new file mode 100644 index 0000000..4fb8727 --- /dev/null +++ b/fixtures/python/pycryptodome/rsa-sign/main.py @@ -0,0 +1,17 @@ +from Crypto.PublicKey import RSA +from Crypto.Signature import pss +from Crypto.Hash import SHA256 + +message = b"Hello, World!" + +# Generate RSA key pair +key = RSA.generate(2048) + +# Sign +h = SHA256.new(message) +signature = pss.new(key).sign(h) + +# Verify +h = SHA256.new(message) +verifier = pss.new(key) +verifier.verify(h, signature) # Raises exception if invalid diff --git a/fixtures/python/pycryptodome/rsa-sign/mv-cbom.json b/fixtures/python/pycryptodome/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..7cd0d34 --- /dev/null +++ b/fixtures/python/pycryptodome/rsa-sign/mv-cbom.json @@ -0,0 +1,88 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "PyCryptodome", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 8, + "column": 7 + } + }, + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 1, + "column": 30 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCryptodome", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 11, + "column": 5 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 3, + "column": 25 + } + } + ] +} diff --git a/fixtures/python/pycryptodome/sha256/main.py b/fixtures/python/pycryptodome/sha256/main.py new file mode 100644 index 0000000..632506f --- /dev/null +++ b/fixtures/python/pycryptodome/sha256/main.py @@ -0,0 +1,7 @@ +from Crypto.Hash import SHA256 + +message = b"Hello, World!" + +hash_obj = SHA256.new() +hash_obj.update(message) +digest = hash_obj.digest() diff --git a/fixtures/python/pycryptodome/sha256/mv-cbom.json b/fixtures/python/pycryptodome/sha256/mv-cbom.json new file mode 100644 index 0000000..74a153b --- /dev/null +++ b/fixtures/python/pycryptodome/sha256/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/sha256/main.py", + "detectorId": "algorithm-detector", + "line": 1, + "column": 25 + } + }, + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCryptodome", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pycryptodome/sha256/main.py", + "detectorId": "algorithm-detector", + "line": 5, + "column": 12 + } + } + ] +} diff --git a/fixtures/python/pynacl/aes-gcm/main.py b/fixtures/python/pynacl/aes-gcm/main.py new file mode 100644 index 0000000..b396981 --- /dev/null +++ b/fixtures/python/pynacl/aes-gcm/main.py @@ -0,0 +1,14 @@ +import nacl.secret +import nacl.utils + +# Note: PyNaCl doesn't support AES-GCM, using SecretBox (XSalsa20-Poly1305) instead +key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE) +box = nacl.secret.SecretBox(key) + +plaintext = b"Hello, World!" + +# Encrypt +encrypted = box.encrypt(plaintext) + +# Decrypt +decrypted = box.decrypt(encrypted) diff --git a/fixtures/python/pynacl/aes-gcm/mv-cbom.json b/fixtures/python/pynacl/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..19ee5e8 --- /dev/null +++ b/fixtures/python/pynacl/aes-gcm/mv-cbom.json @@ -0,0 +1,50 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "50beea07-0a57-5ec1-acb4-ff2800baa8b3", + "assetType": "algorithm", + "name": "XSalsa20Poly1305", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyNaCl", + "evidence": { + "file": "fixtures/python/pynacl/aes-gcm/main.py", + "detectorId": "detector-python", + "line": 5, + "column": 37 + } + }, + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pynacl/aes-gcm/main.py", + "detectorId": "algorithm-detector", + "line": 4, + "column": 32 + } + } + ] +} diff --git a/fixtures/python/pynacl/hmac-sha256/main.py b/fixtures/python/pynacl/hmac-sha256/main.py new file mode 100644 index 0000000..a5eeb5e --- /dev/null +++ b/fixtures/python/pynacl/hmac-sha256/main.py @@ -0,0 +1,14 @@ +import nacl.hash +import nacl.utils +import hmac + +# Note: PyNaCl doesn't have HMAC directly, using Python's hmac with nacl utilities +key = nacl.utils.random(32) +message = b"Hello, World!" + +# Create HMAC +mac = hmac.new(key, message, nacl.hash.sha256).digest() + +# Verify HMAC +expected_mac = hmac.new(key, message, nacl.hash.sha256).digest() +valid = hmac.compare_digest(mac, expected_mac) diff --git a/fixtures/python/pynacl/hmac-sha256/mv-cbom.json b/fixtures/python/pynacl/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..09cb34e --- /dev/null +++ b/fixtures/python/pynacl/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyNaCl", + "evidence": { + "file": "fixtures/python/pynacl/hmac-sha256/main.py", + "detectorId": "detector-python", + "line": 10, + "column": 30 + } + } + ] +} diff --git a/fixtures/python/pynacl/rsa-sign/main.py b/fixtures/python/pynacl/rsa-sign/main.py new file mode 100644 index 0000000..845c20e --- /dev/null +++ b/fixtures/python/pynacl/rsa-sign/main.py @@ -0,0 +1,13 @@ +import nacl.signing + +# Note: PyNaCl doesn't support RSA, using Ed25519 instead +signing_key = nacl.signing.SigningKey.generate() +verify_key = signing_key.verify_key + +message = b"Hello, World!" + +# Sign +signed = signing_key.sign(message) + +# Verify +verify_key.verify(signed.message, signed.signature) diff --git a/fixtures/python/pynacl/rsa-sign/mv-cbom.json b/fixtures/python/pynacl/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..f008bb1 --- /dev/null +++ b/fixtures/python/pynacl/rsa-sign/mv-cbom.json @@ -0,0 +1,53 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a0554bd2-5314-5ecc-aaaa-079002d1b3f9", + "assetType": "algorithm", + "name": "Ed25519", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "PyNaCl", + "evidence": { + "file": "fixtures/python/pynacl/rsa-sign/main.py", + "detectorId": "detector-python", + "line": 4, + "column": 28 + } + }, + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/pynacl/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 3, + "column": 32 + } + } + ] +} diff --git a/fixtures/python/pynacl/sha256/main.py b/fixtures/python/pynacl/sha256/main.py new file mode 100644 index 0000000..33bb090 --- /dev/null +++ b/fixtures/python/pynacl/sha256/main.py @@ -0,0 +1,6 @@ +import nacl.hash + +message = b"Hello, World!" + +# SHA-256 hash +digest = nacl.hash.sha256(message) diff --git a/fixtures/python/pynacl/sha256/mv-cbom.json b/fixtures/python/pynacl/sha256/mv-cbom.json new file mode 100644 index 0000000..3c6cf83 --- /dev/null +++ b/fixtures/python/pynacl/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyNaCl", + "evidence": { + "file": "fixtures/python/pynacl/sha256/main.py", + "detectorId": "detector-python", + "line": 6, + "column": 10 + } + } + ] +} diff --git a/fixtures/python/tink/aes-gcm/main.py b/fixtures/python/tink/aes-gcm/main.py new file mode 100644 index 0000000..6d4389f --- /dev/null +++ b/fixtures/python/tink/aes-gcm/main.py @@ -0,0 +1,20 @@ +import tink +from tink import aead + +# Register primitives +aead.register() + +# Generate key +keyset_handle = tink.new_keyset_handle(aead.aead_key_templates.AES256_GCM) + +# Get primitive +aead_primitive = keyset_handle.primitive(aead.Aead) + +plaintext = b"Hello, World!" +associated_data = b"" + +# Encrypt +ciphertext = aead_primitive.encrypt(plaintext, associated_data) + +# Decrypt +decrypted = aead_primitive.decrypt(ciphertext, associated_data) diff --git a/fixtures/python/tink/aes-gcm/mv-cbom.json b/fixtures/python/tink/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..0460832 --- /dev/null +++ b/fixtures/python/tink/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/tink/aes-gcm/main.py", + "detectorId": "algorithm-detector", + "line": 8, + "column": 64 + } + } + ] +} diff --git a/fixtures/python/tink/hmac-sha256/main.py b/fixtures/python/tink/hmac-sha256/main.py new file mode 100644 index 0000000..d2ec618 --- /dev/null +++ b/fixtures/python/tink/hmac-sha256/main.py @@ -0,0 +1,19 @@ +import tink +from tink import mac + +# Register primitives +mac.register() + +# Generate key +keyset_handle = tink.new_keyset_handle(mac.mac_key_templates.HMAC_SHA256_256BITTAG) + +# Get primitive +mac_primitive = keyset_handle.primitive(mac.Mac) + +message = b"Hello, World!" + +# Create MAC +tag = mac_primitive.compute_mac(message) + +# Verify MAC +mac_primitive.verify_mac(tag, message) diff --git a/fixtures/python/tink/hmac-sha256/mv-cbom.json b/fixtures/python/tink/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..d5b8a7f --- /dev/null +++ b/fixtures/python/tink/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "Google Tink (Python)", + "evidence": { + "file": "fixtures/python/tink/hmac-sha256/main.py", + "detectorId": "detector-python", + "line": 8, + "column": 17 + } + } + ] +} diff --git a/fixtures/python/tink/rsa-sign/main.py b/fixtures/python/tink/rsa-sign/main.py new file mode 100644 index 0000000..58630ea --- /dev/null +++ b/fixtures/python/tink/rsa-sign/main.py @@ -0,0 +1,22 @@ +import tink +from tink import signature + +# Register primitives +signature.register() + +# Generate key pair +private_keyset_handle = tink.new_keyset_handle( + signature.signature_key_templates.RSA_PSS_3072_SHA256_F4) +public_keyset_handle = private_keyset_handle.public_keyset_handle() + +# Get primitives +signer = private_keyset_handle.primitive(signature.PublicKeySign) +verifier = public_keyset_handle.primitive(signature.PublicKeyVerify) + +message = b"Hello, World!" + +# Sign +sig = signer.sign(message) + +# Verify +verifier.verify(sig, message) diff --git a/fixtures/python/tink/rsa-sign/mv-cbom.json b/fixtures/python/tink/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..982b8cd --- /dev/null +++ b/fixtures/python/tink/rsa-sign/mv-cbom.json @@ -0,0 +1,37 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "PyCA cryptography", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/python/tink/rsa-sign/main.py", + "detectorId": "algorithm-detector", + "line": 9, + "column": 39 + } + } + ] +} diff --git a/fixtures/python/tink/sha256/mv-cbom.json b/fixtures/python/tink/sha256/mv-cbom.json new file mode 100644 index 0000000..5cc690e --- /dev/null +++ b/fixtures/python/tink/sha256/mv-cbom.json @@ -0,0 +1,17 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [] +} diff --git a/fixtures/rust/positive/Cargo.toml b/fixtures/rust/positive/Cargo.toml deleted file mode 100644 index 547e11b..0000000 --- a/fixtures/rust/positive/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "rust-positive" -version = "0.1.0" -edition = "2021" - -[dependencies] -aes-gcm = "0.10" - diff --git a/fixtures/rust/positive/src/main.rs b/fixtures/rust/positive/src/main.rs deleted file mode 100644 index 8e4b9a1..0000000 --- a/fixtures/rust/positive/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -use aes_gcm::Aes256Gcm; - -fn main() { - let _ = std::any::type_name::(); -} - diff --git a/fixtures/rust/ring/aes-gcm/main.rs b/fixtures/rust/ring/aes-gcm/main.rs new file mode 100644 index 0000000..82745c5 --- /dev/null +++ b/fixtures/rust/ring/aes-gcm/main.rs @@ -0,0 +1,27 @@ +use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, AES_256_GCM}; +use ring::rand::{SecureRandom, SystemRandom}; + +fn main() { + let rng = SystemRandom::new(); + + // Generate key + let mut key_bytes = [0u8; 32]; + rng.fill(&mut key_bytes).unwrap(); + + let unbound_key = UnboundKey::new(&AES_256_GCM, &key_bytes).unwrap(); + let key = LessSafeKey::new(unbound_key); + + let mut nonce_bytes = [0u8; 12]; + rng.fill(&mut nonce_bytes).unwrap(); + let nonce = Nonce::assume_unique_for_key(nonce_bytes); + + let plaintext = b"Hello, World!"; + let mut ciphertext = plaintext.to_vec(); + + // Encrypt + key.seal_in_place_append_tag(nonce, Aad::empty(), &mut ciphertext).unwrap(); + + // Decrypt + let nonce = Nonce::assume_unique_for_key(nonce_bytes); + let decrypted = key.open_in_place(nonce, Aad::empty(), &mut ciphertext).unwrap(); +} diff --git a/fixtures/rust/ring/aes-gcm/mv-cbom.json b/fixtures/rust/ring/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..396a029 --- /dev/null +++ b/fixtures/rust/ring/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "ring", + "evidence": { + "file": "fixtures/rust/ring/aes-gcm/main.rs", + "detectorId": "detector-rust", + "line": 1, + "column": 5 + } + } + ] +} diff --git a/fixtures/rust/ring/hmac-sha256/main.rs b/fixtures/rust/ring/hmac-sha256/main.rs new file mode 100644 index 0000000..32a8c11 --- /dev/null +++ b/fixtures/rust/ring/hmac-sha256/main.rs @@ -0,0 +1,13 @@ +use ring::hmac; + +fn main() { + let key = b"secret_key"; + let message = b"Hello, World!"; + + // Create HMAC + let key = hmac::Key::new(hmac::HMAC_SHA256, key); + let tag = hmac::sign(&key, message); + + // Verify HMAC + hmac::verify(&key, message, tag.as_ref()).unwrap(); +} diff --git a/fixtures/rust/ring/hmac-sha256/mv-cbom.json b/fixtures/rust/ring/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..fdb2b36 --- /dev/null +++ b/fixtures/rust/ring/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "ring", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/ring/hmac-sha256/main.rs", + "detectorId": "algorithm-detector", + "line": 8, + "column": 30 + } + } + ] +} diff --git a/fixtures/rust/ring/rsa-sign/main.rs b/fixtures/rust/ring/rsa-sign/main.rs new file mode 100644 index 0000000..f34bc71 --- /dev/null +++ b/fixtures/rust/ring/rsa-sign/main.rs @@ -0,0 +1,26 @@ +use ring::rand::SystemRandom; +use ring::signature::{self, KeyPair}; + +fn main() { + let message = b"Hello, World!"; + let rng = SystemRandom::new(); + + // Generate RSA key pair + let key_pair = signature::RsaKeyPair::generate_pkcs8( + &signature::RSA_PSS_2048_8192_SHA256, + &rng + ).unwrap(); + + let key_pair = signature::RsaKeyPair::from_pkcs8(key_pair.as_ref()).unwrap(); + + // Sign + let mut signature = vec![0; key_pair.public_modulus_len()]; + key_pair.sign(&signature::RSA_PSS_SHA256, &rng, message, &mut signature).unwrap(); + + // Verify + let public_key = signature::UnparsedPublicKey::new( + &signature::RSA_PSS_2048_8192_SHA256, + key_pair.public_key().as_ref() + ); + public_key.verify(message, &signature).unwrap(); +} diff --git a/fixtures/rust/ring/rsa-sign/mv-cbom.json b/fixtures/rust/ring/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..add9607 --- /dev/null +++ b/fixtures/rust/ring/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "cecdb684-a18f-57bd-9319-b2cfafe4d210", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "ring", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/ring/rsa-sign/main.rs", + "detectorId": "algorithm-detector", + "line": 9, + "column": 31 + } + } + ] +} diff --git a/fixtures/rust/ring/sha256/main.rs b/fixtures/rust/ring/sha256/main.rs new file mode 100644 index 0000000..8d08c02 --- /dev/null +++ b/fixtures/rust/ring/sha256/main.rs @@ -0,0 +1,8 @@ +use ring::digest; + +fn main() { + let message = b"Hello, World!"; + + let digest = digest::digest(&digest::SHA256, message); + let _hash = digest.as_ref(); +} diff --git a/fixtures/rust/ring/sha256/mv-cbom.json b/fixtures/rust/ring/sha256/mv-cbom.json new file mode 100644 index 0000000..35f335b --- /dev/null +++ b/fixtures/rust/ring/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "ring", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/ring/sha256/main.rs", + "detectorId": "algorithm-detector", + "line": 6, + "column": 18 + } + } + ] +} diff --git a/fixtures/rust/rust-crypto/aes-gcm/main.rs b/fixtures/rust/rust-crypto/aes-gcm/main.rs new file mode 100644 index 0000000..cafeadb --- /dev/null +++ b/fixtures/rust/rust-crypto/aes-gcm/main.rs @@ -0,0 +1,18 @@ +use aes_gcm::{ + aead::{Aead, KeyInit, OsRng}, + Aes256Gcm, Nonce +}; + +fn main() { + let key = Aes256Gcm::generate_key(&mut OsRng); + let cipher = Aes256Gcm::new(&key); + + let nonce = Nonce::from_slice(b"unique nonce"); + let plaintext = b"Hello, World!"; + + // Encrypt + let ciphertext = cipher.encrypt(nonce, plaintext.as_ref()).unwrap(); + + // Decrypt + let decrypted = cipher.decrypt(nonce, ciphertext.as_ref()).unwrap(); +} diff --git a/fixtures/rust/rust-crypto/aes-gcm/mv-cbom.json b/fixtures/rust/rust-crypto/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..4cc7616 --- /dev/null +++ b/fixtures/rust/rust-crypto/aes-gcm/mv-cbom.json @@ -0,0 +1,37 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a3672537-724a-5203-a125-5b9d3c0300da", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/rust-crypto/aes-gcm/main.rs", + "detectorId": "algorithm-detector", + "line": 1, + "column": 5 + } + } + ] +} diff --git a/fixtures/rust/rust-crypto/hmac-sha256/main.rs b/fixtures/rust/rust-crypto/hmac-sha256/main.rs new file mode 100644 index 0000000..d0fb349 --- /dev/null +++ b/fixtures/rust/rust-crypto/hmac-sha256/main.rs @@ -0,0 +1,20 @@ +use hmac::{Hmac, Mac}; +use sha2::Sha256; + +type HmacSha256 = Hmac; + +fn main() { + let key = b"secret_key"; + let message = b"Hello, World!"; + + // Create HMAC + let mut mac = HmacSha256::new_from_slice(key).unwrap(); + mac.update(message); + let result = mac.finalize(); + let code_bytes = result.into_bytes(); + + // Verify HMAC + let mut mac = HmacSha256::new_from_slice(key).unwrap(); + mac.update(message); + mac.verify_slice(&code_bytes).unwrap(); +} diff --git a/fixtures/rust/rust-crypto/hmac-sha256/mv-cbom.json b/fixtures/rust/rust-crypto/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..a91d5f0 --- /dev/null +++ b/fixtures/rust/rust-crypto/hmac-sha256/mv-cbom.json @@ -0,0 +1,56 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "65827a0a-50aa-55c9-b927-81fae74f70ef", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rust-crypto/hmac-sha256/main.rs", + "detectorId": "detector-rust", + "line": 2, + "column": 11 + } + }, + { + "bom-ref": "97066213-4cad-521a-8efe-586ce966af31", + "assetType": "algorithm", + "name": "SHA-512", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rust-crypto/hmac-sha256/main.rs", + "detectorId": "detector-rust", + "line": 2, + "column": 11 + } + } + ] +} diff --git a/fixtures/rust/rust-crypto/rsa-sign/main.rs b/fixtures/rust/rust-crypto/rsa-sign/main.rs new file mode 100644 index 0000000..d590a17 --- /dev/null +++ b/fixtures/rust/rust-crypto/rsa-sign/main.rs @@ -0,0 +1,22 @@ +use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Sign}; +use rsa::signature::{Signer, Verifier}; +use sha2::Sha256; + +fn main() { + let mut rng = rand::thread_rng(); + + // Generate key pair + let bits = 2048; + let private_key = RsaPrivateKey::new(&mut rng, bits).unwrap(); + let public_key = RsaPublicKey::from(&private_key); + + let message = b"Hello, World!"; + let signing_key = rsa::pkcs1v15::SigningKey::::new(private_key); + let verifying_key = rsa::pkcs1v15::VerifyingKey::::new(public_key); + + // Sign + let signature = signing_key.sign(message); + + // Verify + verifying_key.verify(message, &signature).unwrap(); +} diff --git a/fixtures/rust/rust-crypto/rsa-sign/mv-cbom.json b/fixtures/rust/rust-crypto/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..592051d --- /dev/null +++ b/fixtures/rust/rust-crypto/rsa-sign/mv-cbom.json @@ -0,0 +1,75 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "97066213-4cad-521a-8efe-586ce966af31", + "assetType": "algorithm", + "name": "SHA-512", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rust-crypto/rsa-sign/main.rs", + "detectorId": "detector-rust", + "line": 3, + "column": 11 + } + }, + { + "bom-ref": "65827a0a-50aa-55c9-b927-81fae74f70ef", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rust-crypto/rsa-sign/main.rs", + "detectorId": "detector-rust", + "line": 3, + "column": 11 + } + }, + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/rust-crypto/rsa-sign/main.rs", + "detectorId": "algorithm-detector", + "line": 1, + "column": 5 + } + } + ] +} diff --git a/fixtures/rust/rust-crypto/sha256/main.rs b/fixtures/rust/rust-crypto/sha256/main.rs new file mode 100644 index 0000000..2fe65a1 --- /dev/null +++ b/fixtures/rust/rust-crypto/sha256/main.rs @@ -0,0 +1,7 @@ +use sha2::{Sha256, Digest}; + +fn main() { + let mut hasher = Sha256::new(); + hasher.update(b"Hello, World!"); + let result = hasher.finalize(); +} diff --git a/fixtures/rust/rust-crypto/sha256/mv-cbom.json b/fixtures/rust/rust-crypto/sha256/mv-cbom.json new file mode 100644 index 0000000..70323ea --- /dev/null +++ b/fixtures/rust/rust-crypto/sha256/mv-cbom.json @@ -0,0 +1,56 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "97066213-4cad-521a-8efe-586ce966af31", + "assetType": "algorithm", + "name": "SHA-512", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rust-crypto/sha256/main.rs", + "detectorId": "detector-rust", + "line": 1, + "column": 12 + } + }, + { + "bom-ref": "65827a0a-50aa-55c9-b927-81fae74f70ef", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rust-crypto/sha256/main.rs", + "detectorId": "detector-rust", + "line": 1, + "column": 12 + } + } + ] +} diff --git a/fixtures/rust/rustcrypto/aes-gcm/main.rs b/fixtures/rust/rustcrypto/aes-gcm/main.rs new file mode 100644 index 0000000..484ba95 --- /dev/null +++ b/fixtures/rust/rustcrypto/aes-gcm/main.rs @@ -0,0 +1,19 @@ +use aes_gcm::{ + aead::{Aead, AeadCore, KeyInit, OsRng}, + Aes256Gcm, Nonce +}; + +fn main() { + // Generate key and nonce + let key = Aes256Gcm::generate_key(&mut OsRng); + let cipher = Aes256Gcm::new(&key); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + + let plaintext = b"Hello, World!"; + + // Encrypt + let ciphertext = cipher.encrypt(&nonce, plaintext.as_ref()).unwrap(); + + // Decrypt + let decrypted = cipher.decrypt(&nonce, ciphertext.as_ref()).unwrap(); +} diff --git a/fixtures/rust/rustcrypto/aes-gcm/mv-cbom.json b/fixtures/rust/rustcrypto/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..9739beb --- /dev/null +++ b/fixtures/rust/rustcrypto/aes-gcm/mv-cbom.json @@ -0,0 +1,37 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "a3672537-724a-5203-a125-5b9d3c0300da", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "parameterSet": { + "keySize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/rustcrypto/aes-gcm/main.rs", + "detectorId": "algorithm-detector", + "line": 1, + "column": 5 + } + } + ] +} diff --git a/fixtures/rust/rustcrypto/hmac-sha256/main.rs b/fixtures/rust/rustcrypto/hmac-sha256/main.rs new file mode 100644 index 0000000..1a1caae --- /dev/null +++ b/fixtures/rust/rustcrypto/hmac-sha256/main.rs @@ -0,0 +1,20 @@ +use hmac::{Hmac, Mac}; +use sha2::Sha256; + +type HmacSha256 = Hmac; + +fn main() { + let key = b"secret_key"; + let message = b"Hello, World!"; + + // Create HMAC + let mut mac = HmacSha256::new_from_slice(key).unwrap(); + mac.update(message); + let result = mac.finalize(); + let code = result.into_bytes(); + + // Verify HMAC + let mut mac = HmacSha256::new_from_slice(key).unwrap(); + mac.update(message); + mac.verify_slice(&code).unwrap(); +} diff --git a/fixtures/rust/rustcrypto/hmac-sha256/mv-cbom.json b/fixtures/rust/rustcrypto/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..480b10f --- /dev/null +++ b/fixtures/rust/rustcrypto/hmac-sha256/mv-cbom.json @@ -0,0 +1,56 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "65827a0a-50aa-55c9-b927-81fae74f70ef", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rustcrypto/hmac-sha256/main.rs", + "detectorId": "detector-rust", + "line": 2, + "column": 11 + } + }, + { + "bom-ref": "97066213-4cad-521a-8efe-586ce966af31", + "assetType": "algorithm", + "name": "SHA-512", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rustcrypto/hmac-sha256/main.rs", + "detectorId": "detector-rust", + "line": 2, + "column": 11 + } + } + ] +} diff --git a/fixtures/rust/rustcrypto/rsa-sign/main.rs b/fixtures/rust/rustcrypto/rsa-sign/main.rs new file mode 100644 index 0000000..664d6f4 --- /dev/null +++ b/fixtures/rust/rustcrypto/rsa-sign/main.rs @@ -0,0 +1,22 @@ +use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Sign}; +use rsa::signature::{Signer, Verifier}; +use sha2::Sha256; + +fn main() { + let mut rng = rand::thread_rng(); + let message = b"Hello, World!"; + + // Generate RSA key pair + let private_key = RsaPrivateKey::new(&mut rng, 2048).unwrap(); + let public_key = RsaPublicKey::from(&private_key); + + // Create signing key + let signing_key = rsa::pss::SigningKey::::new(private_key); + let verifying_key = signing_key.verifying_key(); + + // Sign + let signature = signing_key.sign(message); + + // Verify + verifying_key.verify(message, &signature).unwrap(); +} diff --git a/fixtures/rust/rustcrypto/rsa-sign/mv-cbom.json b/fixtures/rust/rustcrypto/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..34c4049 --- /dev/null +++ b/fixtures/rust/rustcrypto/rsa-sign/mv-cbom.json @@ -0,0 +1,75 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "97066213-4cad-521a-8efe-586ce966af31", + "assetType": "algorithm", + "name": "SHA-512", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rustcrypto/rsa-sign/main.rs", + "detectorId": "detector-rust", + "line": 3, + "column": 11 + } + }, + { + "bom-ref": "b5dc99a9-59bc-58e6-82c8-29de37994c73", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "parameterSet": { + "keySize": 2048 + }, + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "/Users/ielbaz/Projects/cipherscope/fixtures/rust/rustcrypto/rsa-sign/main.rs", + "detectorId": "algorithm-detector", + "line": 1, + "column": 5 + } + }, + { + "bom-ref": "65827a0a-50aa-55c9-b927-81fae74f70ef", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rustcrypto/rsa-sign/main.rs", + "detectorId": "detector-rust", + "line": 3, + "column": 11 + } + } + ] +} diff --git a/fixtures/rust/rustcrypto/sha256/main.rs b/fixtures/rust/rustcrypto/sha256/main.rs new file mode 100644 index 0000000..1afd813 --- /dev/null +++ b/fixtures/rust/rustcrypto/sha256/main.rs @@ -0,0 +1,9 @@ +use sha2::{Sha256, Digest}; + +fn main() { + let message = b"Hello, World!"; + + let mut hasher = Sha256::new(); + hasher.update(message); + let result = hasher.finalize(); +} diff --git a/fixtures/rust/rustcrypto/sha256/mv-cbom.json b/fixtures/rust/rustcrypto/sha256/mv-cbom.json new file mode 100644 index 0000000..cb334e3 --- /dev/null +++ b/fixtures/rust/rustcrypto/sha256/mv-cbom.json @@ -0,0 +1,56 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "65827a0a-50aa-55c9-b927-81fae74f70ef", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rustcrypto/sha256/main.rs", + "detectorId": "detector-rust", + "line": 1, + "column": 12 + } + }, + { + "bom-ref": "97066213-4cad-521a-8efe-586ce966af31", + "assetType": "algorithm", + "name": "SHA-512", + "assetProperties": { + "primitive": "hash", + "parameterSet": { + "outputSize": 256 + }, + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "RustCrypto (common crates)", + "evidence": { + "file": "fixtures/rust/rustcrypto/sha256/main.rs", + "detectorId": "detector-rust", + "line": 1, + "column": 12 + } + } + ] +} diff --git a/fixtures/swift/commoncrypto/aes-gcm/main.swift b/fixtures/swift/commoncrypto/aes-gcm/main.swift new file mode 100644 index 0000000..7bde60a --- /dev/null +++ b/fixtures/swift/commoncrypto/aes-gcm/main.swift @@ -0,0 +1,12 @@ +import Foundation +import CryptoKit + +// Note: CommonCrypto doesn't support AES-GCM directly, using CryptoKit +let key = SymmetricKey(size: .bits256) +let plaintext = "Hello, World!".data(using: .utf8)! + +// Encrypt +let sealedBox = try! AES.GCM.seal(plaintext, using: key) + +// Decrypt +let decrypted = try! AES.GCM.open(sealedBox, using: key) diff --git a/fixtures/swift/commoncrypto/aes-gcm/mv-cbom.json b/fixtures/swift/commoncrypto/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..f42ca55 --- /dev/null +++ b/fixtures/swift/commoncrypto/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CryptoKit", + "evidence": { + "file": "fixtures/swift/commoncrypto/aes-gcm/main.swift", + "detectorId": "detector-swift", + "line": 9, + "column": 22 + } + } + ] +} diff --git a/fixtures/swift/commoncrypto/hmac-sha256/main.swift b/fixtures/swift/commoncrypto/hmac-sha256/main.swift new file mode 100644 index 0000000..f64d85e --- /dev/null +++ b/fixtures/swift/commoncrypto/hmac-sha256/main.swift @@ -0,0 +1,15 @@ +import Foundation +import CommonCrypto + +let key = "secret_key".data(using: .utf8)! +let message = "Hello, World!".data(using: .utf8)! +var mac = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) + +key.withUnsafeBytes { keyBytes in + message.withUnsafeBytes { messageBytes in + CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), + keyBytes.baseAddress, key.count, + messageBytes.baseAddress, message.count, + &mac) + } +} diff --git a/fixtures/swift/commoncrypto/hmac-sha256/mv-cbom.json b/fixtures/swift/commoncrypto/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..2867ec8 --- /dev/null +++ b/fixtures/swift/commoncrypto/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "8d87019b-2e9c-5335-8c36-37dffd06e3a5", + "assetType": "algorithm", + "name": "HMAC-SHA256", + "assetProperties": { + "primitive": "mac", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CommonCrypto (Swift)", + "evidence": { + "file": "fixtures/swift/commoncrypto/hmac-sha256/main.swift", + "detectorId": "detector-swift", + "line": 10, + "column": 9 + } + } + ] +} diff --git a/fixtures/swift/commoncrypto/rsa-sign/main.swift b/fixtures/swift/commoncrypto/rsa-sign/main.swift new file mode 100644 index 0000000..4df68df --- /dev/null +++ b/fixtures/swift/commoncrypto/rsa-sign/main.swift @@ -0,0 +1,31 @@ +import Foundation +import Security + +let message = "Hello, World!".data(using: .utf8)! + +// Generate RSA key pair +let parameters: [String: Any] = [ + kSecAttrKeyType as String: kSecAttrKeyTypeRSA, + kSecAttrKeySizeInBits as String: 2048 +] + +var publicKey, privateKey: SecKey? +SecKeyGeneratePair(parameters as CFDictionary, &publicKey, &privateKey) + +// Sign +var error: Unmanaged? +let signature = SecKeyCreateSignature( + privateKey!, + .rsaSignatureMessagePSSSHA256, + message as CFData, + &error +) + +// Verify +let valid = SecKeyVerifySignature( + publicKey!, + .rsaSignatureMessagePSSSHA256, + message as CFData, + signature!, + &error +) diff --git a/fixtures/swift/commoncrypto/rsa-sign/mv-cbom.json b/fixtures/swift/commoncrypto/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..8037aab --- /dev/null +++ b/fixtures/swift/commoncrypto/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "cecdb684-a18f-57bd-9319-b2cfafe4d210", + "assetType": "algorithm", + "name": "RSA", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 0 + }, + "sourceLibrary": "Security.framework (Swift)", + "evidence": { + "file": "fixtures/swift/commoncrypto/rsa-sign/main.swift", + "detectorId": "detector-swift", + "line": 8, + "column": 5 + } + } + ] +} diff --git a/fixtures/swift/commoncrypto/sha256/main.swift b/fixtures/swift/commoncrypto/sha256/main.swift new file mode 100644 index 0000000..d6b0cdf --- /dev/null +++ b/fixtures/swift/commoncrypto/sha256/main.swift @@ -0,0 +1,9 @@ +import Foundation +import CommonCrypto + +let message = "Hello, World!".data(using: .utf8)! +var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) + +message.withUnsafeBytes { bytes in + CC_SHA256(bytes.baseAddress, CC_LONG(message.count), &digest) +} diff --git a/fixtures/swift/commoncrypto/sha256/mv-cbom.json b/fixtures/swift/commoncrypto/sha256/mv-cbom.json new file mode 100644 index 0000000..9cd327b --- /dev/null +++ b/fixtures/swift/commoncrypto/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CommonCrypto (Swift)", + "evidence": { + "file": "fixtures/swift/commoncrypto/sha256/main.swift", + "detectorId": "detector-swift", + "line": 8, + "column": 5 + } + } + ] +} diff --git a/fixtures/swift/cryptokit/aes-gcm/main.swift b/fixtures/swift/cryptokit/aes-gcm/main.swift new file mode 100644 index 0000000..f6d68e5 --- /dev/null +++ b/fixtures/swift/cryptokit/aes-gcm/main.swift @@ -0,0 +1,13 @@ +import CryptoKit +import Foundation + +let plaintext = "Hello, World!".data(using: .utf8)! + +// Generate key +let key = SymmetricKey(size: .bits256) + +// Encrypt +let sealedBox = try! AES.GCM.seal(plaintext, using: key) + +// Decrypt +let decrypted = try! AES.GCM.open(sealedBox, using: key) diff --git a/fixtures/swift/cryptokit/aes-gcm/mv-cbom.json b/fixtures/swift/cryptokit/aes-gcm/mv-cbom.json new file mode 100644 index 0000000..4a023fa --- /dev/null +++ b/fixtures/swift/cryptokit/aes-gcm/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "fbe00a14-7b9d-5aba-9e91-8f9b29fee66c", + "assetType": "algorithm", + "name": "AES-GCM", + "assetProperties": { + "primitive": "aead", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CryptoKit", + "evidence": { + "file": "fixtures/swift/cryptokit/aes-gcm/main.swift", + "detectorId": "detector-swift", + "line": 10, + "column": 22 + } + } + ] +} diff --git a/fixtures/swift/cryptokit/hmac-sha256/main.swift b/fixtures/swift/cryptokit/hmac-sha256/main.swift new file mode 100644 index 0000000..c1c5674 --- /dev/null +++ b/fixtures/swift/cryptokit/hmac-sha256/main.swift @@ -0,0 +1,9 @@ +import CryptoKit +import Foundation + +let key = SymmetricKey(data: "secret_key".data(using: .utf8)!) +let message = "Hello, World!".data(using: .utf8)! + +// Create and verify HMAC +let mac = HMAC.authenticationCode(for: message, using: key) +let isValid = HMAC.isValidAuthenticationCode(mac, authenticating: message, using: key) diff --git a/fixtures/swift/cryptokit/hmac-sha256/mv-cbom.json b/fixtures/swift/cryptokit/hmac-sha256/mv-cbom.json new file mode 100644 index 0000000..cdbe2e7 --- /dev/null +++ b/fixtures/swift/cryptokit/hmac-sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CryptoKit", + "evidence": { + "file": "fixtures/swift/cryptokit/hmac-sha256/main.swift", + "detectorId": "detector-swift", + "line": 8, + "column": 11 + } + } + ] +} diff --git a/fixtures/swift/cryptokit/rsa-sign/main.swift b/fixtures/swift/cryptokit/rsa-sign/main.swift new file mode 100644 index 0000000..8652046 --- /dev/null +++ b/fixtures/swift/cryptokit/rsa-sign/main.swift @@ -0,0 +1,15 @@ +import CryptoKit +import Foundation + +// Note: CryptoKit doesn't support RSA directly, using P256 as an alternative +let message = "Hello, World!".data(using: .utf8)! + +// Generate key pair +let privateKey = P256.Signing.PrivateKey() +let publicKey = privateKey.publicKey + +// Sign +let signature = try! privateKey.signature(for: message) + +// Verify +let isValid = publicKey.isValidSignature(signature, for: message) diff --git a/fixtures/swift/cryptokit/rsa-sign/mv-cbom.json b/fixtures/swift/cryptokit/rsa-sign/mv-cbom.json new file mode 100644 index 0000000..31d9bfc --- /dev/null +++ b/fixtures/swift/cryptokit/rsa-sign/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "5944d521-4665-5336-930d-fe9ed7d42abd", + "assetType": "algorithm", + "name": "ECDSA-P256", + "assetProperties": { + "primitive": "signature", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CryptoKit", + "evidence": { + "file": "fixtures/swift/cryptokit/rsa-sign/main.swift", + "detectorId": "detector-swift", + "line": 8, + "column": 18 + } + } + ] +} diff --git a/fixtures/swift/cryptokit/sha256/main.swift b/fixtures/swift/cryptokit/sha256/main.swift new file mode 100644 index 0000000..37b2a8c --- /dev/null +++ b/fixtures/swift/cryptokit/sha256/main.swift @@ -0,0 +1,6 @@ +import CryptoKit +import Foundation + +let message = "Hello, World!".data(using: .utf8)! + +let digest = SHA256.hash(data: message) diff --git a/fixtures/swift/cryptokit/sha256/mv-cbom.json b/fixtures/swift/cryptokit/sha256/mv-cbom.json new file mode 100644 index 0000000..1d518f0 --- /dev/null +++ b/fixtures/swift/cryptokit/sha256/mv-cbom.json @@ -0,0 +1,34 @@ +{ + "bomFormat": "MV-CBOM", + "specVersion": "1.0", + "serialNumber": "urn:uuid:acafcce7-fc11-5530-bedb-4a99878f3eae", + "version": 1, + "metadata": { + "timestamp": "1970-01-01T00:00:00Z", + "tools": [ + { + "name": "cipherscope", + "version": "0.1.0", + "vendor": "CipherScope Contributors" + } + ] + }, + "cryptoAssets": [ + { + "bom-ref": "2898152c-e8b5-5e80-a53c-0b4d664e0443", + "assetType": "algorithm", + "name": "SHA-256", + "assetProperties": { + "primitive": "hash", + "nistQuantumSecurityLevel": 3 + }, + "sourceLibrary": "CryptoKit", + "evidence": { + "file": "fixtures/swift/cryptokit/sha256/main.swift", + "detectorId": "detector-swift", + "line": 6, + "column": 14 + } + } + ] +} diff --git a/fixtures/swift/positive/main.swift b/fixtures/swift/positive/main.swift deleted file mode 100644 index ef06824..0000000 --- a/fixtures/swift/positive/main.swift +++ /dev/null @@ -1,28 +0,0 @@ -import CryptoKit -import CommonCrypto - -func main() { - // CryptoKit usage - let key = SymmetricKey(size: .bits256) - let data = "Hello, World!".data(using: .utf8)! - - do { - let sealedBox = try AES.GCM.seal(data, using: key) - print("Encrypted: \(sealedBox)") - } catch { - print("Encryption failed: \(error)") - } - - // CommonCrypto usage - let message = "Test message" - let messageData = message.data(using: .utf8)! - var digest = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) - - _ = digest.withUnsafeMutableBytes { digestBytes in - messageData.withUnsafeBytes { messageBytes in - CC_SHA256(messageBytes.baseAddress, CC_LONG(messageData.count), digestBytes.bindMemory(to: UInt8.self).baseAddress) - } - } - - print("SHA256: \(digest.map { String(format: "%02hhx", $0) }.joined())") -} diff --git a/patterns.toml b/patterns.toml index 6aa0704..f74eeb6 100644 --- a/patterns.toml +++ b/patterns.toml @@ -15,7 +15,9 @@ include = [ ] apis = [ "\\bEVP_[A-Za-z0-9_]+\\s*\\(", + "\\bHMAC\\s*\\(", "\\bRSA_[A-Za-z0-9_]+\\s*\\(", + "\\bDSA_[A-Za-z0-9_]+\\s*\\(", "\\bEC_KEY_[A-Za-z0-9_]+\\s*\\(", "\\bECDSA_[A-Za-z0-9_]+\\s*\\(", "\\bED25519_[A-Za-z0-9_]+\\s*\\(", @@ -23,6 +25,479 @@ apis = [ "\\bPKCS\\d_[A-Za-z0-9_]+\\s*\\(", ] +# Algorithm definitions for OpenSSL +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bRSA_", + "\\bEVP_PKEY_RSA", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "RSA_(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "DSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_PKEY_DSA", + "\\bDSA_", # DSA_* low-level API + "\\bEVP_dss1\\s*\\(", # legacy DSA with SHA-1 +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bECDSA_", + "\\bEC_KEY_", +] +[[library.algorithms.parameter_patterns]] +name = "curve" +pattern = "EC_KEY_new_by_curve_name\\s*\\(\\s*(NID_(?:X9_62_prime256v1|secp384r1|secp521r1))" +default_value = "P-256" + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_aes_\\d+_gcm\\s*\\(", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "EVP_aes_(\\d+)_gcm" +default_value = 256 + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_aes_\\d+_(?:cbc|ctr|ofb|cfb|ecb)", + # Explicit EVP AES mode calls + "\\bEVP_aes_(?:128|192|256)_cbc\\s*\\(", + "\\bEVP_aes_(?:128|192|256)_ecb\\s*\\(", + "\\bEVP_aes_(?:128|192|256)_cfb\\s*\\(", + "\\bEVP_aes_(?:128|192|256)_ofb\\s*\\(", + "\\bAES_", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "EVP_aes_(\\d+)" +default_value = 256 + +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_PKEY_RSA", + "\\bRSA_", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "RSA_generate_key_ex\\s*\\([^,]+,\\s*(\\d{4})" +default_value = 2048 +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "aes_(\\d+)" +default_value = 256 + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha256\\s*\\(", + "\\bEVP_DigestInit.*SHA256", + "\\bSHA256_Init", + "\\bSHA256_Update", + "\\bSHA256_Final", + "\\bSHA256", +] + +[[library.algorithms]] +name = "SHA3-224" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha3_224\\s*\\(", +] + +[[library.algorithms]] +name = "SHA3-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha3_256\\s*\\(", +] + +[[library.algorithms]] +name = "SHA3-384" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha3_384\\s*\\(", +] + +[[library.algorithms]] +name = "SHA3-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha3_512\\s*\\(", +] + +[[library.algorithms]] +name = "SHAKE128" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_shake128\\s*\\(", +] + +[[library.algorithms]] +name = "SHAKE256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_shake256\\s*\\(", +] + +[[library.algorithms]] +name = "SHA-1" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_sha1\\s*\\(", + "\\bEVP_DigestInit.*SHA1", + "\\bSHA1_Init", + "\\bSHA1_Update", + "\\bSHA1_Final", + "\\bSHA1", +] + +[[library.algorithms]] +name = "SHA-384" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha384\\s*\\(", + "\\bEVP_DigestInit.*SHA384", + "\\bSHA384_Init", + "\\bSHA384_Update", + "\\bSHA384_Final", + "\\bSHA384", +] + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha512\\s*\\(", + "\\bEVP_DigestInit.*SHA512", + "\\bSHA512_Init", + "\\bSHA512_Update", + "\\bSHA512_Final", + "\\bSHA512", +] + +[[library.algorithms]] +name = "SHA-224" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha224\\s*\\(", + "\\bEVP_DigestInit.*SHA224", + "\\bSHA224_Init", + "\\bSHA224_Update", + "\\bSHA224_Final", + "\\bSHA224", +] + +[[library.algorithms]] +name = "MD5" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_md5\\s*\\(", + "\\bEVP_DigestInit.*MD5", + "\\bMD5_Init", + "\\bMD5_Update", + "\\bMD5_Final", + "\\bMD5", +] + +[[library.algorithms]] +name = "MD4" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_md4\\s*\\(", + "\\bEVP_DigestInit.*MD4", + "\\bMD4_Init", + "\\bMD4_Update", + "\\bMD4_Final", + "\\bMD4", +] + +[[library.algorithms]] +name = "RIPEMD-160" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_ripemd160\\s*\\(", + "\\bEVP_DigestInit.*RIPEMD", + "\\bRIPEMD160_Init", + "\\bRIPEMD160_Update", + "\\bRIPEMD160_Final", + "\\bRIPEMD160", +] + +[[library.algorithms]] +name = "Whirlpool" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_whirlpool\\s*\\(", + "\\bWHIRLPOOL_Init", + "\\bWHIRLPOOL_Update", + "\\bWHIRLPOOL_Final", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_blake2b512\\s*\\(", + "\\bBLAKE2b512_Init", + "\\bBLAKE2b512_Update", + "\\bBLAKE2b512_Final", +] + +[[library.algorithms]] +name = "BLAKE2s" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_blake2s256\\s*\\(", + "\\bBLAKE2s256_Init", + "\\bBLAKE2s256_Update", + "\\bBLAKE2s256_Final", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bHMAC\\s*\\(", +] + +[[library.algorithms]] +name = "DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_des_\\w+\\s*\\(", + # Explicit EVP DES mode calls + "\\bEVP_des_(?:cbc|ecb|cfb|ofb)\\s*\\(", + "\\bDES_set_key\\s*\\(", + "\\bDES_encrypt\\s*\\(", + "\\bDES_decrypt\\s*\\(", + "\\bDES_ecb_encrypt\\s*\\(", + "\\bDES_cbc_encrypt\\s*\\(", +] + +[[library.algorithms]] +name = "3DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_des_ede\\w*\\s*\\(", + "\\bEVP_des_ede3\\w*\\s*\\(", + # Explicit EVP 3DES common modes + "\\bEVP_des_ede3_cbc\\s*\\(", + "\\bEVP_des_ede3_ecb\\s*\\(", + "\\bDES_ede3_\\w+\\s*\\(", + "\\bDES3_\\w+\\s*\\(", +] + +[[library.algorithms]] +name = "Blowfish" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_bf_\\w+\\s*\\(", + # Explicit EVP Blowfish mode calls + "\\bEVP_bf_(?:cbc|ecb|cfb|ofb)\\s*\\(", + "\\bBF_set_key\\s*\\(", + "\\bBF_encrypt\\s*\\(", + "\\bBF_decrypt\\s*\\(", + "\\bBF_ecb_encrypt\\s*\\(", + "\\bBF_cbc_encrypt\\s*\\(", +] + +[[library.algorithms]] +name = "CAST5" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_cast5_\\w+\\s*\\(", + # Explicit EVP CAST5 mode calls + "\\bEVP_cast5_(?:cbc|ecb|cfb|ofb)\\s*\\(", + "\\bCAST_set_key\\s*\\(", + "\\bCAST_encrypt\\s*\\(", + "\\bCAST_decrypt\\s*\\(", + "\\bCAST_ecb_encrypt\\s*\\(", + "\\bCAST_cbc_encrypt\\s*\\(", +] + +[[library.algorithms]] +name = "Camellia" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_camellia_", + "\\bCamellia_", + "\\bEVP_camellia_128", + "\\bEVP_camellia_192", + "\\bEVP_camellia_256", + "\\bCamellia_set_key", + "\\bCamellia_encrypt", + "\\bCamellia_decrypt", +] + +[[library.algorithms]] +name = "IDEA" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_idea_", + "\\bIDEA_", + "\\bEVP_idea_cbc", + "\\bEVP_idea_ecb", + "\\bEVP_idea_cfb", + "\\bEVP_idea_ofb", + "\\bIDEA_set_encrypt_key", + "\\bIDEA_set_decrypt_key", +] + +[[library.algorithms]] +name = "RC2" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_rc2_", + "\\bRC2_", + "\\bEVP_rc2_cbc", + "\\bEVP_rc2_ecb", + "\\bEVP_rc2_cfb", + "\\bEVP_rc2_ofb", + "\\bRC2_set_key", + "\\bRC2_encrypt", + "\\bRC2_decrypt", +] + +[[library.algorithms]] +name = "RC4" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_rc4\\s*\\(", + "\\bEVP_rc4_40\\s*\\(", + "\\bRC4_set_key\\s*\\(", + "\\bRC4\\s*\\(", +] + +[[library.algorithms]] +name = "RC5" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bEVP_rc5_", + "\\bRC5_", + "\\bEVP_rc5_32_12_16", + "\\bRC5_32_set_key", + "\\bRC5_32_encrypt", + "\\bRC5_32_decrypt", +] + +[[library.algorithms]] +name = "SEED" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_seed_", + "\\bSEED_", + "\\bEVP_seed_cbc", + "\\bEVP_seed_ecb", + "\\bEVP_seed_cfb", + "\\bEVP_seed_ofb", + "\\bSEED_set_key", + "\\bSEED_encrypt", + "\\bSEED_decrypt", +] + +[[library.algorithms]] +name = "ChaCha20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_chacha20\\s*\\(", + "\\bChaCha20_", + "\\bCHACHA20", +] + +[[library.algorithms]] +name = "ChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_chacha20_poly1305\\s*\\(", + "\\bChaCha20_Poly1305", +] + +[[library.algorithms]] +name = "ARIA" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_aria_", + "\\bARIA_", + "\\bEVP_aria_128", + "\\bEVP_aria_192", + "\\bEVP_aria_256", + "\\bARIA_set_encrypt_key", + "\\bARIA_set_decrypt_key", + "\\bARIA_encrypt", + "\\bARIA_decrypt", +] + +[[library.algorithms]] +name = "SM4" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sm4_", + "\\bSM4_", + "\\bEVP_sm4_cbc", + "\\bEVP_sm4_ecb", + "\\bEVP_sm4_cfb", + "\\bEVP_sm4_ofb", + "\\bSM4_set_key", + "\\bSM4_encrypt", + "\\bSM4_decrypt", +] + [[library]] name = "libsodium" languages = ["C", "C++"] @@ -32,12 +507,79 @@ include = [ ] apis = [ "\\bcrypto_secretbox_(?:easy|open_easy)\\s*\\(", + "\\bcrypto_aead_aes256gcm_(?:encrypt|decrypt|keygen)\\s*\\(", "\\bcrypto_aead_chacha20poly1305_ietf_(?:encrypt|decrypt)\\s*\\(", "\\bcrypto_aead_xchacha20poly1305_ietf_(?:encrypt|decrypt)\\s*\\(", "\\bcrypto_auth(?:_verify)?\\s*\\(", - "\\bcrypto_sign_(?:detached|verify_detached)\\s*\\(", + "\\bcrypto_auth_hmacsha256(?:_keygen|_verify)?\\s*\\(", + "\\bcrypto_hash_sha256\\s*\\(", + "\\bcrypto_sign(?:_keypair|_detached|_verify_detached|_open)?\\s*\\(", "\\bcrypto_generichash\\s*\\(", "\\bcrypto_scalarmult\\s*\\(", + "\\bsodium_init\\s*\\(", + "\\brandombytes_buf\\s*\\(", +] + +# Algorithm definitions for libsodium +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto_aead_aes256gcm", +] + +[[library.algorithms]] +name = "ChaCha20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto_aead_chacha20poly1305", + "\\bcrypto_aead_xchacha20poly1305", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto_hash_sha256", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto_auth_hmacsha256", +] + +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bcrypto_sign(?:_keypair|_open)?\\s*\\(", + "\\bcrypto_sign_ed25519", + "\\bed25519", +] + +[[library.algorithms]] +name = "X25519" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bcrypto_scalarmult_curve25519", + "\\bcurve25519", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto_generichash", + "\\bblake2b", ] [[library]] @@ -51,6 +593,434 @@ apis = [ "\\bgcry_[A-Za-z0-9_]+\\s*\\(", ] +# Algorithm definitions for Libgcrypt +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_pk_genkey.*RSA", + "\\bGCRY_PK_RSA", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*AES", + "\\bGCRY_CIPHER_AES", + "\\bGCRY_CIPHER_AES128", + "\\bGCRY_CIPHER_AES192", + "\\bGCRY_CIPHER_AES256", +] + +[[library.algorithms]] +name = "DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*DES", + "\\bGCRY_CIPHER_DES", +] + +[[library.algorithms]] +name = "3DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*3DES", + "\\bGCRY_CIPHER_3DES", + "\\bGCRY_CIPHER_DES_SK", +] + +[[library.algorithms]] +name = "Blowfish" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*BLOWFISH", + "\\bGCRY_CIPHER_BLOWFISH", +] + +[[library.algorithms]] +name = "CAST5" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*CAST5", + "\\bGCRY_CIPHER_CAST5", +] + +[[library.algorithms]] +name = "Twofish" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*TWOFISH", + "\\bGCRY_CIPHER_TWOFISH", + "\\bGCRY_CIPHER_TWOFISH128", +] + +[[library.algorithms]] +name = "Serpent" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*SERPENT", + "\\bGCRY_CIPHER_SERPENT128", + "\\bGCRY_CIPHER_SERPENT192", + "\\bGCRY_CIPHER_SERPENT256", +] + +[[library.algorithms]] +name = "Camellia" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*CAMELLIA", + "\\bGCRY_CIPHER_CAMELLIA128", + "\\bGCRY_CIPHER_CAMELLIA192", + "\\bGCRY_CIPHER_CAMELLIA256", +] + +[[library.algorithms]] +name = "SEED" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*SEED", + "\\bGCRY_CIPHER_SEED", +] + +[[library.algorithms]] +name = "IDEA" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*IDEA", + "\\bGCRY_CIPHER_IDEA", +] + +[[library.algorithms]] +name = "RC2" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*RC2", + "\\bGCRY_CIPHER_RFC2268_40", + "\\bGCRY_CIPHER_RFC2268_128", +] + +[[library.algorithms]] +name = "RC4" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*ARCFOUR", + "\\bGCRY_CIPHER_ARCFOUR", +] + +[[library.algorithms]] +name = "Salsa20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*SALSA20", + "\\bGCRY_CIPHER_SALSA20", + "\\bGCRY_CIPHER_SALSA20R12", +] + +[[library.algorithms]] +name = "ChaCha20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_cipher_open.*CHACHA20", + "\\bGCRY_CIPHER_CHACHA20", +] + +[[library.algorithms]] +name = "GOST28147" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_cipher_open.*GOST", + "\\bGCRY_CIPHER_GOST28147", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*SHA256", + "\\bGCRY_MD_SHA256", + "\\bgcry_md_hash_buffer.*SHA256", +] + +[[library.algorithms]] +name = "SHA-1" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_md_open.*SHA1", + "\\bGCRY_MD_SHA1", + "\\bgcry_md_hash_buffer.*SHA1", +] + +[[library.algorithms]] +name = "SHA-224" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*SHA224", + "\\bGCRY_MD_SHA224", +] + +[[library.algorithms]] +name = "SHA-384" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*SHA384", + "\\bGCRY_MD_SHA384", +] + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*SHA512", + "\\bGCRY_MD_SHA512", +] + +[[library.algorithms]] +name = "MD5" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_md_open.*MD5", + "\\bGCRY_MD_MD5", + "\\bgcry_md_hash_buffer.*MD5", +] + +[[library.algorithms]] +name = "MD4" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_md_open.*MD4", + "\\bGCRY_MD_MD4", +] + +[[library.algorithms]] +name = "RIPEMD-160" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bgcry_md_open.*RMD160", + "\\bGCRY_MD_RMD160", +] + +[[library.algorithms]] +name = "Whirlpool" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*WHIRLPOOL", + "\\bGCRY_MD_WHIRLPOOL", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*BLAKE2B", + "\\bGCRY_MD_BLAKE2B_512", +] + +[[library.algorithms]] +name = "BLAKE2s" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*BLAKE2S", + "\\bGCRY_MD_BLAKE2S_256", +] + +[[library.algorithms]] +name = "SHA3-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*SHA3_256", + "\\bGCRY_MD_SHA3_256", +] + +[[library.algorithms]] +name = "SHA3-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bgcry_md_open.*SHA3_512", + "\\bGCRY_MD_SHA3_512", +] + +[[library]] +name = "libMD" +languages = ["C", "C++"] +[library.patterns] +include = [ + "^\\s*#\\s*include\\s*", + "^\\s*#\\s*include\\s*", + "^\\s*#\\s*include\\s*", + "^\\s*#\\s*include\\s*", +] +apis = [ + "\\bMD[45]_?[A-Za-z]+\\s*\\(", + "\\bSHA[0-9]*_?[A-Za-z]+\\s*\\(", + "\\bRIPEMD160_[A-Za-z]+\\s*\\(", +] + +# Algorithm definitions for libMD +[[library.algorithms]] +name = "SHA-1" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bSHA1_End", + "\\bSHA1_Data", + "\\bSHA1_File", + "\\bSHA1_FileChunk", + "\\bSHA_End", + "\\bSHA_Data", + "\\bSHA_File", + "\\bSHA_FileChunk", +] + +[[library.algorithms]] +name = "SHA-224" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSHA224_End", + "\\bSHA224_Data", + "\\bSHA224_File", + "\\bSHA224_FileChunk", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSHA256_End", + "\\bSHA256_Data", + "\\bSHA256_File", + "\\bSHA256_FileChunk", +] + +[[library.algorithms]] +name = "SHA-384" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSHA384_End", + "\\bSHA384_Data", + "\\bSHA384_File", + "\\bSHA384_FileChunk", +] + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSHA512_End", + "\\bSHA512_Data", + "\\bSHA512_File", + "\\bSHA512_FileChunk", +] + +[[library.algorithms]] +name = "MD4" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bMD4Init", + "\\bMD4Update", + "\\bMD4Pad", + "\\bMD4Final", + "\\bMD4End", + "\\bMD4File", + "\\bMD4FileChunk", + "\\bMD4Data", +] + +[[library.algorithms]] +name = "MD5" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bMD5Init", + "\\bMD5Update", + "\\bMD5Pad", + "\\bMD5Final", + "\\bMD5End", + "\\bMD5File", + "\\bMD5FileChunk", + "\\bMD5Data", +] + +[[library.algorithms]] +name = "RIPEMD-160" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bRIPEMD160_Init", + "\\bRIPEMD160_Update", + "\\bRIPEMD160_Final", + "\\bRIPEMD160_End", + "\\bRIPEMD160_File", + "\\bRIPEMD160_FileChunk", + "\\bRIPEMD160_Data", +] + +[[library]] +name = "GlibC" +languages = ["C", "C++"] +[library.patterns] +include = [ + "^\\s*#\\s*include\\s*", + "^\\s*#\\s*include\\s*", +] +apis = [ + "\\bg_checksum_[A-Za-z0-9_]+\\s*\\(", + "\\bg_compute_checksum_[A-Za-z0-9_]+\\s*\\(", +] + +# Algorithm definitions for GlibC +[[library.algorithms]] +name = "Hash" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bg_checksum_type_get_length", + "\\bg_checksum_new", + "\\bg_checksum_copy", + "\\bg_checksum_free", + "\\bg_checksum_reset", + "\\bg_checksum_update", + "\\bg_checksum_get_string", + "\\bg_checksum_get_digest", + "\\bg_compute_checksum_for_data", + "\\bg_compute_checksum_for_string", + "\\bg_compute_checksum_for_bytes", +] + [[library]] name = "MbedTLS" languages = ["C", "C++"] @@ -62,6 +1032,34 @@ apis = [ "\\bmbedtls_[A-Za-z0-9_]+\\s*\\(", ] +# Algorithm definitions for MbedTLS +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bmbedtls_rsa_", + "\\bmbedtls_pk_.*rsa", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bmbedtls_aes_", + "\\bmbedtls_gcm_", +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bmbedtls_ecdsa_", + "\\bmbedtls_ecp_", +] + [[library]] name = "wolfSSL/wolfCrypt" languages = ["C", "C++"] @@ -73,6 +1071,34 @@ apis = [ "\\bwc_[A-Za-z0-9_]+\\s*\\(", ] +# Algorithm definitions for wolfSSL/wolfCrypt +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bwc_RsaPublicKeyDecode", + "\\bwc_MakeRsaKey", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bwc_AesSetKey", + "\\bwc_AesGcmSetKey", +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bwc_ecc_", + "\\bwc_EccPrivateKeyDecode", +] + [[library]] name = "Crypto++" languages = ["C++"] @@ -85,6 +1111,711 @@ apis = [ "\\bCryptoPP::[A-Za-z0-9_:]+\\b", # namespace/class use ] +# Algorithm definitions for Crypto++ +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::RSA", + "\\bRSA::", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::AES", + "\\bGCM", + "\\bAES::Encryption", + "\\bAES::Decryption", +] + +[[library.algorithms]] +name = "DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::DES", + "\\bDES::Encryption", + "\\bDES::Decryption", +] + +[[library.algorithms]] +name = "3DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::DES_EDE3", + "\\bDES_EDE3::Encryption", + "\\bDES_EDE3::Decryption", +] + +[[library.algorithms]] +name = "Blowfish" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::Blowfish", + "\\bBlowfish::Encryption", + "\\bBlowfish::Decryption", +] + +[[library.algorithms]] +name = "Twofish" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::Twofish", + "\\bTwofish::Encryption", + "\\bTwofish::Decryption", +] + +[[library.algorithms]] +name = "Serpent" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::Serpent", + "\\bSerpent::Encryption", + "\\bSerpent::Decryption", +] + +[[library.algorithms]] +name = "CAST128" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::CAST128", + "\\bCAST128::Encryption", + "\\bCAST128::Decryption", +] + +[[library.algorithms]] +name = "CAST256" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::CAST256", + "\\bCAST256::Encryption", + "\\bCAST256::Decryption", +] + +[[library.algorithms]] +name = "RC2" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::RC2", + "\\bRC2::Encryption", + "\\bRC2::Decryption", +] + +[[library.algorithms]] +name = "RC4" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::ARC4", + "\\bARC4::", + "\\bCryptoPP::MARC4", +] + +[[library.algorithms]] +name = "RC5" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::RC5", + "\\bRC5::Encryption", + "\\bRC5::Decryption", +] + +[[library.algorithms]] +name = "RC6" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::RC6", + "\\bRC6::Encryption", + "\\bRC6::Decryption", +] + +[[library.algorithms]] +name = "IDEA" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::IDEA", + "\\bIDEA::Encryption", + "\\bIDEA::Decryption", +] + +[[library.algorithms]] +name = "Camellia" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::Camellia", + "\\bCamellia::Encryption", + "\\bCamellia::Decryption", +] + +[[library.algorithms]] +name = "SEED" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SEED", + "\\bSEED::Encryption", + "\\bSEED::Decryption", +] + +[[library.algorithms]] +name = "TEA" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::TEA", + "\\bTEA::Encryption", + "\\bTEA::Decryption", +] + +[[library.algorithms]] +name = "XTEA" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::XTEA", + "\\bXTEA::Encryption", + "\\bXTEA::Decryption", +] + +[[library.algorithms]] +name = "Salsa20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::Salsa20", + "\\bSalsa20::", +] + +[[library.algorithms]] +name = "ChaCha20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::ChaCha", + "\\bChaCha::", + "\\bCryptoPP::ChaChaTLS", +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::ECDSA", + "\\bECDSA::", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SHA256", + "\\bSHA256::", +] + +[[library.algorithms]] +name = "SHA-1" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::SHA1", + "\\bSHA1::", + "\\bSHA::", +] + +[[library.algorithms]] +name = "SHA-224" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SHA224", + "\\bSHA224::", +] + +[[library.algorithms]] +name = "SHA-384" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SHA384", + "\\bSHA384::", +] + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SHA512", + "\\bSHA512::", +] + +[[library.algorithms]] +name = "SHA3-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SHA3_256", + "\\bSHA3_256::", +] + +[[library.algorithms]] +name = "SHA3-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::SHA3_512", + "\\bSHA3_512::", +] + +[[library.algorithms]] +name = "MD5" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::MD5", + "\\bMD5::", +] + +[[library.algorithms]] +name = "MD4" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::MD4", + "\\bMD4::", +] + +[[library.algorithms]] +name = "RIPEMD-160" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCryptoPP::RIPEMD160", + "\\bRIPEMD160::", +] + +[[library.algorithms]] +name = "Whirlpool" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::Whirlpool", + "\\bWhirlpool::", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::BLAKE2b", + "\\bBLAKE2b::", +] + +[[library.algorithms]] +name = "BLAKE2s" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCryptoPP::BLAKE2s", + "\\bBLAKE2s::", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bHMAC", + "\\bCryptoPP::HMAC", +] + +[[library]] +name = "Google Tink (C++)" +languages = ["C++"] +[library.patterns] +include = [ + "^\\s*#\\s*include\\s*\"tink/", +] +apis = [ + "\\bcrypto::tink::[A-Za-z0-9_]+", + "\\btink::[A-Za-z0-9_]+", + "\\b(?:Aead|Mac|HybridDecrypt|HybridEncrypt|PublicKeySign|PublicKeyVerify)Config::Register", + "\\b(?:AeadKeyTemplates|MacKeyTemplates|SignatureKeyTemplates|HybridKeyTemplates)::", + "\\bKeysetHandle::", + "\\bCleartextKeysetHandle::", + "\\bHybridConfig::Register", + "\\bEciesAeadHkdfDemHelper", + "\\bHpkeContext", + "\\bDeterministicAeadConfig::Register", + "\\bStreamingAeadConfig::Register", +] + +# Algorithm definitions for Google Tink (C++) +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates::Aes\\d+Gcm", + "\\bAesGcmKeyManager", + "\\btink::Aead", + "\\bAES\\d+_GCM", +] + +[[library.algorithms]] +name = "AES-CTR-HMAC" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates::Aes\\d+CtrHmacSha256", + "\\bAesCtrHmacAeadKeyManager", + "\\bAES\\d+_CTR_HMAC_SHA256", +] + +[[library.algorithms]] +name = "AES-EAX" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates::Aes\\d+Eax", + "\\bAesEaxKeyManager", + "\\bAES\\d+_EAX", +] + +[[library.algorithms]] +name = "AES-GCM-SIV" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates::Aes\\d+GcmSiv", + "\\bAesGcmSivKeyManager", + "\\bAES\\d+_GCM_SIV", +] + +[[library.algorithms]] +name = "XChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates::XChaCha20Poly1305", + "\\bXChaCha20Poly1305KeyManager", + "\\bXCHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "ChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bChaCha20Poly1305KeyManager", + "\\bCHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "KMS Envelope AEAD" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bKmsEnvelopeAead", + "\\bKmsEnvelopeAeadKeyManager", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMacKeyTemplates::HmacSha256", + "\\bHmacKeyManager", + "\\btink::Mac", + "\\bHMAC_SHA256", +] + +[[library.algorithms]] +name = "HMAC-SHA512" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMacKeyTemplates::HmacSha512", + "\\bHMAC_SHA512", +] + +[[library.algorithms]] +name = "AES-CMAC" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMacKeyTemplates::AesCmac", + "\\bAesCmacKeyManager", + "\\bAES_CMAC", +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bSignatureKeyTemplates::EcdsaP256", + "\\bEcdsaSignKeyManager", + "\\bEcdsaVerifyKeyManager", + "\\btink::PublicKeySign", + "\\btink::PublicKeyVerify", +] + +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSignatureKeyTemplates::Ed25519", + "\\bEd25519SignKeyManager", + "\\bEd25519VerifyKeyManager", +] + +[[library.algorithms]] +name = "RSA-PSS" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bSignatureKeyTemplates::RsaPss\\d+", + "\\bRsaSsaPssSignKeyManager", + "\\bRsaSsaPssVerifyKeyManager", +] + +[[library.algorithms]] +name = "RSA-PKCS1" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bSignatureKeyTemplates::RsaPkcs1_\\d+", + "\\bRsaSsaPkcs1SignKeyManager", + "\\bRsaSsaPkcs1VerifyKeyManager", +] + +[[library.algorithms]] +name = "ECIES-P256-HKDF-HMAC-SHA256-AES128-GCM" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm\\s*\\(", + "\\bEciesAeadHkdfPrivateKeyManager", + "\\bEciesAeadHkdfPublicKeyManager", + "\\btink::HybridEncrypt", + "\\btink::HybridDecrypt", + "\\bECIES_P256_HKDF_HMAC_SHA256_AES128_GCM", +] + +[[library.algorithms]] +name = "ECIES-P256-HKDF-HMAC-SHA256-AES128-CTR-HMAC" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesP256HkdfHmacSha256Aes128CtrHmacSha256\\s*\\(", + "\\bECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256", +] + +[[library.algorithms]] +name = "ECIES-P256-Compressed-HKDF-AES128-GCM" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesP256CompressedHkdfHmacSha256Aes128Gcm\\s*\\(", + "\\bECIES_P256_COMPRESSED_HKDF_HMAC_SHA256_AES128_GCM", +] + +[[library.algorithms]] +name = "ECIES-P256-Compressed-HKDF-AES128-CTR-HMAC" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesP256CompressedHkdfHmacSha256Aes128CtrHmacSha256", + "\\bECIES_P256_COMPRESSED_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256", +] + +[[library.algorithms]] +name = "ECIES-X25519-HKDF-SHA256-AES128-GCM" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesX25519HkdfHmacSha256Aes128Gcm", + "\\bEciesX25519HkdfDemHelper", + "\\bECIES_X25519_HKDF_HMAC_SHA256_AES128_GCM", +] + +[[library.algorithms]] +name = "ECIES-X25519-HKDF-SHA256-AES128-CTR-HMAC" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesX25519HkdfHmacSha256Aes128CtrHmacSha256", + "\\bECIES_X25519_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256", +] + +[[library.algorithms]] +name = "ECIES-X25519-HKDF-SHA256-AES256-GCM" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesX25519HkdfHmacSha256Aes256Gcm", + "\\bECIES_X25519_HKDF_HMAC_SHA256_AES256_GCM", +] + +[[library.algorithms]] +name = "ECIES-X25519-HKDF-SHA256-XChaCha20-Poly1305" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::EciesX25519HkdfHmacSha256XChaCha20Poly1305", + "\\bECIES_X25519_HKDF_HMAC_SHA256_XCHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "DHKEM-X25519-HKDF-SHA256" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::DhkemX25519HkdfSha256HkdfSha256Aes128Gcm", + "\\bDHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM", + "\\bHpkePrivateKeyManager", + "\\bHpkePublicKeyManager", +] + +[[library.algorithms]] +name = "DHKEM-X25519-HKDF-SHA256-AES256-GCM" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::DhkemX25519HkdfSha256HkdfSha256Aes256Gcm", + "\\bDHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM", +] + +[[library.algorithms]] +name = "DHKEM-X25519-HKDF-SHA256-ChaCha20-Poly1305" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::DhkemX25519HkdfSha256HkdfSha256ChaCha20Poly1305", + "\\bDHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "DHKEM-P256-HKDF-SHA256" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::DhkemP256HkdfSha256HkdfSha256Aes128Gcm", + "\\bDHKEM_P256_HKDF_SHA256_HKDF_SHA256_AES_128_GCM", +] + +[[library.algorithms]] +name = "DHKEM-P384-HKDF-SHA384" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::DhkemP384HkdfSha384HkdfSha384Aes256Gcm", + "\\bDHKEM_P384_HKDF_SHA384_HKDF_SHA384_AES_256_GCM", +] + +[[library.algorithms]] +name = "DHKEM-P521-HKDF-SHA512" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bHybridKeyTemplates::DhkemP521HkdfSha512HkdfSha512Aes256Gcm", + "\\bDHKEM_P521_HKDF_SHA512_HKDF_SHA512_AES_256_GCM", +] + +[[library.algorithms]] +name = "AES-SIV" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bDeterministicAeadKeyTemplates::Aes256Siv", + "\\bAesSivKeyManager", + "\\btink::DeterministicAead", + "\\bAES256_SIV", +] + +[[library.algorithms]] +name = "AES-CTR-HMAC-Streaming" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bStreamingAeadKeyTemplates::Aes128CtrHmacSha256", + "\\bStreamingAeadKeyTemplates::Aes256CtrHmacSha256", + "\\bAesCtrHmacStreamingKeyManager", + "\\btink::StreamingAead", + "\\bAES\\d+_CTR_HMAC_SHA256", +] + +[[library.algorithms]] +name = "AES-GCM-HKDF-Streaming" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bStreamingAeadKeyTemplates::Aes128GcmHkdf", + "\\bStreamingAeadKeyTemplates::Aes256GcmHkdf", + "\\bAesGcmHkdfStreamingKeyManager", + "\\bAES\\d+_GCM_HKDF", +] + +[[library.algorithms]] +name = "HKDF" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bHkdf", + "\\bHkdfStreamingPrf", + "\\btink::subtle::Hkdf", +] + +[[library.algorithms]] +name = "HMAC-PRF" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bPrfKeyTemplates::HmacSha256", + "\\bPrfKeyTemplates::HmacSha512", + "\\bHmacPrfKeyManager", + "\\btink::Prf", +] + +[[library.algorithms]] +name = "AES-CMAC-PRF" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bPrfKeyTemplates::AesCmac", + "\\bAesCmacPrfKeyManager", +] + +[[library.algorithms]] +name = "HKDF-PRF" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bPrfKeyTemplates::HkdfSha256", + "\\bHkdfPrfKeyManager", +] + [[library]] name = "Botan" languages = ["C++"] @@ -92,27 +1823,437 @@ languages = ["C++"] include = [ "^\\s*#\\s*include\\s*", ] -apis = [ - "\\bBotan::[A-Za-z0-9_:]+\\s*\\(", - "\\bBotan::[A-Za-z0-9_:]+\\b", +apis = [ + "\\bBotan::[A-Za-z0-9_:]+\\s*\\(", + "\\bBotan::[A-Za-z0-9_:]+\\b", +] + +# Algorithm definitions for Botan +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::RSA_PrivateKey", + "\\bRSA_PrivateKey", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "RSA_PrivateKey\\s*\\([^,]*,\\s*(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::AEAD_Mode.*AES.*GCM", + "\\bAES-\\d+/GCM", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*AES", + "\\bAES-128", + "\\bAES-192", + "\\bAES-256", +] + +[[library.algorithms]] +name = "DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::BlockCipher.*DES", + "\\bDES", +] + +[[library.algorithms]] +name = "3DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::BlockCipher.*TripleDES", + "\\bTripleDES", + "\\b3DES", + "\\bDES-EDE", +] + +[[library.algorithms]] +name = "Blowfish" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::BlockCipher.*Blowfish", + "\\bBlowfish", +] + +[[library.algorithms]] +name = "Twofish" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*Twofish", + "\\bTwofish", +] + +[[library.algorithms]] +name = "Serpent" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*Serpent", + "\\bSerpent", +] + +[[library.algorithms]] +name = "CAST-128" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::BlockCipher.*CAST-128", + "\\bCAST-128", +] + +[[library.algorithms]] +name = "CAST-256" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*CAST-256", + "\\bCAST-256", +] + +[[library.algorithms]] +name = "Camellia" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*Camellia", + "\\bCamellia", +] + +[[library.algorithms]] +name = "SEED" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*SEED", + "\\bSEED", +] + +[[library.algorithms]] +name = "IDEA" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::BlockCipher.*IDEA", + "\\bIDEA", +] + +[[library.algorithms]] +name = "RC4" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::StreamCipher.*RC4", + "\\bRC4", + "\\bARC4", +] + +[[library.algorithms]] +name = "ChaCha20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::StreamCipher.*ChaCha", + "\\bChaCha20", + "\\bChaCha", +] + +[[library.algorithms]] +name = "Salsa20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::StreamCipher.*Salsa20", + "\\bSalsa20", +] + +[[library.algorithms]] +name = "ARIA" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*ARIA", + "\\bARIA", +] + +[[library.algorithms]] +name = "SM4" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*SM4", + "\\bSM4", +] + +[[library.algorithms]] +name = "Threefish" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::BlockCipher.*Threefish", + "\\bThreefish-512", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA-256", + "\\bSHA-256", +] + +[[library.algorithms]] +name = "SHA-1" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA-1", + "\\bSHA-1", +] + +[[library.algorithms]] +name = "SHA-224" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA-224", + "\\bSHA-224", +] + +[[library.algorithms]] +name = "SHA-384" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA-384", + "\\bSHA-384", +] + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA-512", + "\\bSHA-512", +] + +[[library.algorithms]] +name = "SHA3-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA3-256", + "\\bSHA3-256", +] + +[[library.algorithms]] +name = "SHA3-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*SHA3-512", + "\\bSHA3-512", +] + +[[library.algorithms]] +name = "MD5" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::HashFunction.*MD5", + "\\bMD5", +] + +[[library.algorithms]] +name = "RIPEMD-160" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBotan::HashFunction.*RIPEMD-160", + "\\bRIPEMD-160", +] + +[[library.algorithms]] +name = "Whirlpool" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*Whirlpool", + "\\bWhirlpool", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bBotan::HashFunction.*BLAKE2b", + "\\bBLAKE2b", +] + +# ========================= +# Java +# ========================= + +[[library]] +name = "Java JCA/JCE" +languages = ["Java"] +[library.patterns] +include = [ + "^\\s*import\\s+javax\\.crypto\\.", + "^\\s*import\\s+java\\.security\\.", +] +apis = [ + "\\b(?:Cipher|MessageDigest|Signature|KeyPairGenerator|Mac)\\.getInstance\\s*\\(", + "\\bKeyFactory\\.getInstance\\s*\\(", + "\\bKeyAgreement\\.getInstance\\s*\\(", + "\\bSecretKeySpec\\s*\\(", + # ParameterSpec classes + "\\bIvParameterSpec\\s*\\(", + "\\bPBEParameterSpec\\s*\\(", + "\\bRC2ParameterSpec\\s*\\(", + "\\bRC5ParameterSpec\\s*\\(", + "\\bGCMParameterSpec\\s*\\(", + "\\bChaCha20ParameterSpec\\s*\\(", + "\\bDHParameterSpec\\s*\\(", + "\\bDSAParameterSpec\\s*\\(", + "\\bECParameterSpec\\b", + "\\bRSAKeyGenParameterSpec\\s*\\(", + "\\bMGF1ParameterSpec\\b", + "\\bPSSParameterSpec\\s*\\(", + "\\bOAEPParameterSpec\\s*\\(", +] + +# Algorithm definitions for JCA/JCE +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bKeyPairGenerator\\.getInstance\\s*\\(\\s*[\"']RSA[\"']", + "\\bRSA", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "RSAKeyGenParameterSpec\\s*\\(\\s*(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']AES", + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']AES/(?:ECB|CBC|CFB|CFB8|CFB128|OFB|OFB8|OFB128|CTR|GCM|CCM|CTS)/(?:NoPadding|PKCS5Padding|ISO10126Padding)[\"']", + "\\bKeyGenerator\\.getInstance\\s*\\(\\s*[\"']AES[\"']", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "init\\s*\\(\\s*(\\d+)" +default_value = 256 + +[[library.algorithms]] +name = "DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']DES/(?:ECB|CBC)/(?:NoPadding|PKCS5Padding)[\"']", +] + +[[library.algorithms]] +name = "3DES" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']DESede/(?:ECB|CBC)/(?:NoPadding|PKCS5Padding)[\"']", +] + +[[library.algorithms]] +name = "Blowfish" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']Blowfish/(?:ECB|CBC)/(?:NoPadding|PKCS5Padding)[\"']", +] + +[[library.algorithms]] +name = "RC4" +primitive = "aead" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']RC4[\"']", +] + +[[library.algorithms]] +name = "ChaCha20" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']ChaCha20[\"']", +] + +[[library.algorithms]] +name = "ChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']ChaCha20-Poly1305[\"']", ] -# ========================= -# Java -# ========================= +[[library.algorithms]] +name = "RSA-Cipher" +primitive = "pke" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\(\\s*[\"']RSA/ECB/(?:PKCS1Padding|OAEPPadding|OAEPWithSHA-1AndMGF1Padding|OAEPWithSHA-256AndMGF1Padding|NoPadding)[\"']", +] -[[library]] -name = "Java JCA/JCE" -languages = ["Java"] -[library.patterns] -include = [ - "^\\s*import\\s+javax\\.crypto\\.", - "^\\s*import\\s+java\\.security\\.", +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bSignature\\.getInstance\\s*\\([^)]*ECDSA", + "\\bKeyPairGenerator\\.getInstance\\s*\\(\\s*[\"']EC[\"']", +] +[[library.algorithms.parameter_patterns]] +name = "curve" +pattern = "initialize\\s*\\(\\s*(256|384|521)" +default_value = "P-256" + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMessageDigest\\.getInstance\\s*\\([^)]*SHA-?256", + "\\bSHA256with", ] -apis = [ - "\\b(?:Cipher|MessageDigest|Signature|KeyPairGenerator)\\.getInstance\\s*\\(", - "\\bKeyFactory\\.getInstance\\s*\\(", - "\\bKeyAgreement\\.getInstance\\s*\\(", + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMac\\.getInstance\\s*\\([^)]*HmacSHA256", ] [[library]] @@ -127,6 +2268,53 @@ apis = [ "\\bnew\\s+org\\.bouncycastle\\.[A-Za-z0-9_.]+\\s*\\(", ] +# Algorithm definitions for BouncyCastle +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bBouncyCastleProvider", + "\\bKeyPairGenerator\\.getInstance\\s*\\([^)]*RSA[^)]*BC", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "initialize\\s*\\([^)]*?(\\d{4})" +default_value = 2048 + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bKeyPairGenerator\\.getInstance\\s*\\([^)]*EC[^)]*BC", + "\\bSignature\\.getInstance\\s*\\([^)]*ECDSA[^)]*BC", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\([^)]*AES[^)]*BC", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMessageDigest\\.getInstance\\s*\\([^)]*SHA-?256[^)]*BC", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMac\\.getInstance\\s*\\([^)]*HmacSHA256[^)]*BC", +] + [[library]] name = "Google Tink (Java)" languages = ["Java"] @@ -136,7 +2324,88 @@ include = [ ] apis = [ "\\bTinkConfig\\.register\\s*\\(", + "\\b(?:AeadConfig|MacConfig|SignatureConfig)\\.register\\s*\\(", "\\b(?:Aead|Mac|HybridDecrypt|HybridEncrypt|PublicKeySign|PublicKeyVerify)\\b", + "\\b(?:AeadKeyTemplates|MacKeyTemplates|SignatureKeyTemplates)\\b", +] + +# Algorithm definitions for Google Tink (Java) +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates\\.AES\\d+_GCM", + "\\bAead", + "\\bAesGcmKeyManager", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "AES(\\d+)_GCM" +default_value = 256 + +[[library.algorithms]] +name = "AES-CTR-HMAC" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates\\.AES\\d+_CTR_HMAC_SHA256", + "\\bAesCtrHmacAeadKeyManager", +] + +[[library.algorithms]] +name = "AES-EAX" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates\\.AES\\d+_EAX", + "\\bAesEaxKeyManager", +] + +[[library.algorithms]] +name = "AES-GCM-SIV" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates\\.AES\\d+_GCM_SIV", + "\\bAesGcmSivKeyManager", +] + +[[library.algorithms]] +name = "ChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates\\.CHACHA20_POLY1305", + "\\bChaCha20Poly1305KeyManager", +] + +[[library.algorithms]] +name = "XChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAeadKeyTemplates\\.XCHACHA20_POLY1305", + "\\bXChaCha20Poly1305KeyManager", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMacKeyTemplates\\.HMAC_SHA256", + "\\bMac\\.class", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSHA256", + "\\bPrfKeyTemplates\\.HMAC_SHA256_PRF", + "\\bPrf\\.class", ] [[library]] @@ -151,6 +2420,24 @@ apis = [ "\\bOpenSSLProvider\\b", ] +# Algorithm definitions for Conscrypt +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bConscrypt\\.newProvider", + "\\bCipher\\.getInstance\\s*\\([^)]*AES.*GCM", +] + +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bKeyPairGenerator\\.getInstance\\s*\\([^)]*RSA", +] + # ========================= # Go # ========================= @@ -160,10 +2447,95 @@ name = "Go std crypto" languages = ["Go"] [library.patterns] include = [ - "^\\s*import\\s*(?:\\(.*\\)|)\\s*[\\s\\S]*?\"crypto/(?:aes|des|rc4|sha\\d*|md5|rsa|ecdsa|ed25519|x509|rand|tls)\"", + "^\\s*import\\s*(?:\\(.*\\)|)\\s*[\\s\\S]*?\"crypto/(?:aes|des|rc4|sha\\d*|md5|rsa|ecdsa|ed25519|x509|rand|tls|cipher|hmac)\"", + "^\\s*import\\s*(?:\\(.*\\)|)\\s*[\\s\\S]*?\"golang\\.org/x/crypto/", ] apis = [ - "\\bcrypto\\.[A-Z][A-Za-z0-9_]*\\b", + "\\baes\\.NewCipher\\b", + "\\bcipher\\.New(?:GCM|CTR|CFB|OFB)\\b", + "\\bsha256\\.(?:Sum256|New)\\b", + "\\bhmac\\.(?:New|Equal)\\b", + "\\brsa\\.(?:GenerateKey|SignPKCS1v15|VerifyPKCS1v15|EncryptOAEP)\\b", + "\\becdsa\\.(?:GenerateKey|Sign|Verify)\\b", + "\\bed25519\\.(?:GenerateKey|Sign|Verify)\\b", +] + +# Algorithm definitions for Go std crypto +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcipher\\.NewGCM", + "\\baes\\.NewCipher", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsha256\\.Sum256", + "\\bsha256\\.New", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bhmac\\.New.*sha256", +] + +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\brsa\\.GenerateKey", + "\\brsa\\.SignPKCS1v15", + "\\brsa\\.VerifyPKCS1v15", + "\\brsa\\.EncryptOAEP", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "GenerateKey\\s*\\([^,]*,\\s*(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\becdsa\\.GenerateKey", + "\\becdsa\\.Sign", +] + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baes\\.NewCipher", + "\\bcipher\\.NewGCM", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsha256\\.Sum256", + "\\bsha256\\.New", +] + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsha512\\.Sum512", + "\\bsha512\\.New", ] [[library]] @@ -177,6 +2549,33 @@ apis = [ "\\bx?crypto\\b", # weak signal; primary detection via import above ] +# Algorithm definitions for golang.org/x/crypto +[[library.algorithms]] +name = "ChaCha20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bchacha20poly1305\\.New", + "\\bchachapolykey", +] + +[[library.algorithms]] +name = "Argon2" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bargon2\\.IDKey", + "\\bargon2\\.Key", +] + +[[library.algorithms]] +name = "PBKDF2" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bpbkdf2\\.Key", +] + [[library]] name = "Google Tink (Go)" languages = ["Go"] @@ -185,7 +2584,75 @@ include = [ "^\\s*import\\s*(?:\\(.*\\)|)\\s*[\\s\\S]*?\"github\\.com/google/tink/go/", ] apis = [ - "\\btink\\/[A-Za-z0-9_/]+\\b", + "\\baead\\.(?:Init|New|AES256GCMKeyTemplate)\\s*\\(", + "\\bmac\\.(?:Init|New|HMACSHA256Tag256KeyTemplate)\\s*\\(", + "\\bsignature\\.(?:Init|NewSigner|NewVerifier|RSA_PSS_3072_SHA256_F4_KeyTemplate)\\s*\\(", + "\\bkeyset\\.NewHandle\\s*\\(", +] + +# Algorithm definitions for Google Tink (Go) +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.AES\\d+GCMKeyTemplate", + "\\baead\\.New", + "\\baesgcm\\.", +] + +[[library.algorithms]] +name = "AES-CTR-HMAC" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.AES\\d+CTRHMACSHA256KeyTemplate", + "\\baesctrhmac\\.", +] + +[[library.algorithms]] +name = "AES-GCM-SIV" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.AES\\d+GCMSIVKeyTemplate", + "\\baesgcmsiv\\.", +] + +[[library.algorithms]] +name = "ChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.ChaCha20Poly1305KeyTemplate", + "\\bchacha20poly1305\\.", +] + +[[library.algorithms]] +name = "XChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.XChaCha20Poly1305KeyTemplate", + "\\bxchacha20poly1305\\.", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bmac\\.HMACSHA256Tag256KeyTemplate", + "\\bmac\\.New", +] + +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bsignature\\.RSA_PSS_3072_SHA256_F4_KeyTemplate", + "\\bsignature\\.NewSigner", ] # ========================= @@ -205,6 +2672,84 @@ apis = [ "\\bring::[A-Za-z0-9_:]+\\b", ] +# Algorithm definitions for ring +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bring::signature::RSA_", + "\\bRsaKeyPair", +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bring::signature::ECDSA_", + "\\bEcdsaKeyPair", +] +[[library.algorithms.parameter_patterns]] +name = "curve" +pattern = "\\bp(256|384|521)" +default_value = "P-256" + +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bring::signature::Ed25519KeyPair", + "\\bEd25519KeyPair", +] + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bring::aead::AES_", + "\\bUnboundKey", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bring::digest::SHA256", + "\\bdigest::digest", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bhmac::HMAC_SHA256", + "\\bhmac::sign", + "\\bhmac::Key::new", +] + +[[library.algorithms]] +name = "ChaCha20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bring::aead::CHACHA20_POLY1305", + "\\bCHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bring::digest::SHA256", + "\\bdigest::digest.*SHA256", +] + [[library]] name = "openssl (Rust)" languages = ["Rust"] @@ -218,21 +2763,167 @@ apis = [ "\\bopenssl::[A-Za-z0-9_:]+\\b", ] +# Algorithm definitions for openssl (Rust) +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bopenssl::rsa::", + "\\bRsa::", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bopenssl::symm::Cipher", + "\\bCipher::aes_", +] + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bopenssl::ec::", + "\\bEcKey::", +] + [[library]] name = "RustCrypto (common crates)" languages = ["Rust"] [library.patterns] include = [ - "\\buse\\s+(?:aes|aes_gcm|chacha20|chacha20poly1305|poly1305|sha1|sha2|sha3|blake2|blake3|ed25519_dalek|curve25519_dalek|argon2|scrypt)[A-Za-z0-9_:]*", + "\\buse\\s+(?:aes|aes_gcm|chacha20|chacha20poly1305|poly1305|sha1|sha2|sha3|blake2|blake3|ed25519_dalek|curve25519_dalek|argon2|scrypt|rsa|p256|p384|k256)[A-Za-z0-9_:]*", ] apis = [ - "\\b(?:aes_gcm|chacha20poly1305|sha2|sha3|blake3|ed25519_dalek|curve25519_dalek)::[A-Za-z0-9_:]+\\b", + "\\b(?:aes_gcm|chacha20poly1305|sha2|sha3|blake3|ed25519_dalek|curve25519_dalek|rsa|p256|p384|k256)::[A-Za-z0-9_:]+\\b", + "\\b(?:RsaPrivateKey|RsaPublicKey|Pkcs1v15Encrypt)\\b", + "\\b(?:Sha256|Sha512|Digest)\\b", +] + +# Algorithm definitions for RustCrypto +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\b(?:rsa::|RsaPrivateKey|RsaPublicKey)", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "(?:new|generate).*?(\\d{4})|RsaPrivateKey::new.*?(\\d{4})" +default_value = 2048 + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baes_gcm::|Aes\\d+Gcm", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "Aes(\\d+)Gcm" +default_value = 256 + +[[library.algorithms]] +name = "ChaCha20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bchacha20poly1305::|ChaCha20Poly1305", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = ".*" +default_value = 256 + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsha2::|Sha256", +] +[[library.algorithms.parameter_patterns]] +name = "outputSize" +pattern = "Sha(\\d+)" +default_value = 256 + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsha2::|Sha512", +] +[[library.algorithms.parameter_patterns]] +name = "outputSize" +pattern = "Sha(\\d+)" +default_value = 512 + +[[library.algorithms]] +name = "BLAKE3" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bblake3::|Blake3", ] +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bed25519_dalek::|Ed25519", +] +[[library.algorithms.parameter_patterns]] +name = "curve" +pattern = ".*" +default_value = "Curve25519" + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bp256::|p384::|k256::|Ecdsa", +] +[[library.algorithms.parameter_patterns]] +name = "curve" +pattern = "p(\\d+)" +default_value = "P-256" + # ========================= # Swift # ========================= +[[library]] +name = "Security.framework (Swift)" +languages = ["Swift"] +[library.patterns] +include = [ + "^\\s*import\\s+Security\\b", +] +apis = [ + "\\bSec(?:Key|Certificate|Trust|Identity)[A-Za-z0-9_]*\\b", + "\\bkSec[A-Za-z0-9_]+\\b", +] + +# Algorithm definitions for Security.framework (Swift) +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bkSecAttrKeyTypeRSA", + "\\bSecKeyCreateSignature", + "\\brsaSignatureMessagePSSSHA256", +] + [[library]] name = "CryptoKit" languages = ["Swift"] @@ -241,7 +2932,72 @@ include = [ "^\\s*import\\s+CryptoKit\\b", ] apis = [ - "\\b(SHA(?:256|384|512)|HMAC|ChaChaPoly|AES\\.GCM|Curve25519)\\b", + "\\b(SHA(?:256|384|512)|HMAC|ChaChaPoly|AES\\.GCM|Curve25519|P256|P384|P521)\\b", +] + +# Algorithm definitions for CryptoKit +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAES\\.GCM", +] + +[[library.algorithms]] +name = "ChaCha20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bChaChaPoly", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bSHA256", +] + +[[library.algorithms]] +name = "ECDSA-P256" +primitive = "signature" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bP256\\.Signing", +] + +[[library.algorithms]] +name = "ECDSA-P384" +primitive = "signature" +nistQuantumSecurityLevel = 5 +symbol_patterns = [ + "\\bP384\\.Signing", +] + +[[library.algorithms]] +name = "ECDSA-P521" +primitive = "signature" +nistQuantumSecurityLevel = 5 +symbol_patterns = [ + "\\bP521\\.Signing", +] + +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCurve25519\\.Signing", +] + +[[library.algorithms]] +name = "X25519" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCurve25519\\.KeyAgreement", ] [[library]] @@ -252,7 +3008,25 @@ include = [ "^\\s*import\\s+CommonCrypto\\b", ] apis = [ - "\\bCC_(?:Crypt|SHA(?:1|224|256|384|512)|MD5|KeyDerivation|Random)[A-Za-z0-9_]*\\s*\\(", + "\\bCC_(?:Crypt|SHA(?:1|224|256|384|512)|MD5|KeyDerivation|Random|Hmac)[A-Za-z0-9_]*\\s*\\(", + "\\bCCHmac\\s*\\(", +] + +# Algorithm definitions for CommonCrypto (Swift) +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCC_SHA256\\s*\\(", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCCHmac.*kCCHmacAlgSHA256", ] [[library]] @@ -291,12 +3065,69 @@ name = "JCA/JCE (Kotlin)" languages = ["Kotlin"] [library.patterns] include = [ - "^\\s*import\\s+(?:javax\\.crypto\\.|java\\.security\\.)", + "^\\s*import\\s+javax\\.crypto\\.", + "^\\s*import\\s+java\\.security\\.", ] apis = [ - "\\b(?:Cipher|MessageDigest|Signature|KeyPairGenerator)\\.getInstance\\s*\\(", + "\\b(?:Cipher|MessageDigest|Signature|KeyPairGenerator|KeyGenerator|Mac)\\.getInstance\\s*\\(", "\\bKeyFactory\\.getInstance\\s*\\(", "\\bKeyAgreement\\.getInstance\\s*\\(", + "\\bSecretKeySpec\\s*\\(", +] + +# Algorithm definitions for JCA/JCE (Kotlin) - Same as Java +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bKeyPairGenerator\\.getInstance\\s*\\([^)]*RSA", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "RSAKeyGenParameterSpec\\s*\\(\\s*(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCipher\\.getInstance\\s*\\([^)]*AES", + "\\bKeyGenerator\\.getInstance\\s*\\([^)]*AES", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "init\\s*\\(\\s*(\\d+)" +default_value = 256 + +[[library.algorithms]] +name = "ECDSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bKeyPairGenerator\\.getInstance\\s*\\([^)]*EC", + "\\bSignature\\.getInstance\\s*\\([^)]*ECDSA", +] +[[library.algorithms.parameter_patterns]] +name = "curve" +pattern = "initialize\\s*\\(\\s*(256|384|521)" +default_value = "P-256" + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMessageDigest\\.getInstance\\s*\\([^)]*SHA-?256", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bMac\\.getInstance\\s*\\([^)]*HmacSHA256", ] [[library]] @@ -344,6 +3175,60 @@ apis = [ "\\.sign\\(", ] +# Algorithm definitions for PyCA cryptography +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\brsa\\.generate_private_key", + "\\bRSA", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "key_size\\s*=\\s*(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "Fernet" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bFernet\\(", + "\\bfernet", +] +[[library.algorithms.parameter_patterns]] +name = "algorithm" +pattern = ".*" +default_value = "AES-128-CBC + HMAC-SHA256" + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bhashes\\.SHA256\\(", + "\\bSHA256", +] + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bAESGCM\\(", + "\\bAES.*GCM", +] + +[[library.algorithms]] +name = "PBKDF2" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bPBKDF2HMAC\\(", + "\\bpbkdf2", +] + [[library]] name = "PyCryptodome" languages = ["Python"] @@ -361,6 +3246,42 @@ apis = [ "\\b(?:AES|DES|DES3|Blowfish|CAST|ARC2|ARC4|ChaCha20|Salsa20|XOR)\\(", ] +# Algorithm definitions for PyCryptodome +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCrypto\\.PublicKey\\.RSA", + "\\bRSA\\.generate", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "generate\\s*\\(\\s*(\\d+)" +default_value = 2048 + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCrypto\\.Cipher\\.AES", + "\\bAES\\.new", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "AES\\.new\\s*\\(\\s*['\"][A-Za-z0-9_-]*aes-(\\d+)[A-Za-z0-9_-]*['\"]" +default_value = 256 + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCrypto\\.Hash\\.SHA256", + "\\bSHA256\\.new", +] + [[library]] name = "PyNaCl" languages = ["Python"] @@ -392,6 +3313,51 @@ apis = [ "\\bBase64Encoder", ] +# Algorithm definitions for PyNaCl +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bnacl\\.signing\\.SigningKey", + "\\bSigningKey", +] + +[[library.algorithms]] +name = "X25519" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bnacl\\.public\\.PrivateKey", + "\\bnacl\\.public\\.Box", +] + +[[library.algorithms]] +name = "XSalsa20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bnacl\\.secret\\.SecretBox", + "\\bSecretBox", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bnacl\\.hash\\.blake2b", + "\\bblake2b", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bnacl\\.hash\\.sha256", +] + # ========================= # PHP # ========================= @@ -405,6 +3371,49 @@ apis = [ "\\bopenssl_[a-z0-9_]+\\s*\\(", ] +# Algorithm definitions for OpenSSL (PHP) +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bopenssl_pkey_new.*rsa", + "\\bopenssl_sign", +] + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bopenssl_encrypt.*aes", + "\\bopenssl_decrypt.*aes", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "openssl_(?:encrypt|decrypt)\\s*\\(\\s*['\"][^'\"]*aes-(\\d+)" +default_value = 256 +[[library.algorithms.parameter_patterns]] +name = "mode" +pattern = "openssl_(?:encrypt|decrypt)\\s*\\(\\s*['\"][^'\"]*aes-\\d+-(gcm|cbc|ctr|cfb|ofb)" +default_value = "cbc" + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bopenssl_digest.*sha256", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bhash_hmac.*sha256", +] + [[library]] name = "Sodium (PHP)" languages = ["PHP"] @@ -414,6 +3423,41 @@ apis = [ "\\bsodium_[a-z0-9_]+\\s*\\(", ] +# Algorithm definitions for Sodium (PHP) +[[library.algorithms]] +name = "ChaCha20Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsodium_crypto_aead_chacha20poly1305", + "\\bsodium_crypto_secretbox", +] + +[[library.algorithms]] +name = "Ed25519" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bsodium_crypto_sign", + "\\bsodium_crypto_sign_keypair", +] + +[[library.algorithms]] +name = "BLAKE2b" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsodium_crypto_generichash", +] + +[[library.algorithms]] +name = "HMAC-SHA512-256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bsodium_crypto_auth", +] + [[library]] name = "phpseclib" languages = ["PHP"] @@ -441,9 +3485,32 @@ apis = [ # Objective-C: Apple/Common # ========================= +[[library]] +name = "Security.framework (Objective-C)" +languages = ["ObjC"] +[library.patterns] +include = [ + "^\\s*#\\s*import\\s*", +] +apis = [ + "\\bSec(?:Key|Certificate|Trust|Identity)[A-Za-z0-9_]*\\b", + "\\bkSec[A-Za-z0-9_]+\\b", +] + +# Algorithm definitions for Security.framework +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bkSecAttrKeyTypeRSA", + "\\bkSecKeyAlgorithmRSA", + "\\bSecKeyCreateSignature", +] + [[library]] name = "CommonCrypto (Objective-C)" -languages = ["Objective-C"] +languages = ["ObjC"] [library.patterns] include = [ "^\\s*#\\s*(?:import|include)\\s*", @@ -459,21 +3526,50 @@ apis = [ "\\bCCRandomGenerateBytes\\s*\\(", ] -[[library]] -name = "Security.framework (Objective-C)" -languages = ["Objective-C"] -[library.patterns] -include = [ - "^\\s*#\\s*(?:import|include)\\s*", - "^\\s*@import\\s+Security\\b", +# Algorithm definitions for CommonCrypto (Objective-C) +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCCCrypt.*kCCAlgorithmAES", + "\\bkCCAlgorithmAES", +] +[[library.algorithms.parameter_patterns]] +name = "mode" +pattern = "kCCOption[A-Za-z0-9_]*" +default_value = "CBC" + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCC_SHA256", ] -apis = [ - "\\bSecKeyCreateRandomKey\\s*\\(", - "\\bSecKeyCreateEncryptedData\\s*\\(", - "\\bSecKeyCreateDecryptedData\\s*\\(", - "\\bSecKeyCreateSignature\\s*\\(", - "\\bSecKeyVerifySignature\\s*\\(", - "\\bSecRandomCopyBytes\\s*\\(", + +[[library.algorithms]] +name = "SHA-512" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCC_SHA512", +] + +[[library.algorithms]] +name = "MD5" +primitive = "hash" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bCC_MD5", +] + +[[library.algorithms]] +name = "PBKDF2" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bCCKeyDerivationPBKDF", ] # ========================= @@ -482,7 +3578,7 @@ apis = [ [[library]] name = "OpenSSL (Objective-C)" -languages = ["Objective-C"] +languages = ["ObjC"] [library.patterns] include = [ "^\\s*#\\s*(?:import|include)\\s*", @@ -496,9 +3592,63 @@ apis = [ "\\bPKCS\\d_[A-Za-z0-9_]+\\s*\\(", ] +# Algorithm definitions for OpenSSL (Objective-C) +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_sha256\\s*\\(", + "\\bEVP_Digest(?:Init|Update|Final)_ex\\s*\\(", +] + +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_aes_\\d+_gcm\\s*\\(", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "EVP_aes_(\\d+)_gcm" +default_value = 256 + +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bEVP_aes_\\d+_(?:cbc|ctr|ofb|cfb)", + "\\bEVP_CIPHER_CTX_", +] +[[library.algorithms.parameter_patterns]] +name = "keySize" +pattern = "EVP_aes_(\\d+)" +default_value = 256 + +[[library.algorithms]] +name = "RSA" +primitive = "signature" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\bRSA_sign", + "\\bRSA_verify", + "\\bRSA_generate_key_ex", + "\\bRSA_new", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bHMAC\\s*\\(", +] + [[library]] name = "libsodium (Objective-C)" -languages = ["Objective-C"] +languages = ["ObjC"] [library.patterns] include = [ "^\\s*#\\s*(?:import|include)\\s*]+)?>", @@ -517,7 +3667,7 @@ apis = [ [[library]] name = "Google Tink (Objective-C)" -languages = ["Objective-C"] +languages = ["ObjC"] [library.patterns] include = [ "^\\s*@import\\s+Tink\\b", @@ -543,6 +3693,67 @@ apis = [ "\\b(?:JsonKeysetReader|JsonKeysetWriter|cleartext_keyset_handle|KeysetHandle)\\b", "\\b(?:Aead|Mac|HybridEncrypt|HybridDecrypt|PublicKeySign|PublicKeyVerify)\\b", "\\btink\\.core\\.PrimitiveSet\\b", + "\\bmac_key_templates\\.HMAC_SHA256", + "\\btink\\.new_keyset_handle\\b", +] + +# Algorithm definitions for Google Tink (Python) +[[library.algorithms]] +name = "AES-GCM" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.aead_key_templates\\.AES\\d+_GCM", + "\\baead\\.Aead", +] + +[[library.algorithms]] +name = "AES-CTR-HMAC" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.aead_key_templates\\.AES\\d+_CTR_HMAC_SHA256", +] + +[[library.algorithms]] +name = "AES-EAX" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.aead_key_templates\\.AES\\d+_EAX", +] + +[[library.algorithms]] +name = "AES-GCM-SIV" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.aead_key_templates\\.AES\\d+_GCM_SIV", +] + +[[library.algorithms]] +name = "ChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.aead_key_templates\\.CHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "XChaCha20-Poly1305" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\baead\\.aead_key_templates\\.XCHACHA20_POLY1305", +] + +[[library.algorithms]] +name = "HMAC-SHA256" +primitive = "mac" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bmac_key_templates\\.HMAC_SHA256", + "\\bmac\\.Mac", ] # ========================= @@ -553,10 +3764,8 @@ apis = [ name = "Erlang/OTP crypto" languages = ["Erlang"] [library.patterns] -# Detect explicit imports of the module (rare but possible) -include = [ - "^\\s*-import\\s*\\(\\s*crypto\\s*,\\s*\\[", -] +# Detect explicit imports of the module (rare but possible) or empty to allow API detection +include = [] # Detect canonical crypto primitives with module-qualified calls apis = [ "\\bcrypto:(?:hash|hash_init|hash_update|hash_final)\\s*\\(", @@ -566,6 +3775,40 @@ apis = [ "\\bcrypto:pbkdf2_hmac\\s*\\(", "\\bcrypto:rand_seed(?:_alg)?\\s*\\(", "\\bcrypto:hash_xof\\s*\\(", + "\\bcrypto:block_encrypt\\s*\\(", + "\\bcrypto:block_decrypt\\s*\\(", + "\\bcrypto:stream_encrypt\\s*\\(", + "\\bcrypto:stream_decrypt\\s*\\(", +] + +# Algorithm definitions for Erlang/OTP crypto +[[library.algorithms]] +name = "AES" +primitive = "aead" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto:crypto_.*aes", + "\\baes_gcm", + "\\baes_256_cbc", + "\\bcrypto:block_encrypt.*aes", +] + +[[library.algorithms]] +name = "SHA-256" +primitive = "hash" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto:hash.*sha256", + "\\bsha256", + "\\bcrypto:hash\\s*\\(\\s*sha256", +] + +[[library.algorithms]] +name = "PBKDF2" +primitive = "kdf" +nistQuantumSecurityLevel = 3 +symbol_patterns = [ + "\\bcrypto:pbkdf2_hmac", ] [[library]] @@ -575,7 +3818,6 @@ languages = ["Erlang"] # Record/include line commonly present when using PKI/ASN.1 records include = [ "^\\s*-include_lib\\s*\\(\\s*\"public_key/include/public_key\\.hrl\"\\s*\\)", - "^\\s*-import\\s*\\(\\s*public_key\\s*,\\s*\\[", ] apis = [ "\\bpublic_key:(?:sign|verify)\\s*\\(", @@ -592,9 +3834,7 @@ apis = [ name = "enacl (libsodium/NaCl)" languages = ["Erlang"] [library.patterns] -include = [ - "^\\s*-import\\s*\\(\\s*enacl\\s*,\\s*\\[", -] +include = [] apis = [ "\\benacl:(?:secretbox|box(?:_open)?|box_(?:beforenm|afternm|keypair)|box_seal(?:_open)?)\\s*\\(", "\\benacl:aead_(?:x?chacha20poly1305_ietf)_(?:encrypt|decrypt)\\s*\\(", @@ -605,13 +3845,21 @@ apis = [ "\\benacl:randombytes(?:_uniform|_uint32)?\\s*\\(", ] +# Algorithm definitions for enacl +[[library.algorithms]] +name = "X25519" +primitive = "kem" +nistQuantumSecurityLevel = 0 +symbol_patterns = [ + "\\benacl:box_keypair", + "\\benacl:box\\s*\\(", +] + [[library]] name = "bcrypt (Erlang)" languages = ["Erlang"] [library.patterns] -include = [ - "^\\s*-import\\s*\\(\\s*bcrypt\\s*,\\s*\\[", -] +include = [] apis = [ "\\bbcrypt:(?:gen_salt|hashpw|checkpw)\\s*\\(", ]