mirror of
https://github.com/status-im/github-oracle.git
synced 2026-08-27 18:01:09 +00:00
144 lines
5.8 KiB
Python
144 lines
5.8 KiB
Python
from __future__ import absolute_import
|
|
import os
|
|
import argparse
|
|
import sys
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.kdf import x963kdf
|
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes
|
|
from cryptography.hazmat.backends import default_backend
|
|
import base64
|
|
import base58
|
|
|
|
backend = default_backend()
|
|
|
|
def hex_to_key(pub_key_hex):
|
|
pub_key_hex = pub_key_hex.strip()
|
|
pub_key_point = pub_key_hex.decode('hex')
|
|
public_numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(ec.SECP256K1(), pub_key_point)
|
|
public_key = public_numbers.public_key(backend)
|
|
return public_key
|
|
|
|
def hex_to_priv_key(priv_key_hex, public_key_hex):
|
|
priv_key_value = long(priv_key_hex, 16)
|
|
public_key = hex_to_key(public_key_hex)
|
|
public_numbers = public_key.public_numbers()
|
|
private_numbers = ec.EllipticCurvePrivateNumbers(priv_key_value, public_numbers)
|
|
priv_key = private_numbers.private_key(backend)
|
|
return priv_key
|
|
|
|
# Hybrid Encryption Scheme:
|
|
# - We perform a Elliptic Curves Diffie-Hellman Key Exchange using:
|
|
# - SECP256K1 as curve for key generation
|
|
# - ANSI X9.63 KDF as Key Derivation Function to derive the shared secret
|
|
# - The symmetric cipher is an AES256.MODE_GCM with authentication tag 16-byte
|
|
# of length. Since the key is used only once, we can pick the known nonce/iv
|
|
# '000000000000' (96 bits of length). We return concatenation of the encoded
|
|
# point, the tag and the ciphertext
|
|
|
|
def encrypt(message, receiver_public_key):
|
|
sender_private_key = ec.generate_private_key(ec.SECP256K1(), backend)
|
|
shared_key = sender_private_key.exchange(ec.ECDH(), receiver_public_key)
|
|
sender_public_key = sender_private_key.public_key()
|
|
point = sender_public_key.public_numbers().encode_point()
|
|
iv = '000000000000'
|
|
xkdf = x963kdf.X963KDF(
|
|
algorithm = hashes.SHA256(),
|
|
length = 32,
|
|
sharedinfo = '',
|
|
backend = backend
|
|
)
|
|
key = xkdf.derive(shared_key)
|
|
encryptor = Cipher(
|
|
algorithms.AES(key),
|
|
modes.GCM(iv),
|
|
backend = backend
|
|
).encryptor()
|
|
ciphertext = encryptor.update(message) + encryptor.finalize()
|
|
return point + encryptor.tag + ciphertext
|
|
|
|
|
|
def decrypt(message, receiver_private_key):
|
|
point = message[0:65]
|
|
tag = message[65:81]
|
|
ciphertext = message[81:]
|
|
sender_public_numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(ec.SECP256K1(), point)
|
|
sender_public_key = sender_public_numbers.public_key(backend)
|
|
shared_key = receiver_private_key.exchange(ec.ECDH(), sender_public_key)
|
|
iv = '000000000000'
|
|
xkdf = x963kdf.X963KDF(
|
|
algorithm = hashes.SHA256(),
|
|
length = 32,
|
|
sharedinfo = '',
|
|
backend = backend
|
|
)
|
|
key = xkdf.derive(shared_key)
|
|
decryptor = Cipher(
|
|
algorithms.AES(key),
|
|
modes.GCM(iv,tag),
|
|
backend = backend
|
|
).decryptor()
|
|
message = decryptor.update(ciphertext) + decryptor.finalize()
|
|
return message
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Encrypt messages to Oraclize using Elliptic Curve Integrated Encryption Scheme.')
|
|
parser.add_argument('-e', '--encrypt', dest='mode', action='store_const', const='encrypt', help='Encrypt a string. Requires -p')
|
|
parser.add_argument('-p', '--with-public-key', dest='public_key', action='store', help='Use the provided hex-encoded public key to encrypt')
|
|
parser.add_argument('-d', '--decrypt', dest='mode', action='store_const', const='decrypt', help='Decrypt a string. Provide private key in Wallet Import Format in standard input, or first line of standard input if encrypted text is also provided on standard input. DO NOT PUT YOUR PRIVATE KEY ON THE COMMAND LINE.')
|
|
parser.add_argument('-g', '--generate', dest='mode', action='store_const', const='generate', help='Generates a public and a private key')
|
|
parser.add_argument('text', nargs='?', action='store', help='String to encrypt, decrypt. If not specified, standard input will be used.')
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.mode != 'encrypt' and args.mode != 'decrypt' and args.mode != 'generate':
|
|
parser.print_help()
|
|
return
|
|
|
|
if args.mode == 'encrypt' and not args.public_key:
|
|
print "Please, provide a valid public key"
|
|
return
|
|
|
|
if args.mode == 'encrypt':
|
|
if args.public_key:
|
|
pub_key = hex_to_key(args.public_key)
|
|
|
|
if args.text:
|
|
print base64.b64encode(encrypt(args.text, pub_key))
|
|
return
|
|
else:
|
|
print base64.b64encode(encrypt(sys.stdin.read(), pub_key))
|
|
return
|
|
elif args.mode == 'decrypt':
|
|
if args.text:
|
|
print "Insert your public key"
|
|
public_key = sys.stdin.read()
|
|
print "Insert your private key:"
|
|
private_key = sys.stdin.read()
|
|
private_key = hex_to_priv_key(private_key, public_key)
|
|
text = base64.b64decode(args.text)
|
|
else:
|
|
print "Insert your public key"
|
|
public_key = sys.stdin.read()
|
|
print "\nInsert your private key:"
|
|
private_key = sys.stdin.read()
|
|
private_key = hex_to_priv_key(private_key, public_key)
|
|
print "\nInsert encrypted text"
|
|
text = base64.b64decode(sys.stdin.read())
|
|
|
|
print decrypt(text, private_key)
|
|
|
|
if args.mode == 'generate':
|
|
receiver_private_key = ec.generate_private_key(ec.SECP256K1(), backend)
|
|
receiver_public_key = receiver_private_key.public_key()
|
|
number = receiver_private_key.private_numbers()
|
|
print "Public Key:", receiver_public_key.public_numbers().encode_point().encode('hex')
|
|
print "Private Key:", hex(number.private_value)
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|