Beispiel #1
0
def main():
	message = 'This is my benchmarking message; it should really be longer'
	e1 = time.time()
	#Time key generation: EC
	eck1 = ec.generate_private_key(ec.SECP384R1(), default_backend())
	eck2 = ec.generate_private_key(ec.SECP384R1(), default_backend())
	e2 = time.time()
	#Time key generation: RSA
	rsak = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend())
	e3 = time.time()
	#Time Encryption: EC
	ecct = transport_security.construct_message(message, srcprivkey=eck1, destpubkey=eck2.public_key())
	e4 = time.time()
	#Time Encryption: RSA
	rsact = transport_security.get_raw_encrypted(message, pubkey=rsak.public_key())
	e5 = time.time()
	#Time Decryption: EC
	ecpt = transport_security.deconstruct_message(message_dict=ecct, destprivkey=eck2, srcpubkey=eck1.public_key())
	e6 = time.time()
	if ecpt == message:
		print("EC Decryption successful")
	else:
		print("EC Decryption failed")
	#Time Decryption: RSA
	rsapt = transport_security.get_raw_decrypted(ciphertext=rsact, privkey=rsak)
	e7 = time.time()
	if ecpt == message:
		print("RSA Decryption successful")
	else:
		print("RSA Decryption failed")

	with open('timing.out', 'a') as f:
		record = "{}\t{}\t{}\t{}\t{}\t{}\n".format(e2-e1, e3-e2, e4-e3, e5-e4, e6-e5, e7-e6)
		f.write(record)
Beispiel #2
0
    def login(self, password, context):
        """
		Do login, using either saved user info or provided ones
		"""
        self._logger.info("Trying to login")
        self._bindkey = None  # Reset our bind key
        # Do the login request to the auth server
        # XXX: Change to https if server is using TLS
        url = "http://{}:{}/auth/login/{}".format(self._authaddr, self._authport, self._userid)
        self._logger.info("Login via: %s", url)
        # Build payload
        nonce = self._generate_nonce()  # Generate a random nonce
        # Convert Context dict to URLSafe Base64
        context = base64.urlsafe_b64encode(bytes(json.dumps(context), "utf-8"))
        self._login_context = context  # This is our login context for this session
        # Build the payload
        payload = json.dumps({"nonce": nonce, "password": password, "context": context.decode("utf-8")})
        # Apply transport_security
        enc_payload = transport_security.construct_message(
            plaintext=payload, srcprivkey=self._privatekey, destpubkey=self._authpubkey
        )
        self._logger.info("Sending payload to authentication server")
        # Do the request
        try:
            resp = requests.put(url=url, json=enc_payload)
        except requests.exceptions.ConnectionError:
            self._logger.error("Could not connect to authentication server")
            return False
        except requests.exceptions.Timeout:
            self._logger.error("Authentication server connection timed out")
            return False
            # Check the response code
        if resp.status_code != 200:
            self._logger.error("Server response status is negative: %s", resp.status_code)
            return False
        self._logger.info("Server response is positive")
        # Decrypt the secure message
        enc_resp = transport_security.deconstruct_message(
            resp.json(), destprivkey=self._privatekey, srcpubkey=self._authpubkey
        )
        # Load into a dict
        stuff = json.loads(enc_resp)
        if not all(k in stuff for k in ["session", "authenticated", "validity", "token"]):
            self._logger.error("Server response is mangled")
            return False
            # Unpack the bindkey
        self._bindkey = self._unpack_bindkey(nonce=nonce, token=stuff["token"])
        if not self._bindkey:
            self._logger.error("Could not unpack bindkey")
            return False
            # Calculate the validity and expiry time of session
        self._logger.error("Unpacked bindkey; Validity=%s", stuff["validity"])
        self._bindkey_expires = time.time() + stuff["validity"]
        # Session confirmed, store the session data
        self._current_session = stuff["session"]
        self._access_keys = {}
        self._logger.info("Session info: %s", self._current_session)
        self._logger.info("User successfully logged in")
        return True
