def db_gen_user_keys(session, tid, user, password): """ Transaction generating and saving user keys :param session: An ORM session :param tid: A tenant ID :param user: A user object :param password: A user's password :return: A private key generated for the user """ enc_key = GCE.derive_key(password.encode(), user.salt) crypto_prv_key, user.crypto_pub_key = GCE.generate_keypair() user.crypto_bkp_key, user.crypto_rec_key = GCE.generate_recovery_key( crypto_prv_key) user.crypto_prv_key = Base64Encoder.encode( GCE.symmetric_encrypt(enc_key, crypto_prv_key)) # Create an escrow backup for the root tenant tid_1_escrow = config.ConfigFactory(session, 1).get_val('crypto_escrow_pub_key') if tid_1_escrow: user.crypto_escrow_bkp1_key = Base64Encoder.encode( GCE.asymmetric_encrypt(tid_1_escrow, crypto_prv_key)) # Create an escrow backup for the actual tenant tid_n_escrow = config.ConfigFactory(session, tid).get_val('crypto_escrow_pub_key') if tid_n_escrow: user.crypto_escrow_bkp2_key = Base64Encoder.encode( GCE.asymmetric_encrypt(tid_n_escrow, crypto_prv_key)) return crypto_prv_key
def set_user_password(tid, user, password, cc): # Regenerate the password hash only if different from the best choice on the platform if user.hash_alg != 'ARGON2': user.hash_alg = 'ARGON2' user.salt = GCE.generate_salt() password_hash = GCE.hash_password(password, user.salt) # Check that the new password is different form the current password if user.password == password_hash: raise errors.PasswordReuseError user.password = password_hash user.password_change_date = datetime_now() if not State.tenant_cache[tid].encryption and cc == '': return None enc_key = GCE.derive_key(password.encode(), user.salt) if not cc: # The first password change triggers the generation # of the user encryption private key and its backup cc, user.crypto_pub_key = GCE.generate_keypair() user.crypto_bkp_key, user.crypto_rec_key = GCE.generate_recovery_key(cc) user.crypto_prv_key = Base64Encoder.encode(GCE.symmetric_encrypt(enc_key, cc)) if State.tenant_cache[1].crypto_escrow_pub_key: user.crypto_escrow_bkp1_key = Base64Encoder.encode(GCE.asymmetric_encrypt(State.tenant_cache[1].crypto_escrow_pub_key, cc)) if State.tenant_cache[tid].crypto_escrow_pub_key: user.crypto_escrow_bkp2_key = Base64Encoder.encode(GCE.asymmetric_encrypt(State.tenant_cache[tid].crypto_escrow_pub_key, cc)) return cc
def test_recovery_key(self): prv_key, _ = GCE.generate_keypair() bck_key, rec_key = GCE.generate_recovery_key(prv_key) plain_rec_key = GCE.asymmetric_decrypt(prv_key, Base64Encoder.decode(rec_key)) x = GCE.symmetric_decrypt(plain_rec_key, Base64Encoder.decode(bck_key)) self.assertEqual(x, prv_key)
################################################################################ # BEGIN MOCKS NECESSARY FOR DETERMINISTIC ENCRYPTION VALID_PASSWORD1 = 'ACollectionOfDiplomaticHistorySince_1966_ToThe_Pr esentDay#' VALID_PASSWORD2 = VALID_PASSWORD1 VALID_SALT1 = GCE.generate_salt() VALID_SALT2 = GCE.generate_salt() VALID_HASH1 = GCE.hash_password(VALID_PASSWORD1, VALID_SALT1) VALID_HASH2 = GCE.hash_password(VALID_PASSWORD2, VALID_SALT2) VALID_BASE64_IMG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=' INVALID_PASSWORD = '******' KEY = GCE.generate_key() USER_KEY = GCE.derive_key(VALID_PASSWORD1, VALID_SALT1) USER_PRV_KEY, USER_PUB_KEY = GCE.generate_keypair() USER_PRV_KEY_ENC = Base64Encoder.encode(GCE.symmetric_encrypt(USER_KEY, USER_PRV_KEY)) USER_BKP_KEY, USER_REC_KEY = GCE.generate_recovery_key(USER_PRV_KEY) USER_REC_KEY_PLAIN = GCE.asymmetric_decrypt(USER_PRV_KEY, Base64Encoder.decode(USER_REC_KEY)) USER_REC_KEY_PLAIN = Base32Encoder.encode(USER_REC_KEY_PLAIN).replace(b'=', b'').decode('utf-8') GCE_orig_generate_key = GCE.generate_key GCE_orig_generate_keypair = GCE.generate_keypair def GCE_mock_generate_key(): return KEY def GCE_mock_generate_keypair(): return USER_PRV_KEY, USER_PUB_KEY setattr(GCE, 'generate_key', GCE_mock_generate_key)
def db_user_update_user(session, tid, user_session, request): """ Updates the specified user. This version of the function is specific for users that with comparison with admins can change only few things: - real name - email address - preferred language - the password (with old password check) - pgp key raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist. """ from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node user = models.db_get(session, models.User, models.User.id == user_session.user_id) user.language = request.get('language', State.tenant_cache[tid].default_language) user.name = request['name'] new_password = request['password'] old_password = request['old_password'] if new_password: if user.password_change_needed: user.password_change_needed = False else: if not GCE.check_password(user.hash_alg, old_password, user.salt, user.password): raise errors.InvalidOldPassword # Regenerate the password hash only if different from the best choice on the platform if user.hash_alg != GCE.HASH: user.hash_alg = GCE.HASH user.salt = GCE.generate_salt() password_hash = GCE.hash_password(new_password, user.salt) # Check that the new password is different form the current password if user.password == password_hash: raise errors.PasswordReuseError user.password = password_hash user.password_change_date = datetime_now() if State.tenant_cache[tid].encryption: enc_key = GCE.derive_key(request['password'].encode(), user.salt) if not user_session.cc: # Th First first password change triggers the generation # of the user encryption private key and its backup user_session.cc, user.crypto_pub_key = GCE.generate_keypair() user.crypto_bkp_key, user.crypto_rec_key = GCE.generate_recovery_key( user_session.cc) # If the user had already enabled two factor before encryption was not enable # encrypt the two factor secret if user.two_factor_secret: user.two_factor_secret = GCE.asymmetric_encrypt( user.crypto_pub_key, user.two_factor_secret) user.crypto_prv_key = GCE.symmetric_encrypt( enc_key, user_session.cc) # If the email address changed, send a validation email if request['mail_address'] != user.mail_address: user.change_email_address = request['mail_address'] user.change_email_date = datetime_now() user.change_email_token = generateRandomKey(32) user_desc = user_serialize_user(session, user, user.language) user_desc['mail_address'] = request['mail_address'] template_vars = { 'type': 'email_validation', 'user': user_desc, 'new_email_address': request['mail_address'], 'validation_token': user.change_email_token, 'node': db_admin_serialize_node(session, tid, user.language), 'notification': db_get_notification(session, tid, user.language) } State.format_and_send_mail(session, tid, user_desc, template_vars) # If the platform allows users to change PGP keys, process it if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True: parse_pgp_options(user, request) return user