def test_normal(self):
        checker = KwargsChecker(required_arguments=set(["foo", "bar"]))
        checker.check({"foo": 2, "bar": 9})

        checker = KwargsChecker(required_arguments=set(["foo", "bar"]),
                                optional_arguments=set(["moo"]))
        checker.check({"foo": 2, "bar": 9})
        checker.check({"foo": 2, "bar": 9, "moo": 12})

        checker = KwargsChecker(optional_arguments=set(["moo"]))
        checker.check({})
        checker.check({"moo": 9})
    def test_missing_required(self):
        checker = KwargsChecker(required_arguments=set(["foo", "bar"]))
        with self.assertRaises(InvalidInputException):
            checker.check({"foo": 2})
        with self.assertRaises(InvalidInputException):
            checker.check({"foo": 2, "BAR": 9})
        with self.assertRaises(InvalidInputException):
            checker.check({"foo": 2, "BAR": 9, "MOO": 12})
        with self.assertRaises(InvalidInputException):
            checker.check({"foo": 2, "BAR": 9, "MOO": 12}, hint="foobar")

        checker = KwargsChecker(required_arguments=set(["foo", "bar"]),
                                optional_arguments=set(["muh"]))
        with self.assertRaises(InvalidInputException):
            checker.check({"foo": 2, "BAR": 9, "MOO": 12}, hint="foobar")
Beispiel #3
0
class PrimeFieldEllipticCurve(EllipticCurve):
    """y^2 = x^3 + ax + b (mod p)"""
    _DomainArgs = KwargsChecker(required_arguments=set(["p", "a", "b", "n"]),
                                optional_arguments=set(["h", "Gx", "Gy"]))
    _CURVE_TYPE = "prime"

    @property
    def neutral_point(self):
        return None

    def point_addition(self, P, Q):
        if P is None:
            # O + Q = Q
            return Q
        elif Q is None:
            # P + O = P
            return P
        elif ((P.x == Q.x) and (((P.y + Q.y) % self.p) == 0)):
            # P + (-P) = O
            return None
        elif P == Q:
            # Point doubling
            s = ((3 * P.x**2) + self.a) * NumberTheory.modinv(2 * P.y, self.p)
            x = (s * s - (2 * P.x)) % self.p
            y = (s * (P.x - x) - P.y) % self.p
            return EllipticCurvePoint(self, x, y)
        else:
            # Point addition
            s = (P.y - Q.y) * NumberTheory.modinv(P.x - Q.x, self.p)
            x = ((s**2) - P.x - Q.x) % self.p
            y = (s * (P.x - x) - P.y) % self.p
            return EllipticCurvePoint(self, x, y)

    @property
    def is_koblitz(self):
        """Test if a = 0 and b is sufficiently small."""
        return (self.a == 0) and (self.b < 1000)

    @property
    def order_bits(self):
        return math.log(self.n, 2)

    @property
    def field_bits(self):
        return self.p.bit_length()

    @property
    def characteristic_cmpkey(self):
        return (self.curvetype, self.a, self.b, self.n, self.h,
                self._domain_parameters.get("Gx"),
                self._domain_parameters.get("Gy"), self.p)

    def on_curve(self, point):
        lhs = (point.y * point.y) % self.p
        rhs = ((point.x**3) + (self.a * point.x) + self.b) % self.p
        return lhs == rhs
 def test_single(self):
     checker = KwargsChecker(required_arguments=set(["foo", "bar"]),
                             optional_arguments=set(["moo"]))
     checker.check_single("foo")
     checker.check_single("bar")
     checker.check_single("moo")
     with self.assertRaises(InvalidInputException):
         checker.check_single("f*x")
     with self.assertRaises(InvalidInputException):
         checker.check_single("f*x", hint="foobarhint")
Beispiel #5
0
    def __init__(self, cryptosystem, parameters=None):
        assert (isinstance(cryptosystem, Cryptosystems))
        if parameters is None:
            parameters = {}
        self._cryptosystem = cryptosystem
        self._parameters = dict(parameters)

        constraints = KwargsChecker(required_arguments=set(
            param[0] for param in self._cryptosystem.value.spec_parameters))
        constraints.check(parameters,
                          hint="keyspec for cryptosystem %s" %
                          (self._cryptosystem.name))
