Beispiel #1
0
    def hybrid_encrypt(message: bytes, pk: rsa.RSAPublicKey) -> TapCHData:
        """
		This method is the hybrid encrypt outlined in the Tor spec 0.4 section
		:param message: The message to be encrypted
		:param pk: The RSA public to encrypt the message with
		:return: The object TapCHData that has the client handshake data
		"""
        # First convert the message to a byte array so that we can slice it etc.
        message = bytearray(message)

        if len(message
               ) <= CryptoConstants.PK_ENC_LEN - CryptoConstants.PK_PAD_LEN:
            # Then encrypt the message using the onion key
            p = pk.encrypt(
                message,
                padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                             algorithm=hashes.SHA256(),
                             label=None))

            # Create the TAP_H_DATA object
            padding_bytes = bytes(CryptoConstants.PK_PAD_LEN)
            tap_h_data = TapCHData(padding_bytes, None, p, None)

        else:
            k = bytearray(os.urandom(CryptoConstants.KEY_LEN))
            m1 = message[0:CryptoConstants.PK_ENC_LEN -
                         CryptoConstants.PK_PAD_LEN - CryptoConstants.KEY_LEN]
            m2 = message[CryptoConstants.PK_ENC_LEN -
                         CryptoConstants.PK_PAD_LEN - CryptoConstants.KEY_LEN:]
            p1 = pk.encrypt(
                bytes(k + m1),
                padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()),
                             algorithm=hashes.SHA1(),
                             label=None))

            nonce = bytes(
                CryptoConstants.KEY_LEN)  # all bytes are 0, nonce is the IV
            cipher = Cipher(algorithms.AES(k),
                            modes.CTR(nonce),
                            backend=default_backend())
            encryptor = cipher.encryptor()
            p2 = encryptor.update(m2) + encryptor.finalize()

            print(p1, len(p1))
            print(p2, len(p2))
            print(m2, len(m2))
            # tap_h_data = TapCHData(bytearray(p1)[CryptoConstants.PK_ENC_LEN - CryptoConstants.PK_PAD_LEN:],
            #                        bytearray(p1)[0:CryptoConstants.KEY_LEN],
            #                        bytearray(p1)[CryptoConstants.KEY_LEN:(CryptoConstants.PK_ENC_LEN - CryptoConstants.PK_PAD_LEN)],
            #                        p2)
            tap_h_data = TapCHData(
                bytearray(p1)[0:CryptoConstants.PK_PAD_LEN],
                bytearray(p1)[CryptoConstants.PK_PAD_LEN:(
                    CryptoConstants.PK_PAD_LEN + CryptoConstants.KEY_LEN)],
                bytearray(p1)[(CryptoConstants.PK_PAD_LEN +
                               CryptoConstants.KEY_LEN):], p2)

        return tap_h_data
Beispiel #2
0
    def hybrid_encrypt(message: bytes, pk: rsa.RSAPublicKey):
        """
        Some specifications will refer to the "legacy hybrid encryption" of a
        byte sequence M with a public key PK.  It is computed as follows:

      1. If the length of M is no more than PK_ENC_LEN-PK_PAD_LEN,
         pad and encrypt M with PK.
      2. Otherwise, generate a KEY_LEN byte random key K.
         Let M1 = the first PK_ENC_LEN-PK_PAD_LEN-KEY_LEN bytes of M,
         and let M2 = the rest of M.
         Pad and encrypt K|M1 with PK.  Encrypt M2 with our stream cipher,
         using the key K.  Concatenate these encrypted values.
        :param message: the message to encrypt
        :param pk: the public RSA key
        :return: the encrypted message
        """
        # This if shouldn't ever be true, because this algorithm is used with diffie hellman 128 bit keys.
        # M will be 128 bits, and adding key and padding to it will always make it more than 128 bits
        if len(message
               ) <= CryptoConstants.PK_ENC_LEN - CryptoConstants.PK_PAD_LEN:
            encrpt_msg = pk.encrypt(
                message,
                padding.OAEP(mgf=padding.MGF1(hashes.SHA1()),
                             algorithm=hashes.SHA1(),
                             label=None))
            padding_bytes = bytes(CryptoConstants.PK_PAD_LEN)
            tap_h_data = "temporary"
            print("[*] We got a shorter message. Weird")
        else:
            # Split the message
            m1 = message[:CryptoConstants.PK_ENC_LEN -
                         CryptoConstants.PK_PAD_LEN - CryptoConstants.KEY_LEN]
            m2 = message[CryptoConstants.PK_ENC_LEN -
                         CryptoConstants.PK_PAD_LEN - CryptoConstants.KEY_LEN:]
            # Generate encryption key for AES
            key = bytearray(os.urandom(CryptoConstants.KEY_LEN))
            m1 = bytes(key + m1)
            # Encrypt first part with RSA
            encrpt_msg1 = pk.encrypt(
                m1,
                padding.OAEP(mgf=padding.MGF1(hashes.SHA1()),
                             algorithm=hashes.SHA1(),
                             label=None))
            nonce = bytes(CryptoConstants.KEY_LEN)
            cipher = Cipher(algorithms.AES(key),
                            modes.CTR(nonce),
                            backend=default_backend())
            # Encrypt second part with AES
            encryptor = cipher.encryptor()
            encrpt_msg2 = encryptor.update(m2) + encryptor.finalize()
            return encrpt_msg1 + encrpt_msg2
Beispiel #3
0
 def encrypt(self, msg: str, public_key: RSAPublicKey) -> str:
     encrypted = public_key.encrypt(
         msg.encode("ascii"),
         padding=padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                              algorithm=hashes.SHA256(),
                              label=None))
     return binascii.b2a_base64(encrypted).decode("utf-8")
Beispiel #4
0
def pk_encrypt(message: bytes, public_key: rsa.RSAPublicKey) -> bytes:
    """
    Encrypt a message using RSAES-OAEP.
    """
    ciphertext = public_key.encrypt(
        message, padding.OAEP(padding.MGF1(hashes.SHA1()), hashes.SHA1(),
                              None))
    return ciphertext
Beispiel #5
0
def pk_encrypt(message: bytes, public_key: rsa.RSAPublicKey) -> bytes:
    """
    Encrypt a message using RSAES-OAEP.
    """
    ciphertext = public_key.encrypt(message, padding.OAEP(
            padding.MGF1(hashes.SHA1()),
            hashes.SHA1(),
            None))
    return ciphertext
Beispiel #6
0
def rsa_encrypt(public_key: rsa.RSAPublicKey, message: bytes) -> bytes:
    return public_key.encrypt(
        message,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None,
        ),
    )
Beispiel #7
0
def _generate_rsa_seed(key: rsa.RSAPublicKey, hashAlg: int,
                       label: bytes) -> Tuple[bytes, bytes]:
    halg = _get_digest(hashAlg)
    if halg is None:
        raise ValueError(f"unsupported digest algorithm {hashAlg}")
    seed = secrets.token_bytes(halg.digest_size)
    mgf = padding.MGF1(halg())
    padd = padding.OAEP(mgf, halg(), label)
    enc_seed = key.encrypt(seed, padd)
    return (seed, enc_seed)
Beispiel #8
0
 def encrypt(self, message: bytes, otherkey: rsa.RSAPublicKey):
     signature = self.__privkey.sign(
         message,
         apadding.PSS(mgf=apadding.MGF1(hashes.SHA256()),
                      salt_length=apadding.PSS.MAX_LENGTH), hashes.SHA256())
     ciphertext = otherkey.encrypt(
         message,
         apadding.OAEP(mgf=apadding.MGF1(algorithm=hashes.SHA256()),
                       algorithm=hashes.SHA256(),
                       label=None))
     return signature + ciphertext
def rsa_encrypt(short_message: bytes, public_key: rsa.RSAPublicKey) -> bytes:
    """ encrypt Optimal Asymmetric Encryption Padding (OAEP)"""
    hash_algorithm = hashes.SHA512 if public_key.key_size >= 2048 else hashes.SHA256
    return public_key.encrypt(
        plaintext=short_message,
        padding=padding.OAEP(
            mgf=padding.MGF1(algorithm=hash_algorithm()),
            algorithm=hash_algorithm(),
            label=None
        )
    )
Beispiel #10
0
def encrypt(pub_key: rsa.RSAPublicKey, msg: str | bytes) -> bytes:
    """
    Encrypt a chat message and return the encrypted string.

    :param pub_key: RSA public key to encrypt the message with.
    :type pub_key: :class:`rsa.RSAPublicKey`
    :param msg: Message to encrypt.
    :type msg: :type:`str`
    :return: Encrypted message.
    :rtype: bytes
    """
    msg = _bytes(msg)
    return pub_key.encrypt(
        msg, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                          algorithm=hashes.SHA256(), label=None))
Beispiel #11
0
    def send_pgp_key(self, msg: bytes,
                     receiver_public_key: RSAPublicKey) -> PGPPacket:
        """
        Send `msg` using PGP method
        :param msg: secret message
        :param receiver_public_key: receiver's public key
        :return: List containing encrypted message, signed hash and secret key. Message and hash also contain their IV.
        """
        # Sign message hash
        signed_hash: bytes = self.sign_message(msg)

        # Zip message and its signed hash

        message: List[bytes] = [msg, signed_hash]
        zipped_message: List[bytes] = [zlib.compress(m) for m in message]

        # Encrypt message and hash as AESEncryptedData
        iv = os.urandom(16)
        encrypted_message: List = [
            AESEncryptedData(data=self.encrypt(m, iv), iv=iv)
            for m in zipped_message
        ]

        # Encrypt secret_key using receiver's public key
        encrypted_secret_key: bytes = receiver_public_key.encrypt(
            plaintext=self._secret_key,
            padding=padding.OAEP(padding.MGF1(algorithm=hashes.SHA256()),
                                 algorithm=hashes.SHA256(),
                                 label=None))

        # Add encrypted secret key to message
        encrypted_message.append(encrypted_secret_key)
        packet = PGPPacket(data=encrypted_message[0],
                           signature=encrypted_message[1],
                           secret_key=encrypted_message[2])
        return packet