def DeriveECDHSecretFromKey(privateKey, publicKey):
    """Generate a shared secret from keys in ecdsa.Keys format."""

    derive = ECDH(curve=NIST256p)
    derive.load_private_key(privateKey)
    derive.load_received_public_key(publicKey)

    secret = derive.generate_sharedsecret_bytes()
    return secret
Ejemplo n.º 2
0
def DecryptMessage(privateKey_hex, encrypted_hex):
    if privateKey_hex[:2] == '0x':
        privateKey_hex = privateKey_hex[2:]
    if encrypted_hex[:2] == '0x':
        encrypted_hex = encrypted_hex[2:]

    # get the components
    encrypted = bytearray.fromhex(encrypted_hex)
    iv = encrypted[:16]
    ephemPubKeyEncoded = encrypted[17:81]
    mac = encrypted[81:113]
    ciphertext = encrypted[113:]

    # recover the temporary public key
    ephemPubKey = VerifyingKey.from_string(ephemPubKeyEncoded, curve=SECP256k1)

    # load the private key
    priv_key = SigningKey.from_secret_exponent(int(privateKey_hex, 16),
                                               curve=SECP256k1)
    ecdh = ECDH(curve=SECP256k1, private_key=priv_key)

    # ECDH => get the shared secret
    ecdh.load_received_public_key(ephemPubKey)
    px = ecdh.generate_sharedsecret_bytes()

    # compute the encription and MAC keys
    hash_px = SHA512.new(data=px).digest()
    encryptionKey = hash_px[:32]
    macKey = hash_px[32:]

    # check the MAC
    dataToMac = iv + bytearray([4]) + ephemPubKeyEncoded + ciphertext
    computed_mac = hmac.new(macKey, dataToMac, 'sha256').digest()
    if computed_mac != mac:
        raise ValueError("MAC missmatch")

    #decipher the text
    plaintext = AES256CbcDecrypt(ciphertext.hex(), encryptionKey, iv)
    return plaintext.decode("utf-8")
Ejemplo n.º 3
0
def EncryptMessage(publicKey_hex, plainText_string):
    if publicKey_hex[:2] == '0x':
        publicKey_hex = publicKey_hex[2:]
    publicKey_bin = bytearray.fromhex(publicKey_hex)

    # Generate the temporary key
    ecdh = ECDH(curve=SECP256k1)
    ecdh.generate_private_key()

    ephemPubKeyEncoded = bytearray.fromhex(
        ecdh.get_public_key().to_string().hex())

    # Load the public key
    publicKey = VerifyingKey.from_string(publicKey_bin, curve=SECP256k1)

    # ECDH => get the shared secret
    ecdh.load_received_public_key(publicKey)

    px = ecdh.generate_sharedsecret_bytes()

    # compute the encription and MAC keys
    hash_px = SHA512.new(data=px).digest()
    encryptionKey = hash_px[:32]
    macKey = hash_px[32:]

    # cipher the plain text
    iv = Random.get_random_bytes(16)
    plaintext = plainText_string.encode(encoding='utf_8')
    ciphertext = AES256CbcEncrypt(plaintext, encryptionKey, iv)

    # compute the MAC
    dataToMac = iv + bytearray([4]) + ephemPubKeyEncoded + ciphertext
    mac = hmac.new(macKey, dataToMac, 'sha256').digest()

    #build the output
    serializedCiphertext = iv + bytearray(
        [4]) + ephemPubKeyEncoded + mac + ciphertext
    return serializedCiphertext.hex()
Ejemplo n.º 4
0
class SecureChannel:
    def __init__(self, loglevel=logging.WARNING):
        logger.setLevel(loglevel)
        logger.debug("In __init__")
        self.initialized_secure_channel = False
        self.sc_privkey = None
        self.sc_pubkey = None
        self.sc_peer_pubkey = None
        self.sc_IV = None
        self.sc_IVcounter = None
        self.shared_key = None
        self.derived_key = None
        self.mac_key = None

        self.ecdh = ECDH(curve=SECP256k1)
        self.ecdh.generate_private_key()
        self.sc_pubkey = self.ecdh.get_public_key()
        self.sc_pubkey_serialized = self.sc_pubkey.to_string(
            encoding='uncompressed')

    def initiate_secure_channel(self, peer_pubkey_bytes):
        logger.debug("In initiate_secure_channel()")

        self.sc_IVcounter = 1

        #using ecdsa
        self.sc_peer_pubkey = VerifyingKey.from_string(peer_pubkey_bytes,
                                                       curve=SECP256k1)
        self.ecdh.load_received_public_key(self.sc_peer_pubkey)
        self.shared_key = self.ecdh.generate_sharedsecret_bytes()

        #logger.debug("Shared key:"+ self.shared_key.hex()) #debug

        mac = hmac.new(self.shared_key, "sc_key".encode('utf-8'), sha1)
        self.derived_key = mac.digest()[:16]
        mac = hmac.new(self.shared_key, "sc_mac".encode('utf-8'), sha1)
        self.mac_key = mac.digest()

        # alternative derivation
        # tmp_key= sha256(self.shared_key).digest()
        # self.derived_key = tmp_key[:16]
        # tmp_key= sha256(tmp_key).digest()
        # self.mac_key= tmp_key[:20]

        # logger.debug("Derived_key key:"+ self.derived_key.hex()) #debug
        # logger.debug("Mac_key key:"+ self.mac_key.hex()) #debug

        self.initialized_secure_channel = True

    def encrypt_secure_channel(self, data_bytes):
        logger.debug("In encrypt_secure_channel()")
        if not self.initialized_secure_channel:
            raise UninitializedSecureChannelError(
                'Secure channel is not initialized')

        ## for encryption, the data is padded with PKCS#7 (done by PADDING_DEFAULT)
        # blocksize= 16
        # size=len(apdu)
        # padsize= blocksize - (size%blocksize)
        # apdu= apdu+ [padsize]*padsize

        key = self.derived_key
        iv = urandom(12) + (self.sc_IVcounter).to_bytes(4, byteorder='big')

        aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
        aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_DEFAULT)
        ciphertext = aes.feed(data_bytes) + aes.feed()

        self.sc_IVcounter += 2

        data_to_mac = iv + len(ciphertext).to_bytes(
            2, byteorder='big') + ciphertext
        mac = hmac.new(self.mac_key, data_to_mac, sha1).digest()

        return (iv, ciphertext, mac)

    def decrypt_secure_channel(self, iv, ciphertext):
        logger.debug("In decrypt_secure_channel()")
        if not self.initialized_secure_channel:
            raise UninitializedSecureChannelError(
                'Secure channel is not initialized')

        key = self.derived_key

        aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
        aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_DEFAULT)
        decrypted = aes.feed(ciphertext) + aes.feed()

        # #remove padding (already done with PADDING_DEFAULT)
        # #logger.debug(f'Plaintext with padding: {toHexString(plaintext)}')
        # plaintext= list(plaintext)
        # pad= plaintext[-1]
        # plaintext=plaintext[0:-pad]
        # #logger.debug(f'Plaintext without padding: {toHexString(plaintext)}')

        return list(decrypted)