def read_certificate(crt): """ Read details about a certificate. crt: Path to PEM-encoded certificate file or PEM-encoded string. CLI Example: .. code-block:: bash salt '*' pki.read_certificate /etc/ssl/certs/example.crt """ if os.path.exists(crt): with _fopen(crt, "rb") as f: crt = x509.load_pem_x509_certificate(f.read(), _default_backend()) else: crt = x509.load_pem_x509_certificate(crt.encode(), _default_backend()) ret = { "extensions": _read_extensions(crt.extensions), "issuer": _read_name(crt.issuer), "not_valid_after": str(crt.not_valid_after), "not_valid_before": str(crt.not_valid_before), "public_key": _read_public_key(crt.public_key(), text=True), "serial": crt.serial_number, "subject": _read_name(crt.subject), } return ret
def create_private_key(path, type="ec", size=4096, curve="secp256r1"): """ Create an RSA or elliptic curve private key in PEM format. path: The file path to write the private key to. File are written with ``600`` as file mode. type: Key type to generate, either ``ec`` (default) or ``rsa``. size: Key length of an RSA key in bits. Defaults to ``4096``. curve: Curve to use for an EC key. Defaults to ``secp256r1``. CLI example: .. code-block:: bash salt '*' pki.create_private_key /etc/ssl/private/example.key salt '*' pki.create_private_key /etc/ssl/private/rsa.key type=rsa """ # pylint: disable=redefined-builtin ret = {"type": type} if type == "rsa": key = rsa.generate_private_key(public_exponent=65537, key_size=size, backend=_default_backend()) ret["size"] = size elif type == "ec": key = ec.generate_private_key( # pylint: disable=protected-access curve=ec._CURVE_TYPES[curve.lower()], backend=_default_backend(), ) ret["curve"] = curve else: raise SaltInvocationError("Unsupported key type: {}".format(type)) out = key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) with _fpopen(path, "wb", mode=0o600) as f: f.write(out) return ret
def generate_kcv(key: bytes, length: int = 2) -> bytes: r"""Generate DES key checksum value (KCV). Parameters ---------- key : bytes Binary key to provide check digits for. Has to be a valid DES key. length : int, optional Number of KCV bytes returned (default 2). Returns ------- kcv : bytes Binary KCV (`length` bytes) Examples -------- >>> import psec >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> psec.des.generate_kcv(key).hex().upper() '08D7' """ cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) encryptor = cipher.encryptor() return encryptor.update(b"\x00\x00\x00\x00\x00\x00\x00\x00")[:length]
def key_check_digits(key: bytes, length: int = 2) -> bytes: r"""Calculate Triple DES key check digits. Parameters ---------- key : bytes Binary key to provide check digits for. Has to be a valid DES key. length : int, optional Number of key check digits bytes provided in the response (default 2). Returns ------- check_digits : bytes Binary check digits (`length` bytes) Examples -------- >>> from pyemv import tools >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> tools.key_check_digits(key).hex().upper() '08D7' """ cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) encryptor = cipher.encryptor() return encryptor.update(b"\x00\x00\x00\x00\x00\x00\x00\x00")[:length]
def encrypt_tdes_cbc(key: bytes, iv: bytes, data: bytes) -> bytes: r"""Encrypt data using Triple DES CBC algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. iv : bytes Binary initial initialization vector for CBC. data : bytes Binary data to be encrypted. Returns ------- encrypted_data : bytes Binary encrypted data. Examples -------- >>> from pyemv.tools import encrypt_tdes_cbc >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> iv = bytes.fromhex("0000000000000000") >>> encrypt_tdes_cbc(key, iv, b"12345678").hex().upper() '41D2FFBA3CDC15FE' """ cipher = _Cipher( _algorithms.TripleDES(key), _modes.CBC(iv), backend=_default_backend(), ) return cipher.encryptor().update(data)
def read_private_key(path): """ Read details about a private key. path: Path to a private key in PEM format. CLI Example: .. code-block:: bash salt '*' pki.read_private_key /etc/ssl/private/example.key """ ret = {} with _fopen(path, "rb") as f: key = serialization.load_pem_private_key(f.read(), password=None, backend=_default_backend()) if isinstance(key, ec.EllipticCurvePrivateKey): ret["type"] = "ec" ret["curve"] = key.curve.name elif isinstance(key, rsa.RSAPrivateKey): ret["type"] = "rsa" ret["size"] = key.key_size else: raise SaltInvocationError("Unsupported private key object: {0}".format( type(key))) return ret
def encrypt_tdes_ecb(key: bytes, data: bytes) -> bytes: r"""Encrypt data using Triple DES ECB algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. data : bytes Binary data to be encrypted. Returns ------- encrypted_data : bytes Binary encrypted data. Examples -------- >>> from pyemv.tools import encrypt_tdes_ecb >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> encrypt_tdes_ecb(key, b"12345678").hex().upper() '41D2FFBA3CDC15FE' """ cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) return cipher.encryptor().update(data)
def _aes256cbc_encrypt(key, iv, plaintext): algo = _AES(key) mode = _CBC(iv) backend = _default_backend() cipher = _Cipher(algo, mode, backend) encryptor = cipher.encryptor() ciphertext = encryptor.update(plaintext) ciphertext += encryptor.finalize() return ciphertext
def _load_trusted_ca_certs(cafile): """Parse the tlsCAFile into a list of certificates.""" with open(cafile, "rb") as f: data = f.read() # Load all the certs in the file. trusted_ca_certs = [] backend = _default_backend() for cert_data in _re.findall(_CERT_REGEX, data): trusted_ca_certs.append(_load_pem_x509_certificate(cert_data, backend)) return trusted_ca_certs
def read_csr(csr): """ Read details about a certificate signing request. csr: Path to a certificate signing request file or a PEM-encoded string. """ if not isinstance(csr, x509.CertificateSigningRequest): if os.path.isfile(csr): with _fopen(csr, "rb") as f: csr = x509.load_pem_x509_csr(f.read(), _default_backend()) else: csr = x509.load_pem_x509_csr(csr.encode(), _default_backend()) return { "extensions": _read_extensions(csr.extensions), "public_key": _read_public_key(csr.public_key(), text=True), "subject": _read_name(csr.subject), }
def __encryption(): __salt = b'salt_' __user_input = bytes(input("[Input]: "), "utf8") _KDF = _PBKDF2HMAC(algorithm=_hashes.SHA256(), length=32, salt=__salt, iteration=100000, backend=_default_backend()) __encrypted_String = __user_input.encode() # Convert to `bytes[]` __key = base64.urlsafe_b64decode(_KDF.derive(__encrypted_String)) __file = open("exported_keys/_crypto_key.key", "wb") __file.write("Key:", __key, "\n", "User Input: ", __user_input, "\n", "Encrypted: ", __encrypted_String) __file.close()
def _private_key(self): path = os.path.join(self.base, "private.key") if not os.path.exists(path): logging.info("ACME: creating new private account key...") with _fpopen(path, "wb", mode=0o600) as f: f.write( rsa.generate_private_key( public_exponent=65537, key_size=4096, backend=_default_backend() ).private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) ) with _fopen(path, "rb") as f: return josepy.JWK.load(f.read())
def _public_key_hash(cert): public_key = cert.public_key() # https://tools.ietf.org/html/rfc2560#section-4.2.1 # "KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key # (excluding the tag and length fields)" # https://stackoverflow.com/a/46309453/600498 if isinstance(public_key, _RSAPublicKey): pbytes = public_key.public_bytes(_Encoding.DER, _PublicFormat.PKCS1) elif isinstance(public_key, _EllipticCurvePublicKey): pbytes = public_key.public_bytes(_Encoding.X962, _PublicFormat.UncompressedPoint) else: pbytes = public_key.public_bytes(_Encoding.DER, _PublicFormat.SubjectPublicKeyInfo) digest = _Hash(_SHA1(), backend=_default_backend()) digest.update(pbytes) return digest.finalize()
def decrypt_tdes_cbc(key: bytes, iv: bytes, data: bytes) -> bytes: r"""Decrypt data using Triple DES CBC algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. iv : bytes Binary initial initialization vector for CBC. Has to be 8 bytes long. data : bytes Binary data to be decrypted. Has to be multiple of 8 bytes. Returns ------- decrypted_data : bytes Binary decrypted data. Raises ------ ValueError Data length must be multiple of DES block size 8. Examples -------- >>> import psec >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> iv = bytes.fromhex("0000000000000000") >>> psec.des.decrypt_tdes_cbc(key, iv, bytes.fromhex("41D2FFBA3CDC15FE")) b'12345678' """ if len(data) < 8 or len(data) % 8 != 0: raise ValueError( f"Data length ({str(len(data))}) must be multiple of DES block size 8." ) cipher = _Cipher( _algorithms.TripleDES(key), _modes.CBC(iv), backend=_default_backend(), ) return cipher.decryptor().update(data)
def renewal_needed(path, days_remaining=28): """ Check if a certificate expires within the specified days. path: Path to PEM encoded certificate file. days_remaining: The minimum number of days remaining when the certificate should be renewed. Defaults to 28 days. """ with _fopen(path, "rb") as f: crt = x509.load_pem_x509_certificate(f.read(), backend=_default_backend()) remaining_days = (crt.not_valid_after - datetime.datetime.now()).days return remaining_days < days_remaining
def encrypt_tdes_ecb(key: bytes, data: bytes) -> bytes: r"""Encrypt data using Triple DES ECB algorithm. Parameters ---------- key : bytes Binary Triple DES key. Has to be a valid DES key. data : bytes Binary data to be encrypted. Has to be multiple of 8 bytes. Returns ------- encrypted_data : bytes Binary encrypted data. Raises ------ ValueError Data length must be multiple of DES block size 8. Examples -------- >>> import psec >>> key = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> psec.des.encrypt_tdes_ecb(key, b"12345678").hex().upper() '41D2FFBA3CDC15FE' """ if len(data) < 8 or len(data) % 8 != 0: raise ValueError( f"Data length ({str(len(data))}) must be multiple of DES block size 8." ) cipher = _Cipher(_algorithms.TripleDES(key), _modes.ECB(), backend=_default_backend()) return cipher.encryptor().update(data)
def generate_retail_mac( key1: bytes, key2: bytes, data: bytes, padding: int, length: _typing.Optional[int] = None, ) -> bytes: r"""ISO/IEC 9797-1 MAC algorithm 3 aka retail MAC. Requires two independent keys. All blocks until the last are processed using single DES using key1. The last data block is processed using TDES using key2 and key1. The resulting block is the MAC. Parameters ---------- key1 : bytes Binary MAC key used in initial transformation. Has to be a valid DES key. key2 : bytes Binary MAC key used in output transformation. Has to be a valid DES key. data : bytes Data to be MAC'd. padding : int Padding method of `data`. - 1 = ISO/IEC 9797-1 method 1. - 2 = ISO/IEC 9797-1 method 2. - 3 = ISO/IEC 9797-1 method 3. length : int, optional Desired MAC length [4 <= N <= 8] (default 8 bytes). Returns ------- mac : bytes Returns a binary MAC of requested length Raises ------ ValueError Invalid padding method specified Notes ----- See https://en.wikipedia.org/wiki/ISO/IEC_9797-1 for the algorithm reference. See Also -------- psec.mac.pad_iso_1 : ISO/IEC 9791-1 padding method 1 psec.mac.pad_iso_2 : ISO/IEC 9791-1 padding method 2 psec.mac.pad_iso_3 : ISO/IEC 9791-1 padding method 3 Examples -------- >>> import psec >>> key1 = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> key2 = bytes.fromhex("FEDCBA98765432100123456789ABCDEF") >>> data = bytes.fromhex("1234567890ABCDEF") >>> psec.mac.generate_retail_mac(key1, key2, data, padding=2).hex().upper() '644AA5C915DBDAF8' """ if length is None: length = 8 try: data = _pad_dispatch[padding](data, 8) except KeyError: raise ValueError("Specify valid padding method: 1, 2 or 3.") # Encrypt first block with key1 then # encrypt the rest of the data in CBC mode cipher1 = _Cipher( _algorithms.TripleDES(key1), _modes.CBC(b"\x00\x00\x00\x00\x00\x00\x00\x00"), backend=_default_backend(), ) encryptor1 = cipher1.encryptor() data = encryptor1.update(data)[-8:] # Decrypt the last block with key2 and then encrypt it with key1 cipher2 = _Cipher( _algorithms.TripleDES(key2), _modes.CBC(data), backend=_default_backend() ) decryptor2 = cipher2.decryptor() return encryptor1.update(decryptor2.update(data))[:length]
def create_csr(path=None, text=False, algorithm="sha384", **kwargs): """ Create a certificate signing request (CSR). path: Path to write the CSR to. text: Directly return PEM-encoded CSR instead of dictionary with details. Either ``path`` or ``text`` must be specified. key: Path to the private key used to sign the CSR. subject: Dictionary with subject name pairs. .. code-block:: {"commonName": "localhost"} domains: Alias method to quickly create a CSR with DNS names. All given domains will be added as DNS names to the subject alternative name extension and the first domain will additionally used for the subjects common name. extensions: Dictionary with x509v3 extensions. Supported extensions are: subjectAltName: x509v3 Subject Alternative Name .. code-block:: {"subjectAltName": "DNS:www.example.org,IP:192.0.2.1"} """ key = kwargs.get("key", None) subject = kwargs.get("subject", {}) extensions = kwargs.get("extensions", {}) if not path and not text: raise SaltInvocationError("Either path or text must be specified") if not key: raise SaltInvocationError("Key required") if "domains" in kwargs: domains = kwargs["domains"] if isinstance(domains, str): domains = [d.strip() for d in domains.split(",")] if isinstance(domains, list): if not subject: subject = {"commonName": domains[0]} if "subjectAltName" not in extensions: extensions["subjectAltName"] = [f"DNS:{n}" for n in domains] if not subject: raise SaltInvocationError("Subject required") if algorithm not in _HASHES: raise SaltInvocationError(f"Algorithm not supported: {algorithm}") subject = _create_name(subject) extensions = _create_extensions(extensions) with _fopen(key, "rb") as f: key = serialization.load_pem_private_key(f.read(), password=None, backend=_default_backend()) csr = x509.CertificateSigningRequestBuilder(subject, extensions).sign( key, _HASHES[algorithm], backend=_default_backend()) out = csr.public_bytes(serialization.Encoding.PEM) if path: with _fopen(path, "wb") as f: f.write(out) if text: return out.decode() return read_csr(csr)
import os import pathlib import socket from cryptography.hazmat.backends import default_backend as _default_backend from cryptography.hazmat.primitives.asymmetric import rsa from . import aesm_pb2 fspath = getattr(os, 'fspath', str) # pylint: disable=invalid-name ATTRIBUTES = bytes.fromhex('0600000000000000 1f00000000000000') # flags, xfrm AESMD_SOCKET = pathlib.Path('/var/run/aesmd/aesm.socket') _backend = _default_backend() # pylint: disable=invalid-name def get_token(): mrenclave = os.urandom(32) key = rsa.generate_private_key(public_exponent=3, key_size=3072, backend=_backend) modulus = key.public_key().public_numbers().n.to_bytes(384, 'little') req = aesm_pb2.GetTokenReq(req=aesm_pb2.GetTokenReqRaw( signature=mrenclave, key=modulus, attributes=ATTRIBUTES, timeout=10000)).SerializeToString() sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(fspath(AESMD_SOCKET))
def mac_iso9797_3(key1: bytes, key2: bytes, data: bytes, padding: int, length: Optional[int] = None) -> bytes: r"""ISO/IEC 9797-1 MAC algorithm 3. Requires two independent keys. Only the last data block is processed using TDES, all previous blocks are processed using single DES. Parameters ---------- key1 : bytes Binary MAC key used in initial transformation. Has to be a valid DES key. key2 : bytes Binary MAC key used in output transformation. Has to be a valid DES key. data : bytes Data to be MAC'd. padding : int Padding method of `data`. - 1 = ISO/IEC 9797-1 method 1. - 2 = ISO/IEC 9797-1 method 2. - 3 = ISO/IEC 9797-1 method 3. length : int, optional Desired length of AC [4 <= N <= 8] (default 8 bytes). Returns ------- mac : bytes Returns a binary MAC of requested length Raises ------ ValueError Invalid padding method specified Notes ----- See https://en.wikipedia.org/wiki/ISO/IEC_9797-1 for the algorithm reference. See Also -------- pyemv.mac.pad_iso9797_1 : ISO/IEC 9791-1 padding method 1 pyemv.mac.pad_iso9797_2 : ISO/IEC 9791-1 padding method 2 pyemv.mac.pad_iso9797_3 : ISO/IEC 9791-1 padding method 3 Examples -------- >>> from pyemv.mac import mac_iso9797_3 >>> key1 = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> key2 = bytes.fromhex("FEDCBA98765432100123456789ABCDEF") >>> data = bytes.fromhex("1234567890ABCDEF") >>> mac_iso9797_3(key1, key2, data, padding=2).hex().upper() '644AA5C915DBDAF8' """ if length is None: length = 8 if padding == 1: data = pad_iso9797_1(data, 8) elif padding == 2: data = pad_iso9797_2(data, 8) elif padding == 3: data = pad_iso9797_3(data, 8) else: raise ValueError("Specify valid padding method: 1, 2 or 3.") # Encrypt first block with key1 then # encrypt the rest of the data in CBC mode cipher1 = _Cipher( _algorithms.TripleDES(key1), _modes.CBC(b"\x00\x00\x00\x00\x00\x00\x00\x00"), backend=_default_backend(), ) encryptor1 = cipher1.encryptor() data = encryptor1.update(data)[-8:] # Decrypt the last block with key2 and then encrypt it with key1 cipher2 = _Cipher(_algorithms.TripleDES(key2), _modes.CBC(data), backend=_default_backend()) decryptor2 = cipher2.decryptor() return encryptor1.update(decryptor2.update(data))[:length]
#!/usr/bin/env python # -*- coding: utf-8 -*- # -*- author: [email protected] -*- import os import base64 from binascii import Error from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend as _default_backend from cryptography.exceptions import InvalidSignature, InvalidTag default_backend = _default_backend() def encode(*bytes): return base64.b64encode(bytes[0]).decode('ascii') if len(bytes) == 1 else [ encode(i) for i in bytes ] def decode(*str): return base64.b64decode( str[0], validate=True) if len(str) == 1 else [decode(i) for i in str] def encrypt_password(password, key=None): if key: key = decode(key) verify = True