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")
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))
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 __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)
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
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")
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})
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
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))
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"))