示例#1
0
    def analyze_n(self, n):
        judgements = SecurityJudgements()

        if n < 0:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_RSA_Modulus_Negative,
                "Modulus uses incorrect encoding, representation is a negative integer.",
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION)

            # Fix up n so it's a positive integer for the rest of the tests
            bitlen = (n.bit_length() + 7) // 8 * 8
            mask = (1 << bitlen) - 1
            n = n & mask
        elif n == 0:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_RSA_Modulus_Zero,
                "Modulus is zero, this is definitely a broken RSA public key.",
                bits=0,
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION)
        elif n == 1:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_RSA_Modulus_One,
                "Modulus is one, this is definitely a broken RSA public key.",
                bits=0,
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION)

        if self._test_probable_prime:
            if NumberTheory.is_probable_prime(n):
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_PublicKey_RSA_Modulus_Prime,
                    "Modulus is prime, not a compound integer as we would expect for RSA.",
                    bits=0)

        if self._pollards_rho_iterations > 0:
            small_factor = NumberTheory.pollard_rho(
                n, max_iterations=self._pollards_rho_iterations)
            if small_factor is not None:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_PublicKey_RSA_Modulus_Factorable,
                    "Modulus has small factor (%d) and is therefore trivially factorable."
                    % (small_factor),
                    bits=0)

        match = ModulusDB().find(n)
        if match is not None:
            judgements += SecurityJudgement(
                JudgementCode.
                X509Cert_PublicKey_RSA_Modulus_FactorizationKnown,
                "Modulus is known to be compromised: %s" % (match.text),
                bits=0)

        hweight_analysis = NumberTheory.hamming_weight_analysis(n)
        if (hweight_analysis
                is not None) and (not hweight_analysis.plausibly_random):
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_RSA_Modulus_BitBiasPresent,
                "Modulus does not appear to be random. Expected a Hamming weight between %d and %d for a %d bit modulus, but found Hamming weight %d."
                % (hweight_analysis.rnd_min_hweight,
                   hweight_analysis.rnd_max_hweight, hweight_analysis.bitlen,
                   hweight_analysis.hweight),
                commonness=Commonness.HIGHLY_UNUSUAL)

        # We estimate the complexity of factoring the modulus by the asymptotic
        # complexity of the GNFS.
        bits_security = NumberTheory.asymtotic_complexity_gnfs_bits(n)
        judgements += self.algorithm("bits").analyze(
            JudgementCode.X509Cert_PublicKey_RSA_Modulus_LengthInBits,
            bits_security)

        return judgements
