def compute_sha512(*args): hasher = hashes.Hash(hashes.SHA512(), CRYPTO_BACKEND) compute_digest(hasher, *args) return hasher.finalize()
class Conf: def __init__(self, confFile: str): self.general = self._load(confFile) self.fileExtenstions = self._getFileExt() # run checks self._checkCertName() self._checkEncoding() self._checkExtendedKeyUsage() self._checkKeyUsage() self._checkNotValidDate() self._checkPubKeyEncodingPresent() self._checkRedundantNames() self._checkSerialization() def getCert(self, certName: str) -> Union[Dict[Any, Any], None]: certs = self.general["certs"] conf = {} for cert in certs: if cert["name"] == certName: conf = cert break if not (len(conf) > 0): return None return conf.get("conf") def get(self, certName: str, field: str, isExt: bool = True) -> dict: certConf = self.getCert(certName) if isExt is True: return certConf.get("extensions").get(field) # type: ignore elif certConf.get(field): return certConf.get(field) else: logging.error(f"{field} not found in conf") raise ValueError() def getCertPath(self, certName: str, ext: str) -> Union[str, None]: certConf = self.getCert(certName) if certConf is not None: path = certConf.get("storage").get("path") # type: ignore fileName = certConf.get("storage").get("fileName") # type: ignore ext = self.fileExtenstions.get(ext) # type: ignore certpath = f"{path}/{fileName}.{ext}" return certpath else: print("cant fint cert path") return None def getPassphrase(self, certName: str) -> Union[bytes, None]: # get passphrase certConf = self.getCert(certName) if certConf.get("private_key") and certConf.get("private_key").get( "passphrase"): p = certConf.get("private_key").get("passphrase").get( "path") # type: ignore n = certConf.get("private_key").get("passphrase").get( "fileName") # type: ignore passFile = f"{p}/{n}" passphrase = loadFile(passFile) if not type(passphrase) == bytes: logging.error("passphrase should be of bytes type") raise ValueError() sys.exit() return passphrase else: passphrase = None return passphrase def _load(self, fileName: str) -> dict: generalConf = {} try: with open(fileName, mode="r", encoding="utf-8") as file: try: generalConf = loads(file.read()) except JSONEncodeError as e: sys.exit(f"enable to load string from {fileName}: {e}") except OSError as e: logging.error(f"failed to open {fileName}: {e}") return generalConf def _getFileExt(self) -> dict: return self.general.get("defaults").get("file_extentions") def _checkPubKeyEncodingPresent(self) -> None: # check if the public key encoding is persent certs = self.general["certs"] for cert in certs: try: cert.get("conf").get("public_key").get("encoding") except KeyError as e: certName = cert.get("name") logging.error( f"Configuration file error: can't find public key encoding for {certName}, {e}" ) raise ValueError() def _checkRedundantNames(self) -> None: # check if no redundant certs names certs = self.general.get("certs") names: dict = {} for cert in certs: if cert["name"] in names.keys(): names[cert["name"]] += 1 else: names[cert["name"]] = 1 for k, v in names.items(): if v > 1: logging.error( f"Configuration file error: {k} appears {v} times") raise ValueError() def _checkNotValidDate(self) -> None: # check not_valid_before not_valid_after certs = self.general.get("certs") for certConf in certs: certConf = certConf.get("conf") if certConf.get("not_valid_before") == "now": nvb = datetime.datetime.utcnow() elif isinstance(int(), certConf.get("not_valid_before")) or isinstance( int, certConf.get("not_valid_after")): nvb = datetime.datetime.utcnow() + datetime.timedelta( days=certConf.get("not_valid_before")) else: logging.error( f'invalid value from {nvb}, should be of int or "now"') raise ValueError() def _checkCertName(self) -> None: certs = self.general.get("certs") for cert in certs: subjectName = cert.get("conf").get("subject_name") certName = cert.get("name") if certName != subjectName: logging.error( f"certname {certName} has to be the same than the subject name, found {subjectName}" ) raise ValueError() def _checkKeyUsage(self) -> None: certs = self.general.get("certs") for cert in certs: certName = cert.get("name") for ku in cert.get("conf").get("extensions").get("KeyUsage").get( "items"): if ku.lower() not in self.keyUsage: logging.error( f"{ku} not found in allowed keyUsage for {certName}") raise ValueError() def _checkExtendedKeyUsage(self) -> None: certs = self.general.get("certs") for cert in certs: if cert.get("conf").get("extensions").get("ExtendedKeyUsage"): for ku in (cert.get("conf").get("extensions").get( "ExtendedKeyUsage").get("items")): if ku.upper() not in self.extendedKeyUsageMapping.keys(): logging.error( f"{ku} not found in allowed ExtendedKeyUsage") raise ValueError() def _checkEncoding(self) -> None: certs = self.general.get("certs") for cert in certs: certName = cert.get("name") enc_priv = cert.get("conf").get("private_key").get("encoding") enc_pub = cert.get("conf").get("public_key").get("encoding") if (enc_priv not in self.encodingMapping.keys()) or ( enc_pub not in self.encodingMapping.keys()): logging.error( f"encoding not found for {certName} in allowed encoding formats" ) raise ValueError() def _checkSerialization(self) -> None: certs = self.general.get("certs") for cert in certs: certName = cert.get("name") serialization = cert.get("conf").get("private_key").get( "serialization") if serialization not in self.privateSerializationMapping.keys(): logging.error( f"serialization not found for private key of {certName} in allowed serialization formats" ) raise ValueError() nameAttributesMapping = { "COUNTRY_NAME": NameOID.COUNTRY_NAME, "STATE_OR_PROVINCE_NAME": NameOID.STATE_OR_PROVINCE_NAME, "LOCALITY_NAME": NameOID.LOCALITY_NAME, "ORGANIZATION_NAME": NameOID.ORGANIZATION_NAME, "COMMON_NAME": NameOID.COMMON_NAME, } extensionMapping = { "SubjectAlternativeName": x509.SubjectAlternativeName, "KeyUsage": x509.KeyUsage, "BasicConstraints": x509.BasicConstraints, "NameConstraints": x509.NameConstraints, "NameAttribute": x509.NameAttribute, "AuthorityKeyIdentifier": x509.AuthorityKeyIdentifier, "DNSName": x509.DNSName, "IPAddress": x509.IPAddress, } curveMapping = { "SECP256R1": ec.SECP256R1(), "SECP384R1": ec.SECP384R1(), "SECP521R1": ec.SECP521R1(), } encodingMapping = { "PEM": serialization.Encoding.PEM, "DER": serialization.Encoding.DER, "Raw": serialization.Encoding.Raw, "OpenSSH": serialization.Encoding.OpenSSH, } privateSerializationMapping = { "PKCS8": serialization.PrivateFormat.PKCS8, "TraditionalOpenSSL": serialization.PrivateFormat.TraditionalOpenSSL, "Raw": serialization.PrivateFormat.Raw, "OpenSSH": serialization.PrivateFormat.OpenSSH, } publicSerializationMapping = { "SubjectPublicKeyInfo": serialization.PublicFormat.SubjectPublicKeyInfo, "PKCS1": serialization.PublicFormat.PKCS1, "Raw": serialization.PublicFormat.Raw, "OpenSSH": serialization.PublicFormat.OpenSSH, } RSApaddingMapping = { "PSS": padding.PSS, "OAEP": padding.OAEP, "PKCS1v15": padding.PKCS1v15, } hashMapping = { "sha256": hashes.SHA256(), "sha384": hashes.SHA384(), "sha512": hashes.SHA512(), } keyUsage = [ "digital_signature", "content_commitment", "key_encipherment", "data_encipherment", "key_agreement", "key_cert_sign", "crl_sign", "encipher_only", "decipher_only", ] extendedKeyUsageMapping = { "SERVER_AUTH": x509.oid.ExtendedKeyUsageOID.SERVER_AUTH, "CLIENT_AUTH": x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH, "CODE_SIGNING": x509.oid.ExtendedKeyUsageOID.CODE_SIGNING, "EMAIL_PROTECTION": x509.oid.ExtendedKeyUsageOID.EMAIL_PROTECTION, "TIME_STAMPING": x509.oid.ExtendedKeyUsageOID.TIME_STAMPING, "OCSP_SIGNING": x509.oid.ExtendedKeyUsageOID.OCSP_SIGNING, "ANY_EXTENDED_KEY_USAGE": x509.oid.ExtendedKeyUsageOID.ANY_EXTENDED_KEY_USAGE, }
class Crypto: curvemap={ "secp192r1": ec.SECP192R1(), "secp224r1": ec.SECP224R1(), "secp256r1": ec.SECP256R1(), "secp384r1": ec.SECP384R1(), "secp521r1": ec.SECP521R1(), "secp256k1": ec.SECP256K1(), "sect163k1": ec.SECT163K1(), "sect233k1": ec.SECT233K1(), "sect283k1": ec.SECT283K1(), "sect409k1": ec.SECT409K1(), "sect571k1": ec.SECT571K1(), "sect163r2": ec.SECT163R2(), "sect233r1": ec.SECT233R1(), "sect283r1": ec.SECT283R1(), "sect409r1": ec.SECT409R1(), "sect571r1": ec.SECT571R1() } hash_algorithms={"SHA256":hashes.SHA256(),"SHA512":hashes.SHA512()} def __init__(self,crypto_config): try: self.config=crypto_config self.ready=False self.trusted_keys_path=os.path.abspath(crypto_config["trusted_keys_path"]) if not os.path.exists(self.trusted_keys_path): with open(self.trusted_keys_path,"w+") as tf: tf.write("") self.trusted_keys=set() self.backend=default_backend() self.ec_curve=self.curvemap[crypto_config["ECDSA-CURVE"]] self.hash_algorithm=crypto_config["hash"] if not "name" in crypto_config: name="" while True: name=raw_input(color["yellow"]+"Enter a name. This name will be associated with your public key and anyone you share downloads with will try to associate this name with your public key\n:") if len(name.strip())<1: print(color["red"]+"You didn't enter any name. it needs to have at least one character.") else: break self.config["name"]=name if not "url" in crypto_config: url="" while True: url=raw_input(color["yellow"]+"Enter a URL. This URL will be associated with your public key and anyone you share downloads with will attempt to visit this URL to validate whether or not your public key and name have a legitimate association with the site at that URL.\n:") if len(url.strip())<5: print(color["red"]+"You didn't enter any URL. it needs to have at least 5 characters.") else: break self.config["url"]=url if not "description" in crypto_config: description="" while True: print(color["yellow"]+''' Enter a description of you and your public key. This is an informal field. It needs to have at least 5 characters. Feel free to add as little or as much information as you want that will help others validate the association of your public key with your identity. While not required, it certainly does help if you can include signatures (PGP,s/mime signed email,etc...) and other steps users should take to validate your public key and it's association with your identity. When finished enter 'EOF' without quotes on it's own line: ''') lines=[] while True: line=raw_input() if 'eof' in line.strip().lower(): break else: lines.append(line) description='\n'.join(lines) self.config["description"]=description if len(description.strip())<5: print(color["red"]+"You description isn't long enough. it needs to have at least 5 characters.") else: break self.name=self.config["name"] self.url=self.config["url"] self.description=self.config["description"] if not "private-key" in crypto_config: if not self.ecdsa_keygen(): print(color["red"]+"Error,failed to generate ecdsa key.") sys.exit(1) else: passwd=None confirm=None while True: passwd=getpass.getpass("Enter a password that will be used to encrypt your private signing key. You will need this password to sign any downloads.\n:") if len(passwd)>9: confirm=getpass.getpass("Confirm this password by entering it again:\n") if confirm==passwd: break else: print(color["red"]+"Your confirmation password is different than your initial password. Let's try this again.") else: print(color["yellow"]+"Please enter a password longer than 8 characters.") self.config["private-key"]=self.private_ecdsa_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.BestAvailableEncryption(passwd)) passwd=None confirm=None else: while True: try: passwd=getpass.getpass("Enter your private key password:"******"private-key"]),passwd,self.backend) break except (ValueError,TypeError) as e: print(color["red"]+"Unable to decrypt your private key with the supplied password.") continue passwd=None if not None is pkey: self.private_ecdsa_key=pkey self.public_ecdsa_key=pkey.public_key() else: print(color["red"]+"Not good! Unable to load your private key") sys.exit(1) self.load_keys() if not None is self.private_ecdsa_key and not None is self.public_ecdsa_key: self.ready=True except Exception as e: print(color["red"]+"Exception encountered while initializing Crypto") print(traceback.print_exc()) def dump_keys(self): #dispalys trusted public key info print(color["yellow"]+"The following public keys have been trusted by you. Downloads signed by the holders of the corresponding private keys will be accepted and trusted:") for keystring in self.trusted_keys: self.showkey(json.loads(keystring)) ''' new line separated json encoded public key info any key found in the trusted_keys file is valid for signing download catalogs ''' def load_keys(self,showkeys=False): os.chown(self.trusted_keys_path,os.getuid(),os.getgid()) #make sure the current user owns this file. os.chmod(self.trusted_keys_path,0o0600) #owner read/write,nobody else can rwx it. with open(self.trusted_keys_path,"r") as tf: for line in tf.read().splitlines(): if len(line.strip())>0 and line.strip()[0] != "#": try: self.trusted_keys.add(line.strip()) except Exception as e: print(color["red"]+"Error loading:"+line) print(traceback.print_exc()) continue if showkeys==True: self.dump_keys() def showkey(self,keydict,showsig=False): info='' info+='----------------- IDENTITY -----------------\n' if 'name' in keydict: info+=color["yellow"]+"Associated Name: "+keydict['name']+"\n" if 'url' in keydict: info+=color["yellow"]+"Associated URL: "+keydict['url']+"\n\n" if 'description' in keydict: info+=color["blue"]+"Description:\n"+keydict['description']+"\n" if showsig==True and 'signature' in keydict: info+=color["red"]+"Download-specific Signature:\n'"+keydict['signature']+"'\n" if 'public-key' in keydict: info+=color["red"]+"Public key:\n"+keydict['public-key'] info+='----------------- IDENTITY -----------------\n' print(info) ''' istrustedkey: For a key to be trusted a public key and associated information with the follwing properties need to be true: 1) The public key itself 2) The name associated with the public key (case insensitive) 3) The URL associated with the public key (also case insensitve) When the user trusts a public key,they are verifying primarily the association of #1 with #2 and #3. This also prevents trusted key holders from signing as other trusted key holders. If all paramters match True is returned. If the public key is found but corresponding paramters don't match - False is returned If the public key is not found None is returned ''' def istrustedkey(self,key_info): self.load_keys() for keystring in self.trusted_keys: trusted_key_info=json.loads(keystring) if (trusted_key_info["public-key"].strip() == key_info["public-key"].strip() and trusted_key_info["name"].strip().lower() == key_info["name"].strip().lower() and trusted_key_info["url"].strip().lower() == key_info["url"].strip().lower()): return True elif trusted_key_info["public-key"].strip() == key_info["public-key"].strip(): return False return None def confirmandtrust(self,keyinfo): print(color["red"]+''' An unknown and untrusted key was found. The details of the key are below. *CAREFULLY* inspect the name,description and the contents of the associated URL.") When you have verified and trusted this public key, type 'TRUSTED-KEY' as printed without quotes and it will be added to your trusted key list at '''+self.trusted_keys_path+''' Enter blank or any other value if you do not trust this key: ''') self.showkey(keyinfo) choice=raw_input(color["red"]+"Do you trust this public key?\n") if choice.strip() == "TRUSTED-KEY": os.chown(self.trusted_keys_path,os.getuid(),os.getgid()) #make sure the current user owns this file. os.chmod(self.trusted_keys_path,0o0600) #owner read/write,nobody else can rwx it. self.trusted_keys.add(json.dumps(keyinfo)) with open(self.trusted_keys_path,"war+") as tf: tf.write("\n"+json.dumps(keyinfo,sort_keys=True)) print(color["green"]+"Great! It has been added to your list of trusted keys") return True else: print(color["blue"]+"Good job verfying this public key. It will not be trusted or added to your trusted key list") return False def ecdsa_sign(self,hash_algorithm,data): try: if not None is self.private_ecdsa_key and not None is data and len(data)>0: signature=self.private_ecdsa_key.sign(data,ec.ECDSA(hash_algorithm)) if None is signature or len(signature)<1: print(color["red"]+"ecdsa_sign error bad signature value") raise ValueError("ecdsa_sign error bad signature value") return None else: return signature else: print(color["red"]+"ecdsa_sign error private_key or data value error") raise ValueError("ecdsa_sign error private_key or data value error") return None except Exception as e: print(color["red"]+"ecdsa_sign error") print(traceback.print_exc()) return None def ecdsa_verify(self,serialized_public_key,signature,hash_algorithm,data): try: public_ecdsa_key=serialization.load_pem_public_key(str(serialized_public_key),backend=self.backend) v=None if not None is public_ecdsa_key: v=public_ecdsa_key.verifier(signature, ec.ECDSA(hash_algorithm)) if None is v: raise ValueError("ecdsa_verify_error bad verifier") return False v.update(data) v.verify() return True else: print(color["red"]+"ecdsa_verify error - no public key set") raise ValueError("ecdsa_verify error - no public key set") print(traceback.print_exc()) return False return False except InvalidSignature as e: print(color["red"]+"ecdsa_verify error") return False def ecdsa_keygen(self): try: pkey=ec.generate_private_key(self.ec_curve,self.backend) if not None is pkey: self.private_ecdsa_key=pkey self.public_ecdsa_key=pkey.public_key() return True else: print(color["red"]+"ecdsa_keygen error") return False return False except Exception as e: print(color["red"]+"ecdsa_keygen error") print(traceback.print_exc()) return False return False def verify_and_load(self,content): content_d=json.loads(content.strip()) siginfo=content_d["siginfo"] data=content_d["data"] verify=False trusted=self.istrustedkey(siginfo) if trusted==True: verify=True elif trusted==False: print(color["red"]+''' Unable to verify the authenticity of the public key that signed this download The public key used to sign this download was found,however the name or URL associated with this same public key you trusted are not matching up. This might be a malicious party attempting to sign packages by pretending to be someone you trust. Please investigate this (or seek help in doing so). ''') verify=False else: print(color["red"]+"Unable to verify the authenticity of the public key that signed this download") if self.confirmandtrust(siginfo)==True: verify=True else: verify=False if verify==True: if not siginfo["hash-algorithm"] in self.hash_algorithms: print(color["red"]+"Unsupported hash algorithm used in signature.") return None if self.ecdsa_verify(siginfo["public-key"],base64.b64decode(siginfo["signature"]),self.hash_algorithms[siginfo["hash-algorithm"]],str(data))==True: return data,siginfo else: return None,None return None,None def sign_and_export(self,content): if not type(content) is str or len(content.strip())<1: return None hash_algorithm=self.hash_algorithms[self.hash_algorithm] signature=self.ecdsa_sign(hash_algorithm,content) pubkey=self.private_ecdsa_key.public_key().public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo) if None is signature or None is pubkey or len(signature.strip())<32 or len(pubkey)<32: return None export={"data":str(content), "siginfo":{ "public-key":pubkey, "signature":base64.b64encode(signature), "hash-algorithm":self.hash_algorithm, "name":self.name, "url":self.url, "description":self.description } } return export
def test_encrypted_data_keys_hash(encrypted_data_keys, result): hasher = hashes.Hash(hashes.SHA512(), backend=default_backend()) assert _encrypted_data_keys_hash(hasher, encrypted_data_keys) == b''.join( [b64decode(each) for each in result])
from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.base import ( _EARLIEST_UTC_TIME, _PRIVATE_KEY_TYPES, _convert_to_naive_utc_time, _reject_duplicate_extension, ) _OIDS_TO_HASH = { "1.3.14.3.2.26": hashes.SHA1(), "2.16.840.1.101.3.4.2.4": hashes.SHA224(), "2.16.840.1.101.3.4.2.1": hashes.SHA256(), "2.16.840.1.101.3.4.2.2": hashes.SHA384(), "2.16.840.1.101.3.4.2.3": hashes.SHA512(), } class OCSPResponderEncoding(Enum): HASH = "By Hash" NAME = "By Name" class OCSPResponseStatus(Enum): SUCCESSFUL = 0 MALFORMED_REQUEST = 1 INTERNAL_ERROR = 2 TRY_LATER = 3 SIG_REQUIRED = 5 UNAUTHORIZED = 6
class Rs512(RsaSsaPkcs1v15): _name = KeyVaultSignatureAlgorithm.rs512 _default_hash_algorithm = hashes.SHA512()
class TestSMIMEBuilder(object): def test_invalid_data(self): builder = smime.SMIMESignatureBuilder() with pytest.raises(TypeError): builder.set_data(u"not bytes") def test_set_data_twice(self): builder = smime.SMIMESignatureBuilder().set_data(b"test") with pytest.raises(ValueError): builder.set_data(b"test") def test_sign_no_signer(self): builder = smime.SMIMESignatureBuilder().set_data(b"test") with pytest.raises(ValueError): builder.sign(serialization.Encoding.PEM, []) def test_sign_no_data(self): cert, key = _load_cert_key() builder = smime.SMIMESignatureBuilder().add_signer( cert, key, hashes.SHA256()) with pytest.raises(ValueError): builder.sign(serialization.Encoding.PEM, []) def test_unsupported_hash_alg(self): cert, key = _load_cert_key() with pytest.raises(TypeError): smime.SMIMESignatureBuilder().add_signer(cert, key, hashes.SHA512_256()) def test_not_a_cert(self): cert, key = _load_cert_key() with pytest.raises(TypeError): smime.SMIMESignatureBuilder().add_signer(b"notacert", key, hashes.SHA256()) @pytest.mark.supported( only_if=lambda backend: backend.ed25519_supported(), skip_message="Does not support ed25519.", ) def test_unsupported_key_type(self, backend): cert, _ = _load_cert_key() key = ed25519.Ed25519PrivateKey.generate() with pytest.raises(TypeError): smime.SMIMESignatureBuilder().add_signer(cert, key, hashes.SHA256()) def test_sign_invalid_options(self): cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(b"test").add_signer( cert, key, hashes.SHA256())) with pytest.raises(ValueError): builder.sign(serialization.Encoding.PEM, [b"invalid"]) def test_sign_invalid_encoding(self): cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(b"test").add_signer( cert, key, hashes.SHA256())) with pytest.raises(ValueError): builder.sign(serialization.Encoding.Raw, []) def test_sign_invalid_options_text_no_detached(self): cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(b"test").add_signer( cert, key, hashes.SHA256())) options = [smime.SMIMEOptions.Text] with pytest.raises(ValueError): builder.sign(serialization.Encoding.PEM, options) def test_sign_invalid_options_text_der_encoding(self): cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(b"test").add_signer( cert, key, hashes.SHA256())) options = [ smime.SMIMEOptions.Text, smime.SMIMEOptions.DetachedSignature, ] with pytest.raises(ValueError): builder.sign(serialization.Encoding.DER, options) def test_sign_invalid_options_no_attrs_and_no_caps(self): cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(b"test").add_signer( cert, key, hashes.SHA256())) options = [ smime.SMIMEOptions.NoAttributes, smime.SMIMEOptions.NoCapabilities, ] with pytest.raises(ValueError): builder.sign(serialization.Encoding.PEM, options) def test_smime_sign_detached(self, backend): data = b"hello world" cert, key = _load_cert_key() options = [smime.SMIMEOptions.DetachedSignature] builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) sig = builder.sign(serialization.Encoding.PEM, options) sig_binary = builder.sign(serialization.Encoding.DER, options) # We don't have a generic ASN.1 parser available to us so we instead # will assert on specific byte sequences being present based on the # parameters chosen above. assert b"sha-256" in sig # Detached signature means that the signed data is *not* embedded into # the PKCS7 structure itself, but is present in the PEM serialization # as a separate section before the PKCS7 data. So we should expect to # have data in sig but not in sig_binary assert data in sig _smime_verify(serialization.Encoding.PEM, sig, data, [cert], options, backend) assert data not in sig_binary _smime_verify( serialization.Encoding.DER, sig_binary, data, [cert], options, backend, ) def test_sign_byteslike(self): data = bytearray(b"hello world") cert, key = _load_cert_key() options = [smime.SMIMEOptions.DetachedSignature] builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) sig = builder.sign(serialization.Encoding.PEM, options) assert bytes(data) in sig @pytest.mark.parametrize( ("hash_alg", "expected_value"), [ (hashes.SHA1(), b"\x06\x05+\x0e\x03\x02\x1a"), (hashes.SHA256(), b"\x06\t`\x86H\x01e\x03\x04\x02\x01"), (hashes.SHA384(), b"\x06\t`\x86H\x01e\x03\x04\x02\x02"), (hashes.SHA512(), b"\x06\t`\x86H\x01e\x03\x04\x02\x03"), ], ) def test_smime_sign_alternate_digests_der(self, hash_alg, expected_value, backend): data = b"hello world" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hash_alg)) options = [] sig = builder.sign(serialization.Encoding.DER, options) assert expected_value in sig _smime_verify(serialization.Encoding.DER, sig, None, [cert], options, backend) @pytest.mark.parametrize( ("hash_alg", "expected_value"), [ (hashes.SHA1(), b"sha1"), (hashes.SHA256(), b"sha-256"), (hashes.SHA384(), b"sha-384"), (hashes.SHA512(), b"sha-512"), ], ) def test_smime_sign_alternate_digests_detached_pem(self, hash_alg, expected_value): data = b"hello world" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hash_alg)) options = [smime.SMIMEOptions.DetachedSignature] sig = builder.sign(serialization.Encoding.PEM, options) # When in detached signature mode the hash algorithm is stored as a # byte string like "sha-384". assert expected_value in sig def test_smime_sign_attached(self, backend): data = b"hello world" cert, key = _load_cert_key() options = [] builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) sig_binary = builder.sign(serialization.Encoding.DER, options) # When not passing detached signature the signed data is embedded into # the PKCS7 structure itself assert data in sig_binary _smime_verify( serialization.Encoding.DER, sig_binary, None, [cert], options, backend, ) def test_smime_sign_binary(self, backend): data = b"hello\nworld" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) options = [] sig_no_binary = builder.sign(serialization.Encoding.DER, options) sig_binary = builder.sign(serialization.Encoding.DER, [smime.SMIMEOptions.Binary]) # Binary prevents translation of LF to CR+LF (SMIME canonical form) # so data should not be present in sig_no_binary, but should be present # in sig_binary assert data not in sig_no_binary _smime_verify( serialization.Encoding.DER, sig_no_binary, None, [cert], options, backend, ) assert data in sig_binary _smime_verify( serialization.Encoding.DER, sig_binary, None, [cert], options, backend, ) def test_smime_sign_smime_canonicalization(self, backend): data = b"hello\nworld" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) options = [] sig_binary = builder.sign(serialization.Encoding.DER, options) # LF gets converted to CR+LF (SMIME canonical form) # so data should not be present in the sig assert data not in sig_binary assert b"hello\r\nworld" in sig_binary _smime_verify( serialization.Encoding.DER, sig_binary, None, [cert], options, backend, ) def test_smime_sign_text(self, backend): data = b"hello world" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) options = [ smime.SMIMEOptions.Text, smime.SMIMEOptions.DetachedSignature, ] sig_pem = builder.sign(serialization.Encoding.PEM, options) # The text option adds text/plain headers to the S/MIME message # These headers are only relevant in PEM mode, not binary, which is # just the PKCS7 structure itself. assert b"text/plain" in sig_pem # When passing the Text option the header is prepended so the actual # signed data is this. signed_data = b"Content-Type: text/plain\r\n\r\nhello world" _smime_verify( serialization.Encoding.PEM, sig_pem, signed_data, [cert], options, backend, ) def test_smime_sign_no_capabilities(self, backend): data = b"hello world" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) options = [smime.SMIMEOptions.NoCapabilities] sig_binary = builder.sign(serialization.Encoding.DER, options) # NoCapabilities removes the SMIMECapabilities attribute from the # PKCS7 structure. This is an ASN.1 sequence with the # OID 1.2.840.113549.1.9.15. It does NOT remove all authenticated # attributes, so we verify that by looking for the signingTime OID. # 1.2.840.113549.1.9.15 SMIMECapabilities as an ASN.1 DER encoded OID assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x0f" not in sig_binary # 1.2.840.113549.1.9.5 signingTime as an ASN.1 DER encoded OID assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x05" in sig_binary _smime_verify( serialization.Encoding.DER, sig_binary, None, [cert], options, backend, ) def test_smime_sign_no_attributes(self, backend): data = b"hello world" cert, key = _load_cert_key() builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA256())) options = [smime.SMIMEOptions.NoAttributes] sig_binary = builder.sign(serialization.Encoding.DER, options) # NoAttributes removes all authenticated attributes, so we shouldn't # find SMIMECapabilities or signingTime. # 1.2.840.113549.1.9.15 SMIMECapabilities as an ASN.1 DER encoded OID assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x0f" not in sig_binary # 1.2.840.113549.1.9.5 signingTime as an ASN.1 DER encoded OID assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x05" not in sig_binary _smime_verify( serialization.Encoding.DER, sig_binary, None, [cert], options, backend, ) def test_multiple_signers(self, backend): data = b"hello world" cert, key = _load_cert_key() rsa_key = load_vectors_from_file( os.path.join("x509", "custom", "ca", "rsa_key.pem"), lambda pemfile: serialization.load_pem_private_key( pemfile.read(), None), mode="rb", ) rsa_cert = load_vectors_from_file( os.path.join("x509", "custom", "ca", "rsa_ca.pem"), loader=lambda pemfile: x509.load_pem_x509_certificate(pemfile.read( )), mode="rb", ) builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA512()).add_signer(rsa_cert, rsa_key, hashes.SHA512())) options = [] sig = builder.sign(serialization.Encoding.DER, options) # There should be three SHA512 OIDs in this structure assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x03") == 3 _smime_verify( serialization.Encoding.DER, sig, None, [cert, rsa_cert], options, backend, ) def test_multiple_signers_different_hash_algs(self, backend): data = b"hello world" cert, key = _load_cert_key() rsa_key = load_vectors_from_file( os.path.join("x509", "custom", "ca", "rsa_key.pem"), lambda pemfile: serialization.load_pem_private_key( pemfile.read(), None), mode="rb", ) rsa_cert = load_vectors_from_file( os.path.join("x509", "custom", "ca", "rsa_ca.pem"), loader=lambda pemfile: x509.load_pem_x509_certificate(pemfile.read( )), mode="rb", ) builder = (smime.SMIMESignatureBuilder().set_data(data).add_signer( cert, key, hashes.SHA384()).add_signer(rsa_cert, rsa_key, hashes.SHA512())) options = [] sig = builder.sign(serialization.Encoding.DER, options) # There should be two SHA384 and two SHA512 OIDs in this structure assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x02") == 2 assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x03") == 2 _smime_verify( serialization.Encoding.DER, sig, None, [cert, rsa_cert], options, backend, )
class SiriusAPICrypto(): """ SiriusAPICrypto class, implement crypto API of Sirius """ VERBOSE = False # SHA sha_dict = { "SHA1": 0, "SHA224": 1, "SHA256": 2, "SHA384": 3, "SHA512": 4, } sha_functions = { "SHA1": hashes.SHA1(), "SHA224": hashes.SHA224(), "SHA256": hashes.SHA256(), "SHA384": hashes.SHA384(), "SHA512": hashes.SHA512(), } # ECDSA ecdsa_curve = { "secp256k1": 0, "secp256r1": 0, } ecdsa_sha_functions = { "SHA1": 0, "SHA256": 1, } # DSA dsa_sha_functions = { "SHA1": 0, "SHA256": 1, } # AES aes_key_length = [16, 24, 32] aes_mode = { "ECB_ENC": 0, "ECB_DEC": 1, "CBC_ENC": 2, "CBC_DEC": 3, "OFB_ENC": 4, "OFB_DEC": 5, "CFB_ENC": 6, "CFB_DEC": 7, } aes_block_size = 16 # TDES tdes_key_length = [8, 16, 24] tdes_mode = { "ECB_ENC": 0, "ECB_DEC": 1, "CBC_ENC": 2, "CBC_DEC": 3, "OFB_ENC": 4, "OFB_DEC": 5, "CFB_ENC": 6, "CFB_DEC": 7, } tdes_block_size = 8 # CMAC cmac_operation = { "TDES": 0, "AES": 1, } cmac_key_length = {"TDES": tdes_key_length, "AES": aes_key_length} # RSA rsa_operations = { "ENC": 0, "DEC": 1, } def __init__(self, bluefin_serial, verbose=False): """ """ self._datalink = bluefin_serial self.VERBOSE = verbose @staticmethod def getShaMethodList(): ret = [] for key in SiriusAPICrypto.sha_dict: ret.append(key) return ret @staticmethod def getShaMethodStr(): return ', '.join([ '%s' % (key) for (key, value) in SiriusAPICrypto.sha_dict.items() ]) def Trng(self, target, numberOfBytes): """ """ sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target) trng_package = struct.pack('<B', numberOfBytes) cmd = pkt.Packet('\x8b', '\x0e', trng_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Trng serial API fail, code 0x%02x" % ord(rsp[2])) return None return rsp[3:] def Sha(self, target, method, message, selfCheck=False, verbose=False): """ SHA digest API method: <str> method of hashing message: <str> message to be hased isApp: <bool> if true, will send to Application processor """ if method not in SiriusAPICrypto.sha_dict: print_err("Invalid method: %s" % method) return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=verbose) sha_package = struct.pack('<B', SiriusAPICrypto.sha_dict[method]) + message cmd = pkt.Packet('\x8b', '\x4e', sha_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Sha serial API fail, code 0x%02x" % ord(rsp[2])) return None # Check with our result if selfCheck: digest = hashes.Hash(SiriusAPICrypto.sha_functions[method], backend=default_backend()) digest.update(message) ourResult = digest.finalize() theirResult = rsp[3:] if len(theirResult) != len(ourResult): print_err("Wrong length, our: %d, their: %d" % (len(ourResult), len(theirResult))) return None if theirResult != ourResult: print_err("Wrong value") dump_hex(ourResult, "Ours: ") dump_hex(theirResult, "Theirs: ") return None if verbose: dump_hex(rsp[3:], "Sha serial return: ") return rsp[3:] def KeyDownload(self, target, DSS_p=None, DSS_q=None, DSS_g=None, DSS_y=None, DSS_x=None, ECDSA_x=None, ECDSA_y=None, ECDSA_pri=None, RSA_p=None, RSA_q=None, RSA_n=None, RSA_d=None, RSA_e=None, verbose=False): info = MlsKeyTlv(verbose=self.VERBOSE) if DSS_p is not None: info.AddValList('DSS_p', DSS_p) if DSS_q is not None: info.AddValList('DSS_q', DSS_q) if DSS_g is not None: info.AddValList('DSS_g', DSS_g) if DSS_y is not None: info.AddValList('DSS_y', DSS_y) if DSS_x is not None: info.AddValList('DSS_x', DSS_x) if ECDSA_x is not None: info.AddValList('ECDSA_x', ECDSA_x) if ECDSA_y is not None: info.AddValList('ECDSA_y', ECDSA_y) if ECDSA_pri is not None: info.AddValList('ECDSA_pri', ECDSA_pri) if RSA_n is not None: info.AddValList('RSA_n', RSA_n) if RSA_d is not None: info.AddValList('RSA_d', RSA_d) if RSA_p is not None: info.AddValList('RSA_p', RSA_p) if RSA_q is not None: info.AddValList('RSA_q', RSA_q) if RSA_e is not None: # RSA_e should be a number if isinstance(RSA_e, int): RSA_e_str = struct.pack('>I', RSA_e) info.AddValList('RSA_e', RSA_e_str) elif isinstance(RSA_e, str): info.AddValList('RSA_e', RSA_e) else: print_err("Invalid value of RSA_e, abort") return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF for item in info.ValList(): pkt = BluefinserialCommand(sirius_target, verbose=verbose) cmd = pkt.Packet('\x8b', '\x46', item) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Key download fail, code 0x%02x" % ord(rsp[2])) return None return True def EcdsaSign(self, target, curve, hashAlgo, message, verbose=False): """ return: + signature if success + None if fail """ if curve not in SiriusAPICrypto.ecdsa_curve: print_err("Invalid curve: %s" % curve) return None if hashAlgo not in SiriusAPICrypto.ecdsa_sha_functions: print_err("Invalid hash: %s" % hashAlgo) return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=verbose) ecdsa_sign_package = struct.pack( '<BBBHB', 0, # operation: sign SiriusAPICrypto.ecdsa_curve[curve], # curve SiriusAPICrypto.ecdsa_sha_functions[hashAlgo], # sha len(message), # message len 0 # no signature ) + message cmd = pkt.Packet('\x8b', '\x4a', ecdsa_sign_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("ECDSA sign fail, code 0x%02x" % ord(rsp[2])) return None if verbose: dump_hex(rsp[3:], "signature: ") return rsp[3:] def EcdsaVerify(self, target, curve, hashAlgo, message, signature, verbose=False): """ return: + True if verify ok + False if verify fail + None if communication error """ if curve not in SiriusAPICrypto.ecdsa_curve: print_err("Invalid curve: %s" % curve) return None if hashAlgo not in SiriusAPICrypto.ecdsa_sha_functions: print_err("Invalid hash: %s" % hashAlgo) return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=verbose) ecdsa_sign_package = struct.pack( '<BBBHB', 1, # operation: verify SiriusAPICrypto.ecdsa_curve[curve], # curve SiriusAPICrypto.ecdsa_sha_functions[hashAlgo], # sha len(message), # message len len(signature) # no signature ) + message + signature cmd = pkt.Packet('\x8b', '\x4a', ecdsa_sign_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("ECDSA verify fail, code 0x%02x" % ord(rsp[2])) return None if verbose: print("Verify status: %s" % ("ok" if ord(rsp[3]) == 0 else "failed")) return True if ord(rsp[3]) == 0 else False def DsaSign(self, target, hashAlgo, message, verbose=False): """ return: + signature if success + None if fail """ if hashAlgo not in SiriusAPICrypto.dsa_sha_functions: print_err("Invalid hash: %s" % curve) return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=False) dsa_sign_package = struct.pack( '<BBHB', 0, # operation: sign SiriusAPICrypto.dsa_sha_functions[hashAlgo], # sha len(message), # message len 0 # no signature ) + message cmd = pkt.Packet('\x8b', '\x48', dsa_sign_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("DSA sign fail, code 0x%02x" % ord(rsp[2])) return None if verbose: dump_hex(rsp[3:], "signature: ") return rsp[3:] def DsaVerify(self, target, hashAlgo, message, signature, verbose=False): """ return: + True if verify ok + False if verify fail + None if communication error """ if hashAlgo not in SiriusAPICrypto.dsa_sha_functions: print_err("Invalid hash: %s" % hashAlgo) return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=verbose) dsa_verify_package = struct.pack( '<BBHB', 1, # operation: verify SiriusAPICrypto.dsa_sha_functions[hashAlgo], # sha len(message), # message len len(signature) # no signature ) + message + signature cmd = pkt.Packet('\x8b', '\x48', dsa_verify_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Dsa verify fail, code 0x%02x" % ord(rsp[2])) return None if verbose: print("Verify status: %s" % ("ok" if ord(rsp[3]) == 0 else "failed")) return True if ord(rsp[3]) == 0 else False def Cmac(self, target, cipher, key, message): """ return: CMAC, with corresponding cipher, key, message """ if cipher not in SiriusAPICrypto.cmac_operation: print_err("Invalid cipher: %s" % cipher) return None if len(key) not in SiriusAPICrypto.cmac_key_length[cipher]: print_err("Invalid key length: %d" % len(key)) return None msgLen = len(message) sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=False) cmac_package = struct.pack( '<BBB', SiriusAPICrypto.cmac_operation[cipher], # cipher type msgLen, # message len len(key), # key length ) + message + key cmd = pkt.Packet('\x8b', '\x44', cmac_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Cmac fail, code 0x%02x" % ord(rsp[2])) return None return rsp[3:] def Aes(self, target, en_dec, mode, iv, key, data): """ """ en_dec = en_dec.upper() mode = mode.upper() aes_mode = mode + "_" + en_dec if aes_mode not in SiriusAPICrypto.aes_mode: print_err("Invalid mode: %s" % aes_mode) return None if len(key) not in SiriusAPICrypto.aes_key_length: print_err("Invalid key length: %d" % len(key)) return None if len(data) % SiriusAPICrypto.aes_block_size != 0: print_err("Invalid data length: %d" % len(data)) return None if len(iv) != SiriusAPICrypto.aes_block_size: print_err("Invalid IV length: %d" % len(iv)) return None numOfBlock = len(data) / SiriusAPICrypto.aes_block_size sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=False) aes_package = struct.pack( '<BB', numOfBlock, # number of 16-bytes AES or 8-bytess TDES block len(key), # data len ) + data + key + iv + chr(SiriusAPICrypto.aes_mode[aes_mode]) cmd = pkt.Packet('\x8b', '\x0c', aes_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("AES fail, code 0x%02x" % ord(rsp[2])) return None return rsp[3:] def Tdes(self, target, en_dec, mode, iv, key, data): """ """ en_dec = en_dec.upper() mode = mode.upper() tdes_mode = mode + "_" + en_dec if tdes_mode not in SiriusAPICrypto.tdes_mode: print_err("Invalid mode: %s" % tdes_mode) return None if len(key) not in SiriusAPICrypto.tdes_key_length: print_err("Invalid key length: %d" % len(key)) return None if len(data) % SiriusAPICrypto.tdes_block_size != 0: print_err("Invalid data length: %d" % len(data)) return None if len(iv) != SiriusAPICrypto.tdes_block_size: print_err("Invalid IV length: %d" % len(iv)) return None numOfBlock = len(data) / SiriusAPICrypto.tdes_block_size sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=False) tdes_package = struct.pack( '<BB', numOfBlock, # number of 16-bytes tdes or 8-bytess TDES block len(key), # data len ) + data + key + iv + chr(SiriusAPICrypto.tdes_mode[tdes_mode]) cmd = pkt.Packet('\x8b', '\x0a', tdes_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Tdes fail, code 0x%02x" % ord(rsp[2])) return None return rsp[3:] def Rsa(self, target, operation, data, verbose=False): """ """ if operation not in SiriusAPICrypto.rsa_operations: print_err("Invalid operation %s" % (operation)) return None sirius_target = BluefinserialCommand.TARGET_APPLICATION if target == "APP" else BluefinserialCommand.TARGET_RF pkt = BluefinserialCommand(sirius_target, verbose=verbose) rsa_package = struct.pack( '<B', SiriusAPICrypto.rsa_operations[operation], # rsa operation ) + data cmd = pkt.Packet('\x8b', '\x4c', rsa_package) rsp = self._datalink.Exchange(cmd) if (rsp is None): print_err("Send fail") return None if rsp[2] != '\x00': print_err("Rsa %s fail, code 0x%02x" % (operation, ord(rsp[2]))) return None return rsp[3:]
def __init__(self): super(_HS512, self).__init__(hashes.SHA512())
def asymmetric_encrypt_command(client: Client, args: Dict[str, Any]) -> Tuple[str, Any, Any]: """Encrypt plainttext using an asymmetric key. Args: client(Client): User's client. args(dict): Demisto arguments. Returns: The encrypted ciphertext. """ # handle the plaintext - convert to base64 if args.get('simple_plaintext'): plaintext = base64.b64encode( bytes(str(args.get('simple_plaintext')), 'utf-8')) elif args.get('base64_plaintext'): plaintext = base64.b64decode(str(args.get('base64_plaintext'))) elif args.get('entry_id'): file = demisto.getFilePath(args.get('entry_id')) file_path = file['path'] with open(file_path, 'rb') as fp: plaintext = base64.b64encode(fp.read()) else: raise ValueError("No object to encrypt.") project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract( client, args) crypto_key_version = args.get('crypto_key_version') # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version) # get the CryptoKeyVersion info and check it's algorithm. crypto_key_version_info = client.kms_client.get_crypto_key_version( request={'name': crypto_key_version_name}) key_algo = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm( crypto_key_version_info.algorithm).name # Algorithm must be a "DECRYPT" type asymmetric algorithm - if not, raise an error to the user. if 'DECRYPT' not in key_algo: raise ValueError( f"{crypto_key_version_name} is not a valid asymmetric CryptoKeyVersion" ) # get public key of the asymmetric encryption. public_key_response = client.kms_client.get_public_key( request={'name': crypto_key_version_name}) key_txt = public_key_response.pem.encode('ascii') public_key = serialization.load_pem_public_key(key_txt, default_backend()) # using the CryptoKeyVersion algorithm - create the necessary padding for the encryption. if 'SHA256' in key_algo: # create padding with SHA256 pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None) else: # create padding with SHA512 pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA512()), algorithm=hashes.SHA512(), label=None) # encrypt plaintext and return the cipertext without added characters. ciphertext = str(base64.b64encode(public_key.encrypt( plaintext, pad)))[2:-1] # type: ignore[union-attr] asymmetric_encrypt_context = { 'CryptoKey': crypto_key_id, 'IsBase64': args.get('base64_plaintext') is not None, 'Ciphertext': ciphertext } if args.get('entry_id'): file_name = demisto.getFilePath( args.get('entry_id'))['name'] + '_encrypted.txt' demisto.results(fileResult(file_name, ciphertext)) return (f"The text has been encrypted.\nCiphertext: {ciphertext}", { f'{INTEGRATION_CONTEXT_NAME}.AsymmetricEncrypt(val.CryptoKey == obj.CryptoKey ' f'&& val.IsBase64 == obj.IsBase64 && val.Ciphertext == obj.Ciphertext)': asymmetric_encrypt_context, }, asymmetric_encrypt_context)
def test_reg_bug_56(): # some imports only used by this regression test import hashlib from datetime import datetime from pgpy.pgp import PGPSignature from pgpy.constants import HashAlgorithm from pgpy.constants import PubKeyAlgorithm from pgpy.constants import SignatureType from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding # do a regression test on issue #56 # re-create a signature that would have been encoded improperly as with issue #56 # and see if it fails to verify or not # this was the old seckeys/TestRSA-2048.key sec = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "\n" \ "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\n" \ "iz54ZFyNdQ==\n" \ "=WLpc\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" pub = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" \ "\n" \ "mQENBFOaNYoBCAC9FDOrASOxJoo3JhwCCln4wPy+A/UY1H0OYlc+MMolSwev2uDj\n" \ "nnwmt8ziNTjLuLEh3AnKjDWA9xvY5NW2ZkB6Edo6HQkquKLH7AkpLd82kiTWHdOw\n" \ "OH7OWQpz7z2z6e40wwHEduhyGcZ/Ja/A0+6GIb/2YFKlkwfnT92jtB94W//mL6wu\n" \ "LOkZMoU/CS/QatervzAf9VCemvAR9NI0UJc7Y0RC1B/1cBTQAUg70EhjnmJkqyYx\n" \ "yWqaXyfX10dsEX3+MyiP1kvUDfFwhdeL7E2H9sbFE5+MC9Eo99/Qezv3QoXzH2Tj\n" \ "bTun+QMVkbM92dj70KiExAJya9lSLZGCoOrDABEBAAG0M1Rlc3RSU0EtMjA0OCAo\n" \ "VEVTVElORy1VU0UtT05MWSkgPGVtYWlsQGFkZHJlc3MudGxkPokBNwQTAQoAIQUC\n" \ "U5o1igIbIwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRDA8iEODxk9zYQPB/4+\n" \ "kZlIwLE27J7IiZSkk+4T5CPrASxoSsRMadUvoHc0eiZIlQD2Gu05oQcm4kZojJAz\n" \ "Mv12rLtk+ZPwVOZU/TUxPYwuEyJP4keFJEW9P0GiURAvYQRQCbQ5IOlIkZ0tPotb\n" \ "010Ej3u5rHAiVCvh/cxF16UhkXknf/wgDDWErfGIMaaruAIr0G05p4Q2G/NLgBcc\n" \ "owSgFFfWprg3zfNPEQhH/qNs8O5mByniMZk4n2TsKGlX6eT9RrfJVQhSLoQXxYik\n" \ "MtiZTki4yPUhTQev62KWHQcY6zNV2p9VQ24NUhVCIBnZ0CLkm38QFsS5flWVGat5\n" \ "kraHTXxvffz7yGHJiFkiuQENBFOaNYoBCADBPjB83l1O2m/Nr5KDm6/BwKfrRsoJ\n" \ "DmMZ8nNHNUc/zK4RI4EFKkr35PSmgbA8yOlaSDWVz9zuKyOtb8Nohct2/lrac8zI\n" \ "+b4enZ/Z6qehoAdY1t4QYmA2PebKuerBXjIF1RWsPQDpu3GIZw4oBbdu5oUGB4I9\n" \ "yIepindM2b2I9dlY3ct4uhRbBmXPFcslmJ1K4pCurXvr4Po4DCcWqUmsGUQQbI1G\n" \ "UyAzSad7u9y3CRqhHFwzyFRRfl+/mgB2a6XvbGlG5Dkp1g7T/HIVJu+zv58AQkFw\n" \ "+ABuWNKCXa3TB51bkiBQlkRTSAu2tVZ8hVGZE+wUw0o9rLiy6mldFvbLABEBAAGJ\n" \ "AR8EGAEKAAkFAlOaNYoCGwwACgkQwPIhDg8ZPc1uDwf/SGoiZHjUsTWm4gZgZCzA\n" \ "jOpZs7dKjLL8Wm5G3HTFIGX0O8HCzQJARWq05N6EYmI4nPXxu08ba30SubybSeFU\n" \ "+iAPymqm2YNXrE2RwLWko78M0r9enUep6SvbGKnukPG7lz/33PsxIVyATfMmcmzV\n" \ "4chyC7pICTwgHv/zC3S/k7GoS82Z39LO4R4aDa4aubNq6mx4eHUd0MSnYud1IzRx\n" \ "D8cPxh9fCdoW0OpddqKNczAvO4bl5wwDafrEa7HpIX/sMVMZXo2h6TkitdLCdEfk\n" \ "tgEjS0hTsFtfwsXt9TKi1x3HJIbcm8t78ubpWXepB/iNKVzv4punFHhKiz54ZFyN\n" \ "dQ==\n" \ "=lqIH\n" \ "-----END PGP PUBLIC KEY BLOCK-----\n" # load the keypair above sk = PGPKey() sk.parse(sec) pk = PGPKey() pk.parse(pub) sigsubject = bytearray( b"Hello!I'm a test document.I'm going to get signed a bunch of times.KBYE!" ) sig = PGPSignature.new(SignatureType.BinaryDocument, PubKeyAlgorithm.RSAEncryptOrSign, HashAlgorithm.SHA512, sk.fingerprint.keyid) sig._signature.subpackets['h_CreationTime'][-1].created = datetime( 2014, 8, 6, 23, 28, 51) sig._signature.subpackets.update_hlen() hdata = sig.hashdata(sigsubject) sig._signature.hash2 = hashlib.new('sha512', hdata).digest()[:2] # create the signature signature = sk.__key__.__privkey__().sign(hdata, padding.PKCS1v15(), hashes.SHA512()) sig._signature.signature.from_signer(signature) sig._signature.update_hlen() # check encoding assert sig._signature.signature.md_mod_n.to_mpibytes()[2:3] != b'\x00' # with PGPy assert pk.verify(sigsubject, sig) if gpg: # with GnuPG with gpg.Context(armor=True, offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) # import the key key_data = gpg.Data(string=pub) gpg.core.gpgme.gpgme_op_import(c.wrapped, key_data) _, vres = c.verify(gpg.Data(string=sigsubject.decode('latin-1')), gpg.Data(string=str(sig))) assert vres
def verify_signature(self, lic_file_xml, signature_xml): # import pem from cryptography import x509 from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding """ :return: True if signature is fine :rtype : bool """ cur_time = int(time.time()) log_stat = { "target": 0, "emitted": 0, } def log(what, log_level=logging_tools.LOG_LEVEL_OK): log_stat["target"] += 1 if not self.license.idx: _logit = True elif self.license.idx not in LICENSE_LOG_CACHE: _logit = True elif abs(LICENSE_LOG_CACHE[self.license.idx] - cur_time) > 300: _logit = True else: _logit = False if _logit: log_stat["emitted"] += 1 self.log(what, log_level) backend = default_backend() signed_string = LicenseFileReader._extract_string_for_signature(lic_file_xml) # print(len(signed_string)) signature = base64.b64decode(signature_xml.text.encode("ascii")) # print("V" * 50) # print("*", signature_xml.text) # print(".", signature) cert_files = glob.glob("{}/*.pem".format(CERT_DIR)) # print(cert_files) result = -1 if not cert_files: # raise Exception("No certificate files in certificate dir {}.".format(CERT_DIR)) # currently it's not clear whether this is only bad or actually critical log( "No certificate files in certificate dir {}.".format(CERT_DIR), logging_tools.LOG_LEVEL_ERROR ) for cert_file in cert_files: short_cert_file = os.path.basename(cert_file) try: # print("*" * 20) cert = x509.load_pem_x509_certificate( open(cert_file, "rb").read(), backend, ) except: # print(process_tools.get_except_info()) log( "Failed to read certificate file {}: {}".format( cert_file, process_tools.get_except_info() ), logging_tools.LOG_LEVEL_WARN ) else: # print(cert) # only use certs which are currently valid now = datetime.datetime.now() # tz=pytz.timezone(TIME_ZONE)) # print("*", str(cert.get_not_before()) if cert.not_valid_before <= now <= cert.not_valid_after: # print("ok") verifier = cert.public_key().verifier( signature, padding.PSS( mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH, ), hashes.SHA512(), ) verifier.update(signed_string.encode("utf-8")) try: verifier.verify() except InvalidSignature: result = 0 else: # found a valid signature, exit result = 1 break # Result of verification: 1 for success, 0 for failure, -1 on other error. log( "Cert file {} verification result for '{}': {}".format( short_cert_file, str(self.license), result, ), logging_tools.LOG_LEVEL_WARN, ) else: log( "Cert file {} is not valid at this point in time".format(short_cert_file), logging_tools.LOG_LEVEL_ERROR ) if self.license.idx: if log_stat["emitted"]: LICENSE_LOG_CACHE[self.license.idx] = cur_time elif not log_stat["target"] and self.license.idx in LICENSE_LOG_CACHE: del LICENSE_LOG_CACHE[self.license.idx] return result == 1
OID_RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") OID_ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") OID_ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") OID_ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") OID_ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") OID_DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") OID_DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") OID_DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") _SIG_OIDS_TO_HASH = { OID_RSA_WITH_MD5.dotted_string: hashes.MD5(), OID_RSA_WITH_SHA1.dotted_string: hashes.SHA1(), OID_RSA_WITH_SHA224.dotted_string: hashes.SHA224(), OID_RSA_WITH_SHA256.dotted_string: hashes.SHA256(), OID_RSA_WITH_SHA384.dotted_string: hashes.SHA384(), OID_RSA_WITH_SHA512.dotted_string: hashes.SHA512(), OID_ECDSA_WITH_SHA224.dotted_string: hashes.SHA224(), OID_ECDSA_WITH_SHA256.dotted_string: hashes.SHA256(), OID_ECDSA_WITH_SHA384.dotted_string: hashes.SHA384(), OID_ECDSA_WITH_SHA512.dotted_string: hashes.SHA512(), OID_DSA_WITH_SHA1.dotted_string: hashes.SHA1(), OID_DSA_WITH_SHA224.dotted_string: hashes.SHA224(), OID_DSA_WITH_SHA256.dotted_string: hashes.SHA256() } OID_SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") OID_CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") OID_CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") OID_EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") OID_TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") OID_OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9")
def hash_pw(self, pw): h = hashes.Hash(hashes.SHA512(), backend=default_backend()) h.update(pw.encode()) return h.finalize()
from oslo_serialization import base64 from oslo_utils import encodeutils import six from glance.common import exception from glance.i18n import _LE LOG = logging.getLogger(__name__) # Note: This is the signature hash method, which is independent from the # image data checksum hash method (which is handled elsewhere). HASH_METHODS = { 'SHA-224': hashes.SHA224(), 'SHA-256': hashes.SHA256(), 'SHA-384': hashes.SHA384(), 'SHA-512': hashes.SHA512() } # These are the currently supported signature key types (RSA_PSS, ) = ('RSA-PSS', ) # This includes the supported public key type for the signature key type SIGNATURE_KEY_TYPES = {RSA_PSS: rsa.RSAPublicKey} # These are the currently supported certificate formats (X_509, ) = ('X.509', ) CERTIFICATE_FORMATS = {X_509} # These are the currently supported MGF formats, used for RSA-PSS signatures MASK_GEN_ALGORITHMS = {'MGF1': padding.MGF1}
def __init__(self): super(_RS512, self).__init__(padding.PKCS1v15(), hashes.SHA512())
class Ps512(RsaSsaPss): _name = KeyVaultSignatureAlgorithm.ps512 _default_hash_algorithm = hashes.SHA512()
def __init__(self): super(_ES512, self).__init__('P-521', hashes.SHA512())
class Es512(_Ecdsa): _name = "ES512" _default_hash_algorithm = hashes.SHA512()
def __init__(self): padfn = padding.PSS(padding.MGF1(hashes.SHA512()), hashes.SHA512.digest_size) super(_PS512, self).__init__(padfn, hashes.SHA512())
def test_encryption_context_hash(encryption_context, result): hasher = hashes.Hash(hashes.SHA512(), backend=default_backend()) assert _encryption_context_hash(hasher, encryption_context) == b64decode(result)
def __init__(self): super(_A256CbcHs512, self).__init__(hashes.SHA512())
ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") _SIG_OIDS_TO_HASH = { SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256() } class ExtendedKeyUsageOID(object): SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3")
ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") _SIG_OIDS_TO_HASH = { SignatureAlgorithmOID.RSA_WITH_MD5.dotted_string: hashes.MD5(), SignatureAlgorithmOID.RSA_WITH_SHA1.dotted_string: hashes.SHA1(), SignatureAlgorithmOID.RSA_WITH_SHA224.dotted_string: hashes.SHA224(), SignatureAlgorithmOID.RSA_WITH_SHA256.dotted_string: hashes.SHA256(), SignatureAlgorithmOID.RSA_WITH_SHA384.dotted_string: hashes.SHA384(), SignatureAlgorithmOID.RSA_WITH_SHA512.dotted_string: hashes.SHA512(), SignatureAlgorithmOID.ECDSA_WITH_SHA1.dotted_string: hashes.SHA1(), SignatureAlgorithmOID.ECDSA_WITH_SHA224.dotted_string: hashes.SHA224(), SignatureAlgorithmOID.ECDSA_WITH_SHA256.dotted_string: hashes.SHA256(), SignatureAlgorithmOID.ECDSA_WITH_SHA384.dotted_string: hashes.SHA384(), SignatureAlgorithmOID.ECDSA_WITH_SHA512.dotted_string: hashes.SHA512(), SignatureAlgorithmOID.DSA_WITH_SHA1.dotted_string: hashes.SHA1(), SignatureAlgorithmOID.DSA_WITH_SHA224.dotted_string: hashes.SHA224(), SignatureAlgorithmOID.DSA_WITH_SHA256.dotted_string: hashes.SHA256() } class ExtendedKeyUsageOID(object): SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3")
class CryptographyHMACKey(Key): """ Performs signing and verification operations using HMAC and the specified hash function. """ ALG_MAP = { ALGORITHMS.HS256: hashes.SHA256(), ALGORITHMS.HS384: hashes.SHA384(), ALGORITHMS.HS512: hashes.SHA512() } def __init__(self, key, algorithm): if algorithm not in ALGORITHMS.HMAC: raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) self._algorithm = algorithm self._hash_alg = self.ALG_MAP.get(algorithm) if isinstance(key, dict): self.prepared_key = self._process_jwk(key) return if not isinstance(key, str) and not isinstance(key, bytes): raise JWKError('Expecting a string- or bytes-formatted key.') if isinstance(key, str): key = key.encode('utf-8') invalid_strings = [ b'-----BEGIN PUBLIC KEY-----', b'-----BEGIN RSA PUBLIC KEY-----', b'-----BEGIN CERTIFICATE-----', b'ssh-rsa' ] if any(string_value in key for string_value in invalid_strings): raise JWKError( 'The specified key is an asymmetric key or x509 certificate and' ' should not be used as an HMAC secret.') self.prepared_key = key def _process_jwk(self, jwk_dict): if not jwk_dict.get('kty') == 'oct': raise JWKError("Incorrect key type. Expected: 'oct', Received: %s" % jwk_dict.get('kty')) k = jwk_dict.get('k') k = k.encode('utf-8') k = bytes(k) k = base64url_decode(k) return k def to_dict(self): return { 'alg': self._algorithm, 'kty': 'oct', 'k': base64url_encode(self.prepared_key).decode('ASCII'), } def sign(self, msg): msg = six.ensure_binary(msg) h = hmac.HMAC(self.prepared_key, self._hash_alg, backend=default_backend()) h.update(msg) signature = h.finalize() return signature def verify(self, msg, sig): msg = six.ensure_binary(msg) sig = six.ensure_binary(sig) h = hmac.HMAC(self.prepared_key, self._hash_alg, backend=default_backend()) h.update(msg) try: h.verify(sig) verified = True except InvalidSignature: verified = False return verified
def sha512(data): return _sha(hashes.SHA512(), data)
def _publish_certificate(req: object, issuer: dict): logger.info('Create a certificate builder...') crt_builder = x509.CertificateBuilder() crt_builder = crt_builder.subject_name(name=req._subject()) crt_builder = crt_builder.public_key(key=req._public_key()) for extension in req._extensions(): crt_builder = crt_builder.add_extension(extension=extension.value, critical=extension.critical) logger.info('Ready to sign the certificate request...') if not isinstance(issuer['valid_year'], int): issuer['valid_year'] = int(issuer['valid_year']) if issuer['is_ca'] == 'true': issuer['is_ca'] = True if issuer['is_ca'] == 'false': issuer['is_ca'] = False crt_builder = crt_builder.not_valid_before(time=datetime.datetime.today()) crt_builder = crt_builder.not_valid_after( time=datetime.datetime.today() + datetime.timedelta(days=issuer['valid_year'] * 365)) crt_builder = crt_builder.serial_number(number=x509.random_serial_number()) crt_builder = crt_builder.add_extension(extension=x509.BasicConstraints( ca=issuer['is_ca'], path_length=None), critical=True) logger.info( 'Select CA to sign the certificate signing request and output certificate' ) if issuer['ca'] == 'SelfSign': logger.debug('CA is self-signed') crt_builder = crt_builder.issuer_name(name=req._subject()) ca_key = req.private_key() else: ca_dir = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'common_static/ca') ca_file = "{}/{}.pfx".format(ca_dir, issuer['ca']) logger.debug("CA file is located in {}".format(ca_file)) with open(file=ca_file, mode='rb') as f: ca_bytes = f.read() logger.debug('CA file content is \n{}'.format(ca_bytes)) crt_chain = ReadCertificateChain({ 'bytes': ca_bytes, 'password': b'Cisco123!' }) ca_crt = crt_chain.certificate(data_type='object') ca_key = crt_chain.private_key(data_type='object') crt_builder = crt_builder.issuer_name(name=ca_crt.subject) hash_obj_list = { hashes.MD5(), hashes.SHA1(), hashes.SHA224(), hashes.SHA256(), hashes.SHA384(), hashes.SHA512(), hashes.SHA512_224(), hashes.SHA512_256(), hashes.SHA3_224(), hashes.SHA3_256(), hashes.SHA3_384(), hashes.SHA3_512() } for hash_obj in hash_obj_list: if issuer['hash_alg'] == hash_obj.name: hash_algor = hash_obj break else: hash_algor = hashes.MD5() return crt_builder.sign(private_key=ca_key, algorithm=hash_algor, backend=default_backend())
def sign(datau, key, cert, othercerts, hashalgo, attrs=True, signed_value=None, hsm=None, pss=False, timestampurl=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now(tz=util.timezone.utc) if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) else: cert = cert2asn(cert) certificates = [] certificates.append(cert) for i in range(len(othercerts)): certificates.append(cert2asn(othercerts[i])) hashalgo = unicode(hashalgo) if sys.version[0] < '3' else hashalgo signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': cert.issuer, 'serial_number': cert.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature': signed_value, } if not pss: signer['signature_algorithm'] = algos.SignedDigestAlgorithm({'algorithm': 'rsassa_pkcs1v15'}) else: if isinstance(key, keys.PrivateKeyInfo): salt_length = key.byte_size - hashes.SHA512.digest_size - 2 salt_length = hashes.SHA512.digest_size else: salt_length = padding.calculate_max_pss_salt_length(key, hashes.SHA512) signer['signature_algorithm'] = algos.SignedDigestAlgorithm({ 'algorithm': 'rsassa_pss', 'parameters': algos.RSASSAPSSParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha512'}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': algos.MaskGenAlgorithmId('mgf1'), 'parameters': { 'algorithm': algos.DigestAlgorithmId('sha512'), } }), 'salt_length': algos.Integer(salt_length), 'trailer_field': algos.TrailerField(1) }) }) if attrs: if attrs is True: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data',), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value,), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}),) }), ] else: signer['signed_attrs'] = attrs config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms(( algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau if hsm is not None: signed_value_signature = hsm.sign(keyid, tosign, hashalgo) elif isinstance(key, keys.PrivateKeyInfo): key = asymmetric.load_private_key(key) if pss: signed_value_signature = asymmetric.rsa_pss_sign( key, tosign, 'sha512' ) else: signed_value_signature = asymmetric.rsa_pkcs1v15_sign( key, tosign, hashalgo.lower() ) else: if pss: hasher = hashes.Hash(hashes.SHA512(), backend=backends.default_backend()) hasher.update(tosign) digest = hasher.finalize() signed_value_signature = key.sign( digest, padding.PSS( mgf=padding.MGF1(hashes.SHA512()), salt_length=salt_length ), utils.Prehashed(hashes.SHA512()) ) else: signed_value_signature = key.sign( tosign, padding.PKCS1v15(), getattr(hashes, hashalgo.upper())() ) if timestampurl is not None: signed_value = getattr(hashlib, hashalgo)(signed_value_signature).digest() tspreq = tsp.TimeStampReq({ "version": 1, "message_imprint": tsp.MessageImprint({ "hash_algorithm": algos.DigestAlgorithm({'algorithm': hashalgo}), "hashed_message": signed_value, }), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time()*1000), "cert_req": True, #'extensions': tsp.Extensions() }) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} tspresp = requests.post(timestampurl, data=tspreq, headers=tspheaders) if tspresp.headers.get('Content-Type', None) == 'application/timestamp-reply': tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp['status']['status'].native == 'granted': attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('signature_time_stamp_token'), 'values': cms.SetOfContentInfo([ cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': tspresp["time_stamp_token"]["content"], }) ]) }) ] datas['content']['signer_infos'][0]['unsigned_attrs'] = attrs # signed_value_signature = core.OctetString(signed_value_signature) datas['content']['signer_infos'][0]['signature'] = signed_value_signature #open('signed-content-info', 'wb').write(datas.dump()) return datas.dump()
import binascii import pytest from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends.interfaces import RSABackend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding _DIGESTS = { "SHA-1": hashes.SHA1(), "SHA-224": hashes.SHA224(), "SHA-256": hashes.SHA256(), "SHA-384": hashes.SHA384(), "SHA-512": hashes.SHA512(), } def should_verify(backend, wycheproof): if wycheproof.valid: return True if wycheproof.acceptable: if ( backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER and wycheproof.has_flag("MissingNull") ): return False return True
class Es512(_Ecdsa): _name = KeyVaultSignatureAlgorithm.es512 _default_hash_algorithm = hashes.SHA512() coordinate_length = 66