RSA attack tool (mainly for ctf) - retrieve private key from weak public key and/or uncipher data
This report presents the forensic synthetic code analysis of RsaCtfTool/RsaCtfTool, a Python project with 7,062 GitHub stars. SynthScan v2.0 examined 12,263 lines of code across 116 source files, recording 175 pattern matches distributed across 11 syntactic categories. The overall adjusted score of 19.2 places this repository in the Moderate AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
Longitudinal tracking requires multiple scan runs. Once this repository is re-scanned after new commits land, this chart will visualise how the synthetic code signal evolves over time — enabling you to detect whether AI authorship is growing, stabilising, or being actively corrected by human engineers.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 175 distinct pattern matches across 11 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_number_theory.py | 81 | def test_isqrt_perfect_squares(self): | CODE |
| LOW | tests/test_number_theory.py | 149 | def test_next_prime_consecutive(self): | CODE |
| LOW | tests/test_number_theory.py | 164 | def test_powmod_large_exponent(self): | CODE |
| LOW | tests/test_number_theory.py | 256 | def test_chinese_remainder_basic(self): | CODE |
| LOW | tests/test_number_theory.py | 260 | def test_chinese_remainder_same_modulus(self): | CODE |
| LOW | tests/test_number_theory.py | 278 | def test_contfrac_to_rational_basic(self): | CODE |
| LOW | tests/test_number_theory.py | 282 | def test_contfrac_to_rational_empty(self): | CODE |
| LOW | tests/test_number_theory.py | 306 | def test_legendre_quadratic_residue(self): | CODE |
| LOW | tests/test_number_theory.py | 311 | def test_legendre_quadratic_non_residue(self): | CODE |
| LOW | tests/test_number_theory.py | 447 | def test_common_modulus_attack(self): | CODE |
| LOW | tests/test_number_theory.py | 528 | def test_isqrt_rem_perfect_square(self): | CODE |
| LOW | tests/test_number_theory.py | 533 | def test_isqrt_rem_non_perfect(self): | CODE |
| LOW | tests/test_number_theory.py | 561 | def test_miller_rabin_composite(self): | CODE |
| LOW⚡ | tests/test_exceptions.py | 9 | def test_factorization_error_can_be_raised(self): | CODE |
| LOW⚡ | tests/test_exceptions.py | 13 | def test_factorization_error_message(self): | CODE |
| LOW⚡ | tests/test_exceptions.py | 20 | def test_factorization_error_inheritance(self): | CODE |
| LOW | tests/test_pubkey_decode.py | 7 | def test_weak_public_key_decodes_correctly(self, weak_public_key_path): | CODE |
| LOW | tests/test_pubkey_decode.py | 16 | def test_pubkey_n_is_product_of_primes(self, weak_public_key_path): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 23 | def test_public_key_attributes(self, weak_public_key_path): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 32 | def test_public_key_invalid_format(self): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 36 | def test_public_key_str_representation(self, weak_public_key_path): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 46 | def test_private_key_from_p_q_e(self): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 58 | def test_private_key_str_returns_str(self): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 67 | def test_private_key_str_nonempty_for_valid_key(self): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 76 | def test_private_key_n_eq_p_squared(self): | CODE |
| LOW⚡ | tests/test_keys_wrapper.py | 86 | def test_private_key_from_n_e_d(self): | CODE |
| LOW | tests/test_keys_wrapper.py | 98 | def test_private_key_d_computed_from_p_q_e(self): | CODE |
| LOW | tests/test_keys_wrapper.py | 109 | def test_generate_pq_from_n_and_q(self): | CODE |
| LOW | tests/test_keys_wrapper.py | 117 | def test_generate_pq_from_n_and_p(self): | CODE |
| LOW | tests/test_keys_wrapper.py | 137 | def test_generate_keys_pem_format(self): | CODE |
| LOW | tests/test_keys_wrapper.py | 161 | def test_decrypt_non_list_input(self): | CODE |
| LOW⚡ | tests/test_algos.py | 138 | def test_lehman_invalid_congruence(self): | CODE |
| LOW⚡ | tests/test_algos.py | 147 | def test_strong_pseudoprime_basic(self): | CODE |
| LOW⚡ | tests/test_algos.py | 155 | def test_strong_pseudoprime_returns_empty(self): | CODE |
| LOW⚡ | tests/test_algos.py | 159 | def test_strong_pseudoprime_carmichael_example(self): | CODE |
| LOW⚡ | tests/test_algos.py | 505 | def test_collect_relations_early_split(self): | CODE |
| LOW⚡ | tests/test_algos.py | 512 | def test_gaussian_elim_underdetermined(self): | CODE |
| LOW⚡ | tests/test_algos.py | 518 | def test_gaussian_elim_zero_column(self): | CODE |
| LOW⚡ | tests/test_algos.py | 527 | def test_prime_base_collision_large(self): | CODE |
| LOW | tests/test_algos.py | 60 | def test_fermat_invalid_congruence(self): | CODE |
| LOW | tests/test_algos.py | 69 | def test_brent_small_composite(self): | CODE |
| LOW | tests/test_algos.py | 180 | def test_squfof_invalid_congruence(self): | CODE |
| LOW | tests/test_algos.py | 201 | def test_lehmer_machine_invalid_congruence(self): | CODE |
| LOW | tests/test_algos.py | 249 | def test_pollard_strassen_basic(self): | CODE |
| LOW | tests/test_algos.py | 295 | def test_factor_high_low_bits_equal_invalid_n(self): | CODE |
| LOW | tests/test_algos.py | 304 | def test_fib_get_period_bigint(self): | CODE |
| LOW | tests/test_algos.py | 321 | def test_full_rank_elimination(self): | CODE |
| LOW | tests/test_algos.py | 354 | def test_dixon_small_semiprime(self): | CODE |
| LOW | tests/test_algos.py | 362 | def test_dixon_medium_semiprime(self): | CODE |
| LOW | tests/test_algos.py | 390 | def test_prime_base_collision_small(self): | CODE |
| LOW | tests/test_algos.py | 397 | def test_prime_base_collision_larger(self): | CODE |
| LOW | tests/test_algos.py | 415 | def test_factor_base_includes_divisor_primes(self): | CODE |
| LOW | tests/test_algos.py | 425 | def test_sieve_returns_relations(self): | CODE |
| LOW | tests/test_algos.py | 469 | def test_qs_larger_prime_fails(self): | CODE |
| LOW | tests/test_algos.py | 482 | def test_qs_factor_base_divisor_primes(self): | CODE |
| LOW | tests/test_algos.py | 486 | def test_qs_tiny_params_returns_none(self): | CODE |
| LOW | tests/test_attacks.py | 22 | def test_factordb_attack_succeeds(self): | CODE |
| LOW | tests/test_attacks.py | 51 | def test_noveltyprimes_attack(self): | CODE |
| LOW | tests/test_attacks.py | 63 | def test_smallq_attack_with_decrypt(self): | CODE |
| LOW | tests/test_attacks.py | 105 | def test_commonfactors_attack(self): | CODE |
| 25 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | …/RsaCtfTool/attacks/single_key/prime_base_collision.py | 0 | -----begin public key----- mcawdqyjkozihvcnaqebbqaddwawdaifaqawajccaweaaq== -----end public key----- | STRING |
| HIGH | src/RsaCtfTool/attacks/single_key/quadratic_sieve.py | 0 | -----begin public key----- mcawdqyjkozihvcnaqebbqaddwawdaifaqawajccaweaaq== -----end public key----- | STRING |
| HIGH | src/RsaCtfTool/attacks/single_key/dixon.py | 0 | -----begin public key----- mcawdqyjkozihvcnaqebbqaddwawdaifaqawajccaweaaq== -----end public key----- | STRING |
| HIGH | …Tool/attacks/single_key/multiple_base_inversion_gcd.py | 0 | -----begin public key----- migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqcg6zybpnfefpkadglb1idarrl3 gk+vs1csgk1cy3kspypfydlvv7ak | STRING |
| HIGH | src/RsaCtfTool/attacks/single_key/fermat.py | 0 | -----begin public key----- migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqcg6zybpnfefpkadglb1idarrl3 gk+vs1csgk1cy3kspypfydlvv7ak | STRING |
| HIGH | src/RsaCtfTool/attacks/single_key/kraitchik.py | 0 | -----begin public key----- migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqcg6zybpnfefpkadglb1idarrl3 gk+vs1csgk1cy3kspypfydlvv7ak | STRING |
| HIGH | src/RsaCtfTool/attacks/single_key/lehmer.py | 0 | -----begin public key----- migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqcg6zybpnfefpkadglb1idarrl3 gk+vs1csgk1cy3kspypfydlvv7ak | STRING |
| HIGH | src/RsaCtfTool/attacks/single_key/lehman.py | 0 | -----begin public key----- migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqcg6zybpnfefpkadglb1idarrl3 gk+vs1csgk1cy3kspypfydlvv7ak | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | docs/failure_modes.md | 69 | except Exception: | CODE |
| LOW | src/RsaCtfTool/main.py | 304 | except Exception: | STRING |
| LOW | src/RsaCtfTool/main.py | 409 | except Exception: | STRING |
| LOW | src/RsaCtfTool/main.py | 489 | except Exception: | STRING |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 205 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 267 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 285 | except Exception as e: | CODE |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 355 | except Exception as e: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 72 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 142 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 217 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 224 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 256 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 275 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 277 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/utils.py | 35 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/utils.py | 65 | except Exception: | CODE |
| LOW | src/RsaCtfTool/lib/utils.py | 129 | except Exception: | CODE |
| LOW | src/RsaCtfTool/sage/roca_attack.py | 97 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/wolframalpha.py | 23 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/wolframalpha.py | 56 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/wolframalpha.py | 90 | except Exception as e: | CODE |
| MEDIUM | src/RsaCtfTool/attacks/single_key/wolframalpha.py | 18 | def can_run(self): | CODE |
| LOW | …Tool/attacks/single_key/multiple_base_inversion_gcd.py | 61 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/factordb.py | 50 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/partial_d.py | 47 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/factor_2PN.py | 23 | except Exception: | CODE |
| LOW | …c/RsaCtfTool/attacks/single_key/highandlowbitsequal.py | 19 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/SQUFOF.py | 19 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/z3_solver.py | 57 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/z3_solver.py | 69 | except Exception: | CODE |
| LOW | src/RsaCtfTool/attacks/single_key/euler.py | 33 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/RsaCtfTool/main.py | 270 | CODE | |
| LOW | src/RsaCtfTool/main.py | 286 | CODE | |
| LOW | src/RsaCtfTool/main.py | 403 | CODE | |
| LOW | src/RsaCtfTool/main.py | 529 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 43 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 79 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 141 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 161 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 226 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 317 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 523 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 654 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 821 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 925 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 961 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 577 | CODE | |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 58 | CODE | |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 141 | CODE | |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 183 | CODE | |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 192 | CODE | |
| LOW | src/RsaCtfTool/lib/rsa_attack.py | 248 | CODE | |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 19 | CODE | |
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 199 | CODE | |
| LOW | src/RsaCtfTool/lib/utils.py | 56 | CODE | |
| LOW | src/RsaCtfTool/lib/utils.py | 112 | CODE | |
| LOW | src/RsaCtfTool/sage/roca_attack.py | 24 | CODE | |
| LOW | src/RsaCtfTool/attacks/single_key/wolframalpha.py | 26 | CODE | |
| LOW | …Tool/attacks/single_key/multiple_base_inversion_gcd.py | 47 | CODE | |
| LOW | src/RsaCtfTool/attacks/single_key/factordb.py | 21 | CODE | |
| LOW | src/RsaCtfTool/attacks/single_key/ecm2.py | 17 | CODE | |
| LOW | src/RsaCtfTool/attacks/single_key/qs.py | 16 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | tests/test_regression.py | 18 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_regression.py | 21 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_regression.py | 68 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM | tests/test_regression.py | 70 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_regression.py | 128 | # --------------------------------------------------------------------------- | COMMENT |
| MEDIUM⚡ | tests/test_regression.py | 130 | # --------------------------------------------------------------------------- | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | src/RsaCtfTool/lib/algos.py | 116 | # Create a look-up table | COMMENT |
| MEDIUM | src/RsaCtfTool/sage/roca_attack.py | 59 | # Create the polynom f(x) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | docs/failure_modes.md | 161 | ### 20. Recursion depth in continued fraction computation | COMMENT |
| LOW | docs/failure_modes.md | 181 | ### 30. `PrivateKey._init_fields` truncates arbitrary `d` to `int` via `self.d = d` with no type check | COMMENT |
| LOW | src/RsaCtfTool/attacks/single_key/siqs.py | 1 | #!/usr/bin/env python3 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | src/RsaCtfTool/main.py | 374 | # Check if a private key is provided and there's something to decrypt | STRING |
| LOW⚡ | src/RsaCtfTool/main.py | 381 | # Check if a public key is provided | STRING |
| LOW⚡ | src/RsaCtfTool/main.py | 385 | # Check if n and e are provided | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/RsaCtfTool/lib/algos.py | 11 | CODE | |
| LOW | src/RsaCtfTool/lib/algos.py | 11 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/RsaCtfTool/lib/number_theory.py | 674 | __all__ = [ | CODE |
| LOW | src/RsaCtfTool/lib/crypto_wrapper.py | 23 | __all__ = [RSA, PKCS1_OAEP, number, long_to_bytes, bytes_to_long] | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/RsaCtfTool/lib/keys_wrapper.py | 167 | CODE |