示例#2
0
    def analyze(self, pubkey):
        judgements = SecurityJudgements()

        L = pubkey.p.bit_length()
        N = pubkey.q.bit_length()

        if not NumberTheory.is_probable_prime(pubkey.p):
            standard = LiteratureReference(
                quote="p: a prime modulus",
                sect="4.1",
                author="National Institute of Standards and Technology",
                title="FIPS PUB 186-4: Digital Signature Standard (DSS)",
                year=2013,
                month=7,
                doi="10.6028/NIST.FIPS.186-4")
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_DSA_Parameters_P_NotPrime,
                "DSA parameter p is not prime.",
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION,
                bits=0,
                standard=standard)

        if not NumberTheory.is_probable_prime(pubkey.q):
            standard = LiteratureReference(
                quote="q: a prime divisor of (p - 1)",
                sect="4.1",
                author="National Institute of Standards and Technology",
                title="FIPS PUB 186-4: Digital Signature Standard (DSS)",
                year=2013,
                month=7,
                doi="10.6028/NIST.FIPS.186-4")
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_DSA_Parameters_Q_NotPrime,
                "DSA parameter q is not prime.",
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION,
                bits=0,
                standard=standard)

        if ((pubkey.p - 1) % pubkey.q) != 0:
            standard = LiteratureReference(
                quote="q: a prime divisor of (p - 1)",
                sect="4.1",
                author="National Institute of Standards and Technology",
                title="FIPS PUB 186-4: Digital Signature Standard (DSS)",
                year=2013,
                month=7,
                doi="10.6028/NIST.FIPS.186-4")
            judgements += SecurityJudgement(
                JudgementCode.
                X509Cert_PublicKey_DSA_Parameters_Q_NoDivisorOfP1,
                "DSA parameter q is not a divisor of (p - 1).",
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION,
                bits=0,
                standard=standard)

        if pow(pubkey.g, pubkey.q, pubkey.p) != 1:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_DSA_Parameters_G_Invalid,
                "DSA parameter g is not valid. In particular, g^q mod p != 1.",
                commonness=Commonness.HIGHLY_UNUSUAL,
                bits=0)

        if (pubkey.g <= 1) or (pubkey.g >= pubkey.p):
            standard = LiteratureReference(
                quote=
                "g: a generator of a subgroup of order q in the multiplicative group of GF(p), such that 1 < g < p",
                sect="4.1",
                author="National Institute of Standards and Technology",
                title="FIPS PUB 186-4: Digital Signature Standard (DSS)",
                year=2013,
                month=7,
                doi="10.6028/NIST.FIPS.186-4")
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_DSA_Parameters_G_InvalidRange,
                "DSA parameter g is not inside the valid range (1 < g < p).",
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.STANDARDS_DEVIATION,
                bits=0,
                standard=standard)

        hweight_analysis = NumberTheory.hamming_weight_analysis(pubkey.p)
        if not hweight_analysis.plausibly_random:
            judgements += SecurityJudgement(
                JudgementCode.
                X509Cert_PublicKey_DSA_Parameters_P_BitBiasPresent,
                "Hamming weight of DSA prime p is %d at bitlength %d, but expected a weight between %d and %d when randomly chosen; this is likely not coincidential."
                % (hweight_analysis.hweight, hweight_analysis.bitlen,
                   hweight_analysis.rnd_min_hweight,
                   hweight_analysis.rnd_max_hweight),
                commonness=Commonness.HIGHLY_UNUSUAL)

        hweight_analysis = NumberTheory.hamming_weight_analysis(pubkey.q)
        if not hweight_analysis.plausibly_random:
            judgements += SecurityJudgement(
                JudgementCode.
                X509Cert_PublicKey_DSA_Parameters_Q_BitBiasPresent,
                "Hamming weight of DSA prime q is %d at bitlength %d, but expected a weight between %d and %d when randomly chosen; this is likely not coincidential."
                % (hweight_analysis.hweight, hweight_analysis.bitlen,
                   hweight_analysis.rnd_min_hweight,
                   hweight_analysis.rnd_max_hweight),
                commonness=Commonness.HIGHLY_UNUSUAL)

        if (L in self._TYPICAL_L_N_VALUES) and (
                N in self._TYPICAL_L_N_VALUES[L]):
            # Typical
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_DSA_L_N_Common,
                "DSA parameter values L/N (%d/%d) are common." % (L, N),
                commonness=Commonness.COMMON)
        else:
            # Non-typical
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_PublicKey_DSA_L_N_Uncommon,
                "DSA parameter values L/N (%d/%d) are uncommon." % (L, N),
                commonness=Commonness.UNUSUAL)

        L_strength_bits = NumberTheory.asymtotic_complexity_gnfs_bits(pubkey.p)
        N_strength_bits = math.floor(N / 2)
        bits_security = min(L_strength_bits, N_strength_bits)
        judgements += self.algorithm("bits").analyze(
            JudgementCode.X509Cert_PublicKey_DSA_L_N, bits_security)

        result = {
            "cryptosystem": "dsa",
            "specific": {
                "L": L,
                "N": N,
            },
            "security": judgements,
        }

        if self._analysis_options.include_raw_data:
            result["specific"]["p"] = {
                "value": pubkey.p,
            }
            result["specific"]["q"] = {
                "value": pubkey.q,
            }
            result["specific"]["g"] = {
                "value": pubkey.g,
            }
            result["specific"]["pubkey"] = {
                "value": pubkey.pubkey,
            }
        return result