Beispiel #6
0
class BinaryFieldEllipticCurve(EllipticCurve):
    """y^2 + xy = x^3 + ax^2 + b (in F_{2^m}, reduced by irreducible poly)"""
    _DomainArgs = KwargsChecker(
        required_arguments=set(["m", "poly", "a", "b", "n"]),
        optional_arguments=set(["h", "Gx", "Gy", "basis"]))
    _CURVE_TYPE = "binary"

    def __init__(self, **domain_parameters):
        super().__init__(**domain_parameters)
        self._domain_parameters["intpoly"] = sum(1 << bit
                                                 for bit in set(self.poly))

    @property
    def is_koblitz(self):
        """Test if a, b in [ 0, 1 ]."""
        return (self.a in [0, 1]) and (self.b in [0, 1])

    @property
    def order_bits(self):
        return math.log(self.n, 2)

    @property
    def field_bits(self):
        return self.m

    @property
    def int_poly(self):
        return sum(1 << exponent for exponent in self.poly)

    @property
    def characteristic_cmpkey(self):
        return (self.curvetype, self.a, self.b, self.n, self.h,
                self._domain_parameters.get("Gx"),
                self._domain_parameters.get("Gy"), self.m,
                tuple(sorted(set(self.poly))))

    def on_curve(self, point):
        lhs = NumberTheory.binpoly_reduce(
            NumberTheory.cl_mul(point.y, point.y)
            ^ NumberTheory.cl_mul(point.x, point.y), self.intpoly)
        rhs = NumberTheory.binpoly_reduce(
            NumberTheory.cl_mul(NumberTheory.cl_mul(point.x, point.x), point.x)
            ^ NumberTheory.cl_mul(NumberTheory.cl_mul(self.a, point.x),
                                  point.x) ^ self.b, self.intpoly)
        return lhs == rhs
Beispiel #7
0
	def __init__(self, cmdname, args):
		BaseAction.__init__(self, cmdname, args)

		# Plausibilize input parameters
		kwargs_checker = KwargsChecker(optional_arguments = set(self._DER_CLASSES.keys()))
		kwargs_checker.check(self._args.include_dertype, hint = "DER classes to be included")
		kwargs_checker.check(self._args.exclude_dertype, hint = "DER classes to be excluded")

		# Plausibilize output directory
		if os.path.exists(self._args.outdir) and (not self._args.force):
			raise Exception("Directory %s already exists. Remove it first or use --force." % (self._args.outdir))
		try:
			os.makedirs(self._args.outdir)
		except FileExistsError:
			pass

		# Determine active DERHandler classes
		if len(self._args.include_dertype) == 0:
			active_der_types = set(self._DER_CLASSES.keys())
		else:
			active_der_types = set(self._args.include_dertype)
		active_der_types -= set(self._args.exclude_dertype)
		self._active_der_types = [ self._DER_CLASSES[class_name] for class_name in active_der_types ]
		self._active_der_types.sort(key = lambda handler: (handler.precedence, handler.data_type))

		self._stats = ActionScrapeStats(self._args)
		self._stats.set_active_der_types([ handler_class.data_type for handler_class in self._active_der_types ])

		self._matches = Intervals()
		self._hashes = set()
		engine = ScrapeEngine(self._args.filename)
		if not self._args.no_pem:
			engine.search(self._find_pem, b"-----BEGIN ", min_length = 52, max_length = 32 * 1024)
		if (not self._args.no_der) and (len(self._active_der_types) > 0):
			self._log.debug("Looking for %d DER type(s): %s", len(self._active_der_types), ", ".join(handler.data_type for handler in self._active_der_types))
			engine.search(self._find_der, bytes.fromhex("30"), min_length = 2, max_length = 32 * 1024)
		end_offset = engine.commence(start_offset = self._args.seek_offset, length = self._args.analysis_length, progress_callback = self._progress_callback)
		self._stats.finish(end_offset)
		self._stats.dump()
		if self._args.write_json is not None:
			JSONTools.write_to_file(self._stats.as_dict(), self._args.write_json)
