Example #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)
Example #2
0
def send_secret_to_acs(sessionid):
	"""
	Send a freshly generated secret to ACS corresponding to the new AIC

	sessionid -- Session ID
	"""
	logger.info("Trying to add new user secret to ACS")
	# Sedn the session data to the ACS
	#XXX: Change to https is servers deployed with TLS
	url = "http://{}:{}/acs/user".format(acs_address, acs_port)
	logger.info("Adding secret via %s", url)
	import os
	secret = base64.urlsafe_b64encode(os.urandom(32)).decode('utf-8')
	payload = json.dumps({"id":sessionid, "twofactor":{"2FAKey":secret, "Counter":0}})
	epayload = transport_security.construct_message(payload, srcprivkey=app_privatekey, destpubkey=acs_publickey)
	try:
		resp = requests.put(url, json=epayload)
	except requests.exceptions.Timeout:
		logger.warning("ACS request timeout")
		return False
	except requests.exceptions.ConnectionError:
		logger.warning("ACS connection refused")
		return False
	logger.info("ACS response code: %s", resp.status_code)
	if resp.status_code != 200:
		logger.warning("ACS rejected secret addition")
		return False
	return True
Example #3
0
def validate_context(sessionid, context, extend_by):
	"""
	Contact auth and validate the users context

	sessionid -- ID of the session whose context is being validated
	context -- Context data in urlsafe_b64 format
	"""
	logger.info("Validating context via Auth for session: %s", sessionid)
	# Do a context validation call to the authentication server
	#XXX: Change to https when deployed with TLS
	url = "http://{}:{}/auth/{}/context".format(auth_address, auth_port, sessionid)
	# The payload contains the context data, and the time to extend the session by if the context is good
	payload = json.dumps({'context':context, 'extend_by':extend_by})
	# Transport security
	secure_payload = transport_security.construct_message(payload, srcprivkey=app_privatekey, destpubkey=auth_publickey)
	try:
		# Do the request
		resp = requests.put(url, json=secure_payload)
	except requests.exceptions.Timeout:
		logger.warning("Auth request timeout")
		return False
	except requests.exceptions.ConnectionError:
		logger.warning("Auth connection refused")
		return False
	logger.info("Auth response code: %s", resp.status_code)
	# A 200 OK response means the context was validated successfully
	if resp.status_code != 200:
		logger.warning("Session %s context validation failed", sessionid)
		return False
	logger.info("Session %s context validation successful", sessionid)
	return True
Example #4
0
def get_key(db, attribute):
	"""
	/key/<db>/<attribute> Get the key
	"""
	logger.info("Keys requested for %s/%s", db, attribute)
	# Each request must be verified by supplying a token
	try:
		token = flask.request.args.get('token')
	except KeyError:
		logger.warning("No token in request")
		flask.abort(401)
	logger.info("Authenticating token: %s", token)
	# Verify the HOPT token
	if not check_hotp_value(token):
		logger.warning("HOTP value is wrong")
		flask.abort(401)
	logger.info("Token %s authenticated", token)
	# Get the key
	key = retrieve_key(db, attribute)
	if not key:
		logger.warning("No key found for this combination")
		flask.abort(403)
	logger.info("Key for %s/%s retrieved", db, attribute)
	# Send the raw key, using transport_security
	resp = transport_security.construct_message(key, srcprivkey=app_privatekey, destpubkey=ags_publickey)
	return flask.jsonify(**resp)
Example #5
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
Example #6
0
def serve_keys(db, attribute):
	"""
	/ags/access/<db>/<attribute>?id=<sessionid>&context=<contextdata> From user, give them the keys
	"""
	logger.info("GETting keys for %s/%s", db, attribute)
	# Check if request contains ID and context data
	try:
		sessionid = flask.request.args.get('id')
		contextdata = flask.request.args.get('context')
		if not sessionid or not contextdata:
			raise KeyError
	except KeyError:
		logger.warning("No id/context in URL")
		flask.abort(random_http_error())
	# Context was a base64 encoded JSON string, turn it into a dictionary
	print(contextdata)
	newcontext = json.loads(base64.urlsafe_b64decode(contextdata).decode('utf-8'))
	# Check if session exists
	if not red.exists("session:"+sessionid):
		logger.warning("User not authorized by AS")
		flask.abort(random_http_error())
	# Check policy before handing out keys
	role = red.hget("session:"+sessionid, "role").decode('utf-8')
	r, w = retrieve_policy(role, db, attribute)
	if not (r or w):
		logger.warning("User can't read or write %s/%s, not sending him keys", db, attribute)
		flask.abort(random_http_error())
	# Context validation
	valid = validate_context(sessionid, context=newcontext, extend_by=key_lifetime)
	if not valid:
		# Context change is not valid, user needs to be logged out
		logger.warning("User context was not valid")
		if red.delete("session:"+sessionid):
			logger.warning("User logged out at AGS")
		else:
			logger.warning("Logout at AGS failed")
		flask.abort(random_http_error())
	logger.info("User context is valid")
	# Key to send, retrieved from Key Server
	key = retrieve_keys(db, attribute)
	inner_payload = json.dumps({"key": key, "validity": key_lifetime})	#inner_payload = plaintext json
	# Inner layer of encryption using bindkey
	bindkey = red.hget('session:'+sessionid, "bindkey")
	fern = Fernet(bindkey)
	inner_payload = fern.encrypt(bytes(inner_payload, 'utf-8')).decode('utf-8')
	# Outer layer of encryption from transport_security
	# Load users public key from the In-memory database
	userpubkeystr = red.hget("session:"+sessionid, "pubkey")
	userpubkey = load_pem_public_key(userpubkeystr, backend=default_backend())
	# Secure using transport_security
	outer_payload = transport_security.construct_message(inner_payload, srcprivkey=app_privatekey, destpubkey=userpubkey)
	extend_aic_on_lease(sessionid)		# Extend authorization period by key lifetime
	logger.info("Key distributed to %s for %s/%s", sessionid, db, attribute)
	return flask.jsonify(**outer_payload)
Example #7
0
def send_aic(sessionid, role, bindkey, pubkey):
	"""
	Send an AIC to the ags, returns success value

	sessionid -- Anonymized Session ID for user
	role -- Role as retrieved from database
	bindkey -- As generated during login
	pubkey -- Users stored public key
	context -- Users login context
	"""
	# AIC construct
	aic = {"sessionid":sessionid, "role":role, "bindkey":bindkey, "pubkey":pubkey}
	message = json.dumps(aic)
	logger.info("Genrated AIC: %s", message)
	# Secure the payload
	payload = transport_security.construct_message(message, srcprivkey=app_privatekey, destpubkey=ags_publickey)
	# Calculate the current HOTP token from file
	with open(ags_secretfile, 'r') as f:
		agsdict = json.loads(f.read())
		counter = agsdict['Counter']
		tfapass = agsdict['2FAKey']
	hotp = HOTP(bytes(tfapass, 'utf-8'), 6, hashes.SHA1(), backend=default_backend())
	tfaval = hotp.generate(counter).decode('utf-8')
	# Do the reques to the AGS
	#XXX: Change to https for deployment
	url = "http://{}:{}/ags/authorized?token={}".format(ags_address, ags_port, tfaval)
	logger.info("Adding AIC to AGS: %s", url)
	try:
		resp = requests.put(url, json=payload)
	except requests.Timeout:
		logger.warning("AGS connection timeout")
		return None
	except requests.ConnectionError:
		logger.warning("AGS connection error")
		return None
	logger.info("AGS AIC PUT status code: %s", resp.status_code)
	# A 200 OK response means the request was successful
	if resp.status_code == 200:
		# Update the HOTP counter value
		counter += 1
		agsdict['Counter'] = counter
		with open(ags_secretfile, 'w') as f:
			f.write(json.dumps(agsdict))
		logger.info("AGS HOTP counter was incremented to %s", counter)
		# Return the validity as returned by the AGS
		return resp.json()['validity']
	else:
		logger.warning("AGS rejected AIC")
		return None
Example #8
0
def main():
	message = sys.argv[1]
	#print("Message={}".format(message))
	print("Message length is: {}".format(len(message)))
	eck1 = ec.generate_private_key(ec.SECP384R1(), default_backend())
	eck2 = ec.generate_private_key(ec.SECP384R1(), default_backend())

	tsct = transport_security.construct_message(plaintext=message, srcprivkey=eck1, destpubkey=eck2.public_key())
	#print("TS={}".format(tsct))
	print("Transport Security: {}".format(len(json.dumps(tsct))))
	tsoh = (len(json.dumps(tsct))/len(message))*100

	k = Fernet.generate_key()
	f = Fernet(k)
	fct = f.encrypt(bytes(message, 'utf-8')).decode('utf-8')
	#print("Fernet={}".format(fct))
	print("Fernet: {}".format(len(fct)))
	foh = (len(fct)/len(message))*100

	with open('bandwidth.out', 'a') as f:
		record = "{}\t{}\t{}\n".format(len(message), tsoh, foh)
		f.write(record)
Example #9
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)
Example #10
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)