/ tools / encrypted_queries_tools.py
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()