Beispiel #8
0
class LiteratureReference(StandardReference):
    _STD_TYPE = "literature"
    _Arguments = KwargsChecker(required_arguments=set(["author", "title"]),
                               optional_arguments=set([
                                   "type", "year", "month", "source", "quote",
                                   "doi", "sect", "deviation_type"
                               ]),
                               check_functions={
                                   "year":
                                   lambda x: isinstance(x, int),
                                   "month":
                                   lambda x: isinstance(x, int) and
                                   (1 <= x <= 12),
                               })
    _MONTHNAMES = {
        1: "Jan",
        2: "Feb",
        3: "Mar",
        4: "Apr",
        5: "May",
        6: "Jun",
        7: "Jul",
        8: "Aug",
        9: "Sep",
        10: "Oct",
        11: "Nov",
        12: "Dec",
    }

    def __init__(self, **kwargs):
        StandardReference.__init__(self)
        self._Arguments.check(kwargs, "LiteratureReference")
        self._fields = kwargs
        if isinstance(self._fields["author"], str):
            self._fields["author"] = [self._fields["author"]]
        self._fields["type"] = self._STD_TYPE

    @property
    def deviation_type(self):
        if "deviation_type" not in self._fields:
            return None
        else:
            return {
                "SHOULD": StandardDeviationType.RECOMMENDATION,
                "MUST": StandardDeviationType.VIOLATION,
            }[self._fields["deviation_type"]]

    @classmethod
    def from_dict(cls, data):
        return cls(**data)

    def to_dict(self):
        return dict(self._fields)

    def __str__(self):
        text = " and ".join(self._fields["author"])
        if "year" in self._fields is not None:
            if "month" in self._fields is not None:
                text += " (%s %d)" % (self._MONTHNAMES[self._fields["month"]],
                                      self._fields["year"])
            else:
                text += " (%d)" % (self._fields["year"])
        text += ". \"%s\"" % (self._fields["title"])
        if "sect" in self._fields:
            text += " Sect. %s" % (self._fields["sect"])
        return text