Beispiel #3
0
def retrieve_keys(db, attribute):
	"""
	Retrieve keys from the KS; This involves querying the KS with an authentication token
	Then decrypting and returning the encrypted payload

	db -- Databse whose keys to retrieve
	attribute -- The attribute whose encryption key to retrieve
	"""
	# Load the HOTP secret and counter from the secret file of the Key Server
	with open(ks_secretfile, 'r') as f:
		ksdict = json.loads(f.read())
		counter = ksdict['Counter']
		tfapass = ksdict['2FAKey']
	# Calculate the HOTP token value
	hotp = HOTP(bytes(tfapass, 'utf-8'), 6, hashes.SHA1(), backend=default_backend())
	tfaval = hotp.generate(counter).decode('utf-8')
	# Do the request to the key server
	#XXX: Chnage to https for deployment
	url = "http://{}:{}/key/{}/{}?token={}".format(ks_address, ks_port, db, attribute, tfaval)
	logger.info("Trying to access key from KS: %s", url)
	# Do the request
	try:
		resp = requests.get(url)
	except requests.exceptions.Timeout:
		logger.warning("KS request timeout")
		return None
	except requests.exceptions.ConnectionError:
		logger.warning("KS connection refused")
		return None
	logger.info("KS response code: %s", resp.status_code)
	if resp.status_code == 200:	# Got 200 means KS incremented the counter
		counter += 1	# Increment our own counter
		# Save the updated secret
		ksdict['Counter'] = counter
		with open(ks_secretfile, 'w') as f:
			f.write(json.dumps(ksdict))
		logger.info("KS HOTP counter was incremented to %s", counter)
		# Get the transport secure message
		secured_message = resp.json()
		key = transport_security.deconstruct_message(secured_message, destprivkey=app_privatekey, srcpubkey=ks_publickey)
		# Check if decryption was successful
		if not key:
			logger.warning("Secured message from KS was not decrypted properly")
			return None
		return key
	else:
		# KS did not return the key
		logger.warning("KS replied negatively. Something is wrong.")
		return None
Beispiel #4
0
    def request_access(self, db, attribute, newcontext=None):
        """
		Request keys
		"""
        self._logger.info("Trying to retrieve keys for %s/%s", db, attribute)
        # If the user wants to reset their context, do that else use the login context
        if not newcontext:
            newcontext = self._login_context
        newcontext = base64.urlsafe_b64encode(bytes(json.dumps(newcontext), "utf-8"))
        # Do the request
        # XXX: Change to https if server is using TLS
        url = "http://{}:{}/ags/access/{}/{}?id={}&context={}".format(
            self._agsaddr, self._agsport, db, attribute, self._current_session["id"], newcontext.decode("utf-8")
        )
        self._logger.info("Access via: %s", url)
        try:
            resp = requests.get(url=url)
        except requests.exceptions.ConnectionError:
            self._logger.error("Could not connect to grant server")
            return False
        except requests.exceptions.Timeout:
            self._logger.error("Grant server connection timed out")
            return False
        if resp.status_code != 200:
            self._logger.error("Grant server responded negatively")
            return False
        payload = resp.json()
        # Get rid of transport security
        actual_payload = transport_security.deconstruct_message(
            payload, destprivkey=self._privatekey, srcpubkey=self._agspubkey
        )
        # Get rid of binding encryption
        fern = Fernet(self._bindkey)
        try:
            decrypted_payload = fern.decrypt(bytes(actual_payload, "utf-8"))
        except:
            self._logger.error("Could not decrypt binding encryption")
            return False
            # Load into dict, must contain key and validity
        payload = json.loads(decrypted_payload.decode("utf-8"))
        if not all(k in payload for k in ["key", "validity"]):
            self._logger.error("Grant server respnse is mangled")
            return False
        self._logger.info("Successfully retrieved key")
        # Add the key to our local storage
        self._add_key(db, attribute, payload["key"], payload["validity"])
        self._logger.info("Keys added")
        return True
Beispiel #5
0
def add_authorization():
	"""
	/ags/authorized From AS, Users Session got authorized
	"""
	logger.info("Adding authorization")
	# First we need to do token validation
	try:
		tfaval = flask.request.args.get('token')
		if not tfaval:
			raise KeyError
	except KeyError:
		logger.warning("No authorization token in URL")
		flask.abort(401)
	if not check_hotp_value(tfaval):
		logger.warning("HOTP token not authenticated")
		flask.abort(401)
	# Token validation successful, now we need to get the message
	logger.info("Token authenticated")
	secure_payload = flask.request.get_json()
	payload = transport_security.deconstruct_message(secure_payload, destprivkey=app_privatekey, srcpubkey=auth_publickey)
	if not payload:
		logger.warning("Payload could not be decrypted")
		flask.abort(400)
	payload = json.loads(payload)
	# A valid payload must contain all the following
	if not all(k in payload for k in ['sessionid', 'role', 'bindkey', 'pubkey']):
		logger.warning("Payload is incomplete")
		flask.abort(422)
	# Store the AIC contents in the In-memory database
	if not store_aic(payload['sessionid'], payload['pubkey'], payload['role'], payload['bindkey']):
		logger.warning("Public key format error; Could not store AIC")
		flask.abort(422)
	# The session info needs to be sent to the ACS
	# This part is only needed when the ACS is present
	#if not send_secret_to_acs(payload['sessionid']):
	#	logger.warning("ACS did not accept user secret")
	#	flask.abort(422)
	# Send back the validity
	resp = {"stored": True, "validity":aic_lifetime}
	logger.info("Sending back response: %s", resp)
	return flask.jsonify(**resp)
Beispiel #6
0
def context_check(sessionid):
	"""
	Verify the context of the session

	sessionid -- The session whose context is being checked
	"""
	logger.info("Context validation for %s", sessionid)
	# Get secure payload, decrypt it
	secure_payload = flask.request.get_json()
	payload = transport_security.deconstruct_message(secure_payload, srcpubkey=ags_publickey, destprivkey=app_privatekey)
	if not payload:
		logger.warning("Could not decrypt transport secure payload")
		flask.abort(403)
	# Load the JSON string into a dict
	payload = json.loads(payload)
	# Payload must contain all context and extension period
	if not all(k in payload for k in ['context', 'extend_by']):
		logger.warning("Incomplete payload")
		flask.abort(401)
	new_context = payload['context']	# Context suplied by user
	extend = payload['extend_by']	# Extrension specified by AGS
	# Check if session exists
	if not red.exists("session:"+sessionid):
		logger.warning("Context check for non-existant session")
		flask.abort(403)
	# Get old context and UserID, created during login
	old_context = red.hget("session:"+sessionid, key='context').decode('utf-8')
	userid = red.hget("session:"+sessionid, key='user').decode('utf-8')
	# Validate the users context, calling the context validation module
	valid = context_validator.validate(userid, old=old_context, new=new_context)
	if not valid:
		logger.warning("Context change validation failed")
		red.delete("session:"+sessionid)
		red.delete("user:"******"session:"+sessionid, extend)
	red.expire("user:"******"valid":True})
Beispiel #7
0
def main():
	args = options()

	if args.command == 'encrypt':
		print("Encryption invoked, treating source key as private, destination key as public")
		with open(args.src, 'r') as f:
			pkbytes = bytes(f.read(), 'utf-8')
			if args.password:
				passbytes = bytes(args.password, 'utf-8')
			else:
				passbytes = None
			srcprivkey = load_pem_private_key(pkbytes, password=passbytes, backend=default_backend())
			print("Loaded source private key from ", args.src)
		with open(args.dest, 'r') as f:
			pkbytes = bytes(f.read(), 'utf-8')
			destpubkey = load_pem_public_key(pkbytes, backend=default_backend())
			print("Loaded destination public key from ", args.dest)
		with open(args.input, 'r') as f:
			plaintext = f.read()
			print("Loaded plaintext from ", args.input)
		ciphertext = transport_security.construct_message(plaintext, srcprivkey, destpubkey)
		print("Done with encryption")
		outfile = args.input + '.tsecure'
		if args.output:
			outfile = args.output
		print("Outputting to ", outfile)
		with open(outfile, 'w') as f:
			f.write(json.dumps(ciphertext))
		print("Output complete")
		sys.exit(0)
	elif args.command == 'decrypt':
		print("Decryption invoked, treating source key as public, destination key as private")
		with open(args.dest, 'r') as f:
			pkbytes = bytes(f.read(), 'utf-8')
			if args.password:
				passbytes = bytes(args.password, 'utf-8')
			else:
				passbytes = None
			destprivkey = load_pem_private_key(pkbytes, password=passbytes, backend=default_backend())
			print("Loaded destination private key from ", args.dest)
		with open(args.src, 'r') as f:
			pkbytes = bytes(f.read(), 'utf-8')
			srcpubkey = load_pem_public_key(pkbytes, backend=default_backend())
			print("Loaded source public key from ", args.src)
		with open(args.input, 'r') as f:
			plaintext = f.read()
			print("Loaded ciphertext from ", args.input)
		ciphertext = transport_security.deconstruct_message(json.loads(plaintext), destprivkey, srcpubkey)
		if not ciphertext:
			print("Decryption failed", file=sys.stderr)
			sys.exit(1)
		print("Done with decryption")
		outfile = args.input + '.plain'
		if args.output:
			outfile = args.output
		print("Outputting to ", outfile)
		with open(outfile, 'w') as f:
			f.write(ciphertext)
		print("Output complete")
		sys.exit(0)
	else:
		print("We should never have come here")
		sys.exit(1)
Beispiel #8
0
def login_request(userid):
	"""
	/auth/login/<userid> Login a user

	userid -- The ID suplied by the user
	"""
	logger.info("%s trying to log in", userid)
	enc_payload = flask.request.get_json()
	# Retrieve the users info from the database
	user_info = get_userinfo_auth(userid=userid)
	if not user_info:
		logger.warning("User info not found")
		flask.abort(random_http_error())
	logger.info("User info retrieved")
	# Check if already logged in
	if not bench and red.exists("user:"******"User trying to login while a session already exists")
		flask.abort(random_http_error())
	# Decrypt login payload
	userpubkey = build_pubkey(user_info['pubkey'])
	payload = transport_security.deconstruct_message(enc_payload, srcpubkey=userpubkey, destprivkey=app_privatekey)
	if not payload:
		logger.warning("Could not decrypt transport secure message")
		flask.abort(random_http_error())
	logger.info("Payload decrypted")
	# Turn JSON string to dict object
	payload = json.loads(payload)
	# Payload must contain all the below
	if not all(k in payload for k in ['nonce', 'password', 'context']):
		logger.warning("Incomplete payload")
		flask.abort(random_http_error())
	# Users password is authenticated
	if not autenticate_user(password=payload['password'], pwhash=user_info['pwhash']):
		logger.warning("Wrong password from user")
		flask.abort(random_http_error())
	logger.info("User %s successfully authenticated", userid)
	bindkey = generate_bindkey()
	# Generate unique session ID + key for this login session
	sessionid = generate_sessionid()
	sessionkey = generate_sessionkey()
	# If either could not be generated, we have run out of IDs/Keys
	if not sessionid or not sessionkey:
		logger.warning("Could not generate new session ID")
		flask.abort(random_http_error())
	logger.info("Session ID generated for user %s", userid)
	# Send AIC, AGS returns the validity period of the stored AIC
	validity = send_aic(sessionid, role=user_info['role'], bindkey=bindkey, pubkey=user_info['pubkey'])
	logger.info("Generated AIC and Bindkey for user %s", userid)
	if not validity:
		logger.warning("AIC could not be sent to AGS")
		flask.abort(random_http_error())
	logger.info("Sent AIC for %s to AGS", userid)
	# Add session to session list
	x = red.hmset("session:"+sessionid, {"user":userid, "key":sessionkey, "context":payload['context']})
	if not x:
		logger.warning("Could not add session data to redis")
		flask.abort(500)
	# Expires after validity period
	red.expire("session:"+sessionid, validity)
	# Add user of list of users, who are logged in
	x = red.set("user:"******"Could not add session data to redis")
		flask.abort(500)
	logger.info("Set user %s to session %s", userid, sessionid)
	# Expires after validity period
	red.expire("user:"******"Users nonce is bad")
		flask.abort(random_http_error())
	# Send response, contains session info, token, validity
	logger.info("Token generated for user %s", userid)
	resp = {"authenticated":True, "session":{"id":sessionid, "key":sessionkey}, "token":token, "validity":validity}
	respstr = json.dumps(resp)
	# Transport security
	enc_resp = transport_security.construct_message(respstr, srcprivkey=app_privatekey, destpubkey=userpubkey)
	return flask.jsonify(**enc_resp)