def DecryptECIES(curve_name, R, enc, t, pwd):
    '''Performs ECIES decryption.'''
    # Setup for Decryption
    E = PredefinedCurves(curve_name)

    # Get secret key s
    hashpwd = SHA512.new(pwd).hexdigest() + RIPEMD.new(pwd).hexdigest()
    s = int(str(int(hashpwd,16))[0: len(str(E.N))]) % E.N
    if s < 2:
        s = E.N/2

    # Begin Decryption
    Z = E.multPoint(s,R)
    RZ = str(R)+str(Z)
    H1 = SHA512.new(RZ).hexdigest()
    k1 = H1[0:32]
    k2 = H1[32:128]
    H2 = RIPEMD.new(enc+k2).digest()

    # If the hashes don't match, stop
    if base64.b64decode(t) != H2:
        return "Error: Hashes don't match! Your public key password is most likely incorrect.  It is also possible, though improbable, that you selected the wrong encrypted image."

    cipher = AES.new(k1)
    message = cipher.decrypt(base64.b64decode(enc))

    return message
def PublicKeyECIES(curve_name, pwd, im):
    '''Create ECIES public key, create the associated binary string, and pass to the image encoder.'''
    # --------------------------
    # ECIES Public Key Creation
    # --------------------------

    E = PredefinedCurves(curve_name)

    # Generate secret key s via a password hashing.
    # Use a concatonation of two hash functions to make sure we have enough characters to get a full strength secret key.
    # For full strenth we need: number of digits of integer version of hash >= numbber of digits of the prime we're working over.
    hashpwd = SHA512.new(pwd).hexdigest() + RIPEMD.new(pwd).hexdigest()

    # Convert from hex to int, make hashpwd the same length as the order of the point we're using, then take it modulo order.
    s = int(str(int(hashpwd,16))[0: len(str(E.N))]) % E.N

    # If s = 0 or s = 1 (very unlikely), we want to use a different value.
    if s < 2:
        s = E.N/2

    # Use the secret key s to generate the public key.
    B = E.multPoint(s, E.A)

    # -------------------------------------------------------------
    # Create a binary string from the given public key information
    # -------------------------------------------------------------
    #
    # Create a binary string with public key info separated by 2's.
    # End the string with consecutive 2's.
    #
    # The information is encoded in the following order:
    #
    # 0. Initial check string.
    # 1. Length of curve name.
    # 2. x-coordinate of ellipitc curve point B.
    # 3. y-coordinate of ellipitc curve point B.
    # 4. Curve name.
    # -------------------------------------------------------------

    # Change curve name to binary, each character separated by a 2.
    curve_name_bin = '2'.join([bin(ord(ch)).lstrip('0b') for ch in curve_name])

    # Initialize our string as "111111" so we have a quick check that our file is valid when decoding.
    bit_string = '1111112'

    # Now append on the binary public key information with a '2' separating each entry.
    # Note: curve_name_bin already ends in 2 so we only need to add one 2 at the final step.
    bit_string += bin(len(curve_name)).lstrip('0b') + '2'
    bit_string += bin(B[0]).lstrip('0b') + '2'
    bit_string += bin(B[1]).lstrip('0b') + '2'
    bit_string += curve_name_bin + '2'

    return EncodeImageInfo(bit_string, im)
def EncryptECIES(curve_name, B, msg, im):
    '''Perform ECIES encryption, create the associated binary string, and pass to the image encoder.'''
    E = PredefinedCurves(curve_name)

    # Make sure the length is correct, otherwise add white space.  For AES message length must be multiple of 16.
    while len(msg) % 16 != 0:
        msg += ' '

    # Begin ECIES Encryption.
    k = random.randint(2, E.N-1)
    R = E.multPoint(k, E.A)
    Z = E.multPoint(k, B)

    RZ = str(R)+str(Z)
    H1 = SHA512.new()
    H1.update(RZ)
    k1 = H1.hexdigest()[0:32]
    k2 = H1.hexdigest()[32:128]

    cipher = AES.new(k1)
    enc = base64.b64encode(cipher.encrypt(msg))

    H2 = RIPEMD.new()
    H2.update(enc+k2)
    t = base64.b64encode(H2.digest())

    # ---------------------------------------------------------------
    # Create a binary string from the given encrypted msg information
    # ---------------------------------------------------------------
    #
    # Create a binary string with encrypted msg info separated by 2's.
    # End the string with consecutive 2's.
    #
    # The information is encoded in the following order:
    #
    # 1. Initial check string.
    # 2. Length of curve name.
    # 3. Length of the encrypted message.
    # 4. x-coordinate of ellipitc curve point R.
    # 5. y-coordinate of ellipitc curve point R.
    # 6. t, the authentication hash value
    # 7. Curve name.
    # 8. Encrypted message.
    # ---------------------------------------------------------------

    # Convert each character in t, curve_name, and enc to binary with 2's separating each character.
    t_bin = '2'.join([bin(ord(ch)).lstrip('0b') for ch in t])
    curve_name_bin = '2'.join([bin(ord(ch)).lstrip('0b') for ch in curve_name])
    enc_bin = '2'.join([bin(ord(ch)).lstrip('0b') for ch in enc])

    # Initialize our string as "110011" so we have a quick check that our file is valid when decoding.
    bit_string = "1100112"

    # Now append on the binary public key information with a "2" separating each entry.
    bit_string += bin(len(curve_name)).lstrip('0b') + '2'
    bit_string += bin(len(enc)).lstrip('0b') + '2'
    bit_string += bin(R[0]).lstrip('0b') + '2'
    bit_string += bin(R[1]).lstrip('0b') + '2'
    bit_string += t_bin + '2'
    bit_string += curve_name_bin + '2'
    bit_string += enc_bin + '22'

    return EncodeImageInfo(bit_string, im)