Beispiel #9
0
class PrivateKeyStorage():
    _PRIVATE_KEY_CLASSES = [RSAPrivateKey, ECPrivateKey, EDPrivateKey]

    _PARAMETER_CONSTRAINTS = {
        PrivateKeyStorageForm.PEM_FILE:
        KwargsChecker(required_arguments=set(["filename"]),
                      optional_arguments=set(["search_path"])),
        PrivateKeyStorageForm.DER_FILE:
        KwargsChecker(required_arguments=set(["filename"]),
                      optional_arguments=set(["search_path"])),
        PrivateKeyStorageForm.HARDWARE_TOKEN:
        KwargsChecker(required_arguments=set(["pkcs11uri", "so_search_path"]),
                      optional_arguments=set(["dynamic_so", "module_so"])),
    }

    def __init__(self, storage_form, **kwargs):
        assert (isinstance(storage_form, PrivateKeyStorageForm))
        self._storage_form = storage_form
        self._PARAMETER_CONSTRAINTS[storage_form].check(
            kwargs, hint="PrivateKeyStorage using %s" % (storage_form.name))
        self._parameters = kwargs
        if "search_path" not in self._parameters:
            self._parameters["search_path"] = ""
        if self._storage_form == PrivateKeyStorageForm.HARDWARE_TOKEN:
            self._verify_pkcs11_uri()

    def _verify_pkcs11_uri(self):
        uri = self._parameters["pkcs11uri"]
        if uri.startswith("pkcs11:"):
            # Literal PKCS#11 URI, leave as-is.
            pass
        elif uri.startswith("label="):
            # Replace with encoded version
            label = uri[6:]
            self._parameters["pkcs11uri"] = "pkcs11:object=%s;type=private" % (
                urllib.parse.quote(label))
        elif uri.startswith("id="):
            # Replace with encoded version
            key_id_str = uri[3:]
            try:
                key_id = baseint(key_id_str)
                key_bytes = key_id.to_bytes(length=16,
                                            byteorder="big").lstrip(bytes(1))
            except (ValueError, OverflowError) as e:
                raise InvalidInputException(
                    "Key ID '%s' is not a valid hex value or is too large: %s"
                    % (key_id_str, e.__class__.__name__))
            key_id_quoted = "".join("%%%02x" % (c) for c in key_bytes)
            self._parameters["pkcs11uri"] = "pkcs11:id=%s;type=private" % (
                key_id_quoted)
        else:
            raise InvalidInputException(
                "For hardware keys, you need to either give a RFC7512-compliant pkcs11-scheme URI (starts with 'pkcs11:'), a key label in the form 'label=foobar' or a key id in the hex form like 'id=0xabc123' or in decimal form like 'id=11256099'. The supplied value '%s' is neither."
                % (uri))

    def update(self, key, value):
        self._PARAMETER_CONSTRAINTS[self._storage_form].check_single(key)
        self._parameters[key] = value

    @property
    def storage_form(self):
        return self._storage_form

    @property
    def is_file_based(self):
        return self.storage_form in [
            PrivateKeyStorageForm.PEM_FILE, PrivateKeyStorageForm.DER_FILE
        ]

    @property
    def filename(self):
        assert (self.storage_form in [
            PrivateKeyStorageForm.PEM_FILE, PrivateKeyStorageForm.DER_FILE
        ])
        return self._parameters["filename"]

    @property
    def full_filename(self):
        assert (self.storage_form in [
            PrivateKeyStorageForm.PEM_FILE, PrivateKeyStorageForm.DER_FILE
        ])
        return self._parameters["search_path"] + self._parameters["filename"]

    @property
    def pkcs11uri(self):
        assert (self.storage_form == PrivateKeyStorageForm.HARDWARE_TOKEN)
        return self._parameters["pkcs11uri"]

    @property
    def so_search_path(self):
        assert (self.storage_form == PrivateKeyStorageForm.HARDWARE_TOKEN)
        return self._parameters["so_search_path"]

    @property
    def dynamic_so(self):
        assert (self.storage_form == PrivateKeyStorageForm.HARDWARE_TOKEN)
        return self._parameters.get("dynamic_so", "libpkcs11.so")

    @property
    def module_so(self):
        assert (self.storage_form == PrivateKeyStorageForm.HARDWARE_TOKEN)
        return self._parameters.get("module_so", "opensc-pkcs11.so")

    def to_dict(self):
        return {
            "storage_form": self.storage_form.name,
            "parameters": {
                key: value
                for (key, value) in self._parameters.items()
                if key not in ["search_path"]
            },
        }

    @classmethod
    def from_dict(cls, serialized_dict, **kwargs):
        storage_form = getattr(PrivateKeyStorageForm,
                               serialized_dict["storage_form"])
        parameters = serialized_dict["parameters"]
        parameters.update(kwargs)
        return cls(storage_form=storage_form, **parameters)

    @classmethod
    def from_str(cls, key_type, key_value):
        if key_type == "pem":
            return cls(PrivateKeyStorageForm.PEM_FILE, filename=key_value)
        elif key_type == "der":
            return cls(PrivateKeyStorageForm.DER_FILE, filename=key_value)
        elif key_type == "hw":
            return cls(PrivateKeyStorageForm.HARDWARE_TOKEN,
                       pkcs11uri=key_value)
        else:
            raise LazyDeveloperException(NotImplemented, key_type)

    def load_private_key(self):
        assert (self.is_file_based)
        for handler_class in self._PRIVATE_KEY_CLASSES:
            try:
                if self.storage_form == PrivateKeyStorageForm.PEM_FILE:
                    privkey = handler_class.read_pemfile(self.full_filename)[0]
                elif self.storage_form == PrivateKeyStorageForm.DER_FILE:
                    privkey = handler_class.read_derfile(self.full_filename)
                else:
                    raise LazyDeveloperException(NotImplemented,
                                                 self.storage_form)
            except UnexpectedFileContentException:
                continue
            return privkey
        raise UnexpectedFileContentException(
            "Could not load key material from %s." % (self.full_filename))

    def __str__(self):
        if self.storage_form in [
                PrivateKeyStorageForm.PEM_FILE, PrivateKeyStorageForm.DER_FILE
        ]:
            return "PrivateKeyStorage<%s: %s>" % (self.storage_form.name,
                                                  self.filename)
        elif self.storage_form == PrivateKeyStorageForm.HARDWARE_TOKEN:
            return "PrivateKeyStorage<%s %s>" % (self.storage_form.name,
                                                 self.pkcs11uri)
        else:
            return "PrivateKeyStorage<%s: %s>" % (self.storage_form.name,
                                                  str(self._parameters))
Beispiel #10
0
class TwistedEdwardsEllipticCurve(EllipticCurve):
    """ax^2 + y^2 = 1 + dx^2 y^2 (mod p)"""
    _DomainArgs = KwargsChecker(required_arguments=set([
        "p", "a", "d", "element_octet_cnt", "expand_bitwise_and",
        "expand_bitwise_or", "expand_hashfnc"
    ]),
                                optional_arguments=set(
                                    ["Gx", "Gy", "expand_hashlen"]))
    _CURVE_TYPE = "twisted_edwards"

    def __init__(self, **domain_parameters):
        super().__init__(**domain_parameters)
        self._sqrt_neg1_modp = pow(2, (self.p - 1) // 4, self.p)

    @property
    def element_octet_cnt(self):
        return self._domain_parameters["element_octet_cnt"]

    @property
    def order_bits(self):
        return NumberTheory.hamming_weight(self.expand_bitwise_and
                                           & ~self.expand_bitwise_or)

    @property
    def field_bits(self):
        return self.p.bit_length()

    @property
    def neutral_point(self):
        return self.point(0, 1)

    def on_curve(self, point):
        lhs = ((self.a * point.x * point.x) + (point.y * point.y)) % self.p
        rhs = 1 + (self.d * point.x * point.x * point.y * point.y) % self.p
        return lhs == rhs

    def point_addition(self, P, Q):
        x = (P.x * Q.y + Q.x * P.y) % self.p
        x = (x * NumberTheory.modinv(1 + self.d * P.x * Q.x * P.y * Q.y,
                                     self.p)) % self.p
        y = (P.y * Q.y - self.a * P.x * Q.x) % self.p
        y = (y * NumberTheory.modinv(1 - self.d * P.x * Q.x * P.y * Q.y,
                                     self.p)) % self.p
        return self.point(x, y)

    def encode_point(self, point):
        encoded_point = bytearray(
            point.y.to_bytes(length=self.element_octet_cnt,
                             byteorder="little"))
        encoded_point[-1] |= (point.x & 1) << 7
        return bytes(encoded_point)

    def decode_point(self, serialized_point):
        assert (isinstance(serialized_point, bytes))
        if len(serialized_point) != self.element_octet_cnt:
            raise InvalidInputException(
                "Do not know how to decode %s point. Expected %d octets, but got %d."
                % (str(self), self.element_octet_cnt, len(serialized_point)))

        serialized_point = bytearray(serialized_point)
        x_lsb = (serialized_point[-1] >> 7) & 1
        serialized_point[-1] &= 0x7f
        y = int.from_bytes(serialized_point, byteorder="little")

        if y >= self.p:
            raise InvalidInputException(
                "y coordinate of point must be smaller than p.")

        # x^2 = (1 - y^2) / (a - dy^2)
        x2 = (1 - y * y) % self.p
        x2 *= NumberTheory.modinv(self.a - self.d * y * y, self.p)
        (x_pos, x_neg) = NumberTheory.sqrt_mod_p(x2, self.p)

        if x_lsb == 0:
            x = x_pos
        else:
            x = x_neg

        point = self.point(x, y)
        return point

    def expand_secret(self, serialized_unhashed_secret):
        assert (isinstance(serialized_unhashed_secret, bytes))
        if len(serialized_unhashed_secret) != self.element_octet_cnt:
            raise InvalidInputException(
                "Do not know how to decode %s secret. Expected %d octets, but got %d."
                % (str(self), self.element_octet_cnt,
                   len(serialized_unhashed_secret)))
        hashfnc = hashlib.new(self.expand_hashfnc)
        hashfnc.update(serialized_unhashed_secret)
        if ("expand_hashlen"
                in self._domain_parameters) and (hashfnc.digest_size == 0):
            hashed_secret = hashfnc.digest(self.expand_hashlen)
        else:
            hashed_secret = hashfnc.digest()

        if ("expand_hashlen" in self._domain_parameters) and (
                len(hashed_secret) !=
                self._domain_parameters["expand_hashlen"]):
            raise InvalidInputException(
                "Expansion of secret requires %d byte hash function output, but %s provided %d bytes."
                % (self._domain_parameters["expand_hashlen"], str(hashfnc),
                   len(hashed_secret)))

        scalar = int.from_bytes(hashed_secret[:self.element_octet_cnt],
                                byteorder="little")
        scalar &= self.expand_bitwise_and
        scalar |= self.expand_bitwise_or
        return (scalar, self.G.scalar_mul(scalar))

    @property
    def characteristic_cmpkey(self):
        return (self.curvetype, self.a, self.d, self.p,
                self._domain_parameters.get("Gx"),
                self._domain_parameters.get("Gy"), self.element_octet_cnt,
                self.expand_bitwise_and, self.expand_bitwise_or,
                self.expand_hashfnc, self._domain_params.get("expand_hashlen"))