encrypted_queries_tools.py
1 from __future__ import absolute_import 2 import os 3 import argparse 4 import sys 5 from cryptography.hazmat.primitives import hashes 6 from cryptography.hazmat.primitives.kdf import x963kdf 7 from cryptography.hazmat.primitives.asymmetric import ec 8 from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes 9 from cryptography.hazmat.backends import default_backend 10 import base64 11 import base58 12 13 backend = default_backend() 14 15 def hex_to_key(pub_key_hex): 16 pub_key_hex = pub_key_hex.strip() 17 pub_key_point = pub_key_hex.decode('hex') 18 public_numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(ec.SECP256K1(), pub_key_point) 19 public_key = public_numbers.public_key(backend) 20 return public_key 21 22 def hex_to_priv_key(priv_key_hex, public_key_hex): 23 priv_key_value = long(priv_key_hex, 16) 24 public_key = hex_to_key(public_key_hex) 25 public_numbers = public_key.public_numbers() 26 private_numbers = ec.EllipticCurvePrivateNumbers(priv_key_value, public_numbers) 27 priv_key = private_numbers.private_key(backend) 28 return priv_key 29 30 # Hybrid Encryption Scheme: 31 # - We perform a Elliptic Curves Diffie-Hellman Key Exchange using: 32 # - SECP256K1 as curve for key generation 33 # - ANSI X9.63 KDF as Key Derivation Function to derive the shared secret 34 # - The symmetric cipher is an AES256.MODE_GCM with authentication tag 16-byte 35 # of length. Since the key is used only once, we can pick the known nonce/iv 36 # '000000000000' (96 bits of length). We return concatenation of the encoded 37 # point, the tag and the ciphertext 38 39 def encrypt(message, receiver_public_key): 40 sender_private_key = ec.generate_private_key(ec.SECP256K1(), backend) 41 shared_key = sender_private_key.exchange(ec.ECDH(), receiver_public_key) 42 sender_public_key = sender_private_key.public_key() 43 point = sender_public_key.public_numbers().encode_point() 44 iv = '000000000000' 45 xkdf = x963kdf.X963KDF( 46 algorithm = hashes.SHA256(), 47 length = 32, 48 sharedinfo = '', 49 backend = backend 50 ) 51 key = xkdf.derive(shared_key) 52 encryptor = Cipher( 53 algorithms.AES(key), 54 modes.GCM(iv), 55 backend = backend 56 ).encryptor() 57 ciphertext = encryptor.update(message) + encryptor.finalize() 58 return point + encryptor.tag + ciphertext 59 60 61 def decrypt(message, receiver_private_key): 62 point = message[0:65] 63 tag = message[65:81] 64 ciphertext = message[81:] 65 sender_public_numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(ec.SECP256K1(), point) 66 sender_public_key = sender_public_numbers.public_key(backend) 67 shared_key = receiver_private_key.exchange(ec.ECDH(), sender_public_key) 68 iv = '000000000000' 69 xkdf = x963kdf.X963KDF( 70 algorithm = hashes.SHA256(), 71 length = 32, 72 sharedinfo = '', 73 backend = backend 74 ) 75 key = xkdf.derive(shared_key) 76 decryptor = Cipher( 77 algorithms.AES(key), 78 modes.GCM(iv,tag), 79 backend = backend 80 ).decryptor() 81 message = decryptor.update(ciphertext) + decryptor.finalize() 82 return message 83 84 85 def main(): 86 parser = argparse.ArgumentParser(description='Encrypt messages to Oraclize using Elliptic Curve Integrated Encryption Scheme.') 87 parser.add_argument('-e', '--encrypt', dest='mode', action='store_const', const='encrypt', help='Encrypt a string. Requires -p') 88 parser.add_argument('-p', '--with-public-key', dest='public_key', action='store', help='Use the provided hex-encoded public key to encrypt') 89 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.') 90 parser.add_argument('-g', '--generate', dest='mode', action='store_const', const='generate', help='Generates a public and a private key') 91 parser.add_argument('text', nargs='?', action='store', help='String to encrypt, decrypt. If not specified, standard input will be used.') 92 93 args = parser.parse_args() 94 95 if args.mode != 'encrypt' and args.mode != 'decrypt' and args.mode != 'generate': 96 parser.print_help() 97 return 98 99 if args.mode == 'encrypt' and not args.public_key: 100 print "Please, provide a valid public key" 101 return 102 103 if args.mode == 'encrypt': 104 if args.public_key: 105 pub_key = hex_to_key(args.public_key) 106 107 if args.text: 108 print base64.b64encode(encrypt(args.text, pub_key)) 109 return 110 else: 111 print base64.b64encode(encrypt(sys.stdin.read(), pub_key)) 112 return 113 elif args.mode == 'decrypt': 114 if args.text: 115 print "Insert your public key" 116 public_key = sys.stdin.read() 117 print "Insert your private key:" 118 private_key = sys.stdin.read() 119 private_key = hex_to_priv_key(private_key, public_key) 120 text = base64.b64decode(args.text) 121 else: 122 print "Insert your public key" 123 public_key = sys.stdin.read() 124 print "\nInsert your private key:" 125 private_key = sys.stdin.read() 126 private_key = hex_to_priv_key(private_key, public_key) 127 print "\nInsert encrypted text" 128 text = base64.b64decode(sys.stdin.read()) 129 130 print decrypt(text, private_key) 131 132 if args.mode == 'generate': 133 receiver_private_key = ec.generate_private_key(ec.SECP256K1(), backend) 134 receiver_public_key = receiver_private_key.public_key() 135 number = receiver_private_key.private_numbers() 136 print "Public Key:", receiver_public_key.public_numbers().encode_point().encode('hex') 137 print "Private Key:", hex(number.private_value) 138 139 140 141 142 if __name__ == "__main__": 143 main()