Exemple #1
0
 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)
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != 'disabled',
                                       User.tid == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

        # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563
        if State.tenant_cache[1].creation_date < 1551740400:
            u_password = '******'' + u.password + '\''
            if GCE.check_password(u.hash_alg, password, u.salt, u_password):
                user = u
                break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    crypto_prv_key = ''
    if State.tenant_cache[tid].encryption:
        if user.crypto_prv_key:
            user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
            crypto_prv_key = GCE.symmetric_decrypt(user_key,
                                                   user.crypto_prv_key)
        else:
            # Force the password change on which the user key will be created
            user.password_change_needed = True

    if user.two_factor_enable:
        if authcode != '':
            if user.crypto_pub_key:
                two_factor_secret = GCE.asymmetric_decrypt(
                    crypto_prv_key, user.two_factor_secret).decode('utf-8')
            else:
                two_factor_secret = user.two_factor_secret.decode('utf-8')

            # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec
            if not pyotp.TOTP(two_factor_secret).verify(authcode,
                                                        valid_window=1):
                raise errors.InvalidTwoFactorAuthCode

        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    return Sessions.new(tid, user.id, user.tid, user.role,
                        user.password_change_needed, user.two_factor_enable,
                        crypto_prv_key)
Exemple #3
0
def login_whistleblower(session, tid, receipt):
    """
    login_whistleblower returns a session
    """
    x = None

    algorithms = [x[0] for x in session.query(WhistleblowerTip.hash_alg).filter(WhistleblowerTip.tid == tid).distinct()]
    if algorithms:
        hashes = []
        for alg in algorithms:
            hashes.append(GCE.hash_password(receipt, State.tenant_cache[tid].receipt_salt, alg))

        x  = session.query(WhistleblowerTip, InternalTip) \
                    .filter(WhistleblowerTip.receipt_hash.in_(hashes),
                            WhistleblowerTip.tid == tid,
                            InternalTip.id == WhistleblowerTip.id,
                            InternalTip.tid == WhistleblowerTip.tid).one_or_none()

    if x is None:
        log.debug("Whistleblower login: Invalid receipt")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    wbtip = x[0]
    itip = x[1]

    itip.wb_last_access = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[tid].encryption and wbtip.crypto_prv_key:
        user_key = GCE.derive_key(receipt.encode('utf-8'), State.tenant_cache[tid].receipt_salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, wbtip.crypto_prv_key)

    return Sessions.new(tid, wbtip.id, tid, 'whistleblower', False, crypto_prv_key)
Exemple #4
0
def decrypt_tip(user_key, tip_prv_key, tip):
    tip_key = GCE.asymmetric_decrypt(user_key, tip_prv_key)

    for questionnaire in tip['questionnaires']:
        questionnaire['answers'] = json.loads(GCE.asymmetric_decrypt(tip_key, base64.b64decode(questionnaire['answers'].encode())).decode())

    for k in ['whistleblower_identity']:
        if k in tip['data'] and tip['data'][k]:
            tip['data'][k] = json.loads(GCE.asymmetric_decrypt(tip_key, base64.b64decode(tip['data'][k].encode())).decode())

            # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2612
            # The bug is due to the fact that the data was initially saved as an array of one entry
            if k == 'whistleblower_identity' and isinstance(tip['data'][k], list):
                tip['data'][k] = tip['data'][k][0]

    for x in tip['comments'] + tip['messages']:
        x['content'] = GCE.asymmetric_decrypt(tip_key, base64.b64decode(x['content'].encode())).decode()

    for x in tip['wbfiles'] + tip['rfiles']:
        for k in ['name', 'description', 'type', 'size']:
            if k in x:
                x[k] = GCE.asymmetric_decrypt(tip_key, base64.b64decode(x[k].encode())).decode()
                if k == 'size':
                    x[k] = int(x[k])

    return tip
Exemple #5
0
    def test_set_params(self):
        GCE.set_params(123, 321)

        self.assertEqual(GCE.ALGORITM_CONFIGURATION['ARGON2']['MEMLIMIT'], 123)
        self.assertEqual(GCE.ALGORITM_CONFIGURATION['ARGON2']['OPSLIMIT'], 321)

        GCE.set_params(27, 1)
Exemple #6
0
    def test_encrypt_and_decrypt_file(self):
        chunk_size = 1
        prv_key, pub_key = GCE.generate_keypair()
        a = __file__
        b = os.path.join(Settings.tmp_path, 'b')
        c = os.path.join(Settings.tmp_path, 'c')

        with open(a, 'rb') as input_fd, GCE.streaming_encryption_open(
                'ENCRYPT', pub_key, b) as seo:
            chunk = input_fd.read(1)
            while (True):
                x = input_fd.read(1)
                if not x:
                    seo.encrypt_chunk(chunk, 1)
                    break

                seo.encrypt_chunk(chunk, 0)

                chunk = x

        with open(c, 'wb') as output_fd,\
             GCE.streaming_encryption_open('DECRYPT', prv_key, b) as seo:

            while (True):
                last, data = seo.decrypt_chunk()
                output_fd.write(data)
                if last:
                    break

        self.assertFalse(filecmp.cmp(a, b, False))
        self.assertTrue(filecmp.cmp(a, c, False))
Exemple #7
0
def db_admin_update_user(session, tid, user_id, request, language):
    """
    Updates the specified user.
    """
    fill_localized_keys(request, models.User.localized_keys, language)

    user = db_get_user(session, tid, user_id)

    if user.username != request['username']:
        check = session.query(models.User).filter(
            models.User.username == text_type(request['username']),
            models.User.tid == tid).one_or_none()
        if check is not None:
            raise errors.InputValidationError('Username already in use')

    user.update(request)

    password = request['password']
    if password:
        user.hash_alg = GCE.HASH
        user.salt = GCE.generate_salt()
        user.password = GCE.hash_password(password, user.salt)
        user.password_change_date = datetime_now()
        user.crypto_prv_key = b''
        user.crypto_pub_key = b''

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    if user.role == 'admin':
        db_refresh_memory_variables(session, [tid])

    return user
Exemple #8
0
def db_admin_update_user(session, tid, user_id, request, language):
    """
    Updates the specified user.
    """
    fill_localized_keys(request, models.User.localized_keys, language)

    user = db_get_user(session, tid, user_id)

    if user.username != request['username']:
        check = session.query(models.User).filter(models.User.username == text_type(request['username']),
                                                  models.UserTenant.user_id == models.User.id,
                                                  models.UserTenant.tenant_id == tid).one_or_none()
        if check is not None:
            raise errors.InputValidationError('Username already in use')

    user.update(request)

    password = request['password']
    if password:
        user.hash_alg = GCE.HASH
        user.salt = GCE.generate_salt()
        user.password = GCE.hash_password(password, user.salt)
        user.password_change_date = datetime_now()
        user.crypto_prv_key = b''
        user.crypto_pub_key = b''

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    if user.role == 'admin':
        db_refresh_memory_variables(session, [tid])

    return user
Exemple #9
0
def login_whistleblower(session, tid, receipt):
    """
    login_whistleblower returns a session
    """
    x = None

    algorithms = [x[0] for x in session.query(WhistleblowerTip.hash_alg).filter(WhistleblowerTip.tid == tid).distinct()]
    if algorithms:
        hashes = []
        for alg in algorithms:
            hashes.append(GCE.hash_password(receipt, State.tenant_cache[tid].receipt_salt, alg))

        x  = session.query(WhistleblowerTip, InternalTip) \
                    .filter(WhistleblowerTip.receipt_hash.in_(hashes),
                            WhistleblowerTip.tid == tid,
                            InternalTip.id == WhistleblowerTip.id,
                            InternalTip.tid == WhistleblowerTip.tid).one_or_none()

    if x is None:
        log.debug("Whistleblower login: Invalid receipt")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    wbtip = x[0]
    itip = x[1]

    itip.wb_last_access = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and wbtip.crypto_prv_key:
        user_key = GCE.derive_key(receipt.encode('utf-8'), State.tenant_cache[tid].receipt_salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, wbtip.crypto_prv_key)

    return Sessions.new(tid, wbtip.id, 'whistleblower', False, crypto_prv_key)
Exemple #10
0
    def test_encrypt_and_decrypt_file(self):
        chunk_size = 1
        prv_key, pub_key = GCE.generate_keypair()
        a = __file__
        b = os.path.join(Settings.tmp_path, 'b')
        c = os.path.join(Settings.tmp_path, 'c')

        with open(a, 'rb') as input_fd, GCE.streaming_encryption_open('ENCRYPT', pub_key, b) as seo:
            chunk = input_fd.read(1)
            while(True):
                x = input_fd.read(1)
                if not x:
                    seo.encrypt_chunk(chunk, 1)
                    break

                seo.encrypt_chunk(chunk, 0)

                chunk = x

        with open(c, 'wb') as output_fd,\
             GCE.streaming_encryption_open('DECRYPT', prv_key, b) as seo:

            while(True):
                last, data = seo.decrypt_chunk()
                output_fd.write(data)
                if last:
                    break

        self.assertFalse(filecmp.cmp(a, b, False))
        self.assertTrue(filecmp.cmp(a, c, False))
Exemple #11
0
def login_whistleblower(session, tid, receipt):
    """
    Login transaction for whistleblowers' access

    :param session: An ORM session
    :param tid: A tenant ID
    :param receipt: A provided receipt
    :return: Returns a user session in case of success
    """
    x = None

    algorithms = [x[0] for x in session.query(WhistleblowerTip.hash_alg).filter(WhistleblowerTip.tid == tid).distinct()]

    if algorithms:
        hashes = [GCE.hash_password(receipt, State.tenant_cache[tid].receipt_salt, alg) for alg in algorithms]

        x = session.query(WhistleblowerTip, InternalTip) \
                   .filter(WhistleblowerTip.receipt_hash.in_(hashes),
                           WhistleblowerTip.tid == tid,
                           InternalTip.id == WhistleblowerTip.id).one_or_none()

    if x is None:
        login_failure(tid, 1)

    wbtip = x[0]
    itip = x[1]

    itip.wb_last_access = datetime_now()

    crypto_prv_key = ''
    if wbtip.crypto_prv_key:
        user_key = GCE.derive_key(receipt.encode(), State.tenant_cache[tid].receipt_salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, Base64Encoder.decode(wbtip.crypto_prv_key))

    return Sessions.new(tid, wbtip.id, tid, 'whistleblower', False, False, crypto_prv_key, '')
Exemple #12
0
def db_update_node(session, tid, user_session, request, language):
    """
    Transaction to update the node configuration

    :param session: An ORM session
    :param tid: A tenant ID
    :param user_session: The current user session
    :param request: The request data
    :param language: the language in which to localize data
    :return: Return the serialized configuration for the specified tenant
    """
    config = ConfigFactory(session, tid)

    enable_escrow = not config.get_val('escrow') and request.get('escrow', False)
    disable_escrow = user_session.ek and config.get_val('escrow') and not request.get('escrow', False)

    config.update('node', request)

    if request['enable_ricochet_panel'] and not request['ricochet_address']:
        request['enable_ricochet_panel'] = False

    # Validate that IP addresses/ranges we're getting are goo
    if 'ip_filter_admin' in request and request['ip_filter_admin_enable'] and request['ip_filter_admin']:
        parse_csv_ip_ranges_to_ip_networks(request['ip_filter_admin'])

    if 'languages_enabled' in request and 'default_language' in request:
        db_update_enabled_languages(session,
                                    tid,
                                    request['languages_enabled'],
                                    request['default_language'])

    if language in db_get_languages(session, tid):
        ConfigL10NFactory(session, tid).update('node', request, language)

    if enable_escrow:
        crypto_escrow_prv_key, State.tenant_cache[tid].crypto_escrow_pub_key = GCE.generate_keypair()
        user = db_get(session, models.User, models.User.id == user_session.user_id)
        user.crypto_escrow_prv_key = Base64Encoder.encode(GCE.asymmetric_encrypt(user.crypto_pub_key, crypto_escrow_prv_key))

        if tid == 1:
            session.query(models.User).update({'password_change_needed': True}, synchronize_session=False)
        else:
            session.query(models.User).filter(models.User.tid == tid).update({'password_change_needed': True}, synchronize_session=False)

    if disable_escrow:
        if tid == 1:
            session.query(models.User).update({'crypto_escrow_bkp1_key': ''}, synchronize_session=False)
        else:
            session.query(models.User).update({'crypto_escrow_bkp2_key': ''}, synchronize_session=False)

        session.query(models.User).filter(models.User.tid == tid).update({'crypto_escrow_prv_key': ''}, synchronize_session=False)

    config.set_val('crypto_escrow_pub_key', State.tenant_cache[tid].crypto_escrow_pub_key)

    db_refresh_memory_variables(session, [tid])

    if tid == 1:
        log.setloglevel(config.get_val('log_level'))

    return db_admin_serialize_node(session, tid, language)
Exemple #13
0
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    Login transaction for users' access

    :param session: An ORM session
    :param tid: A tenant ID
    :param username: A provided username
    :param password: A provided password
    :param authcode: A provided authcode
    :param client_using_tor: A boolean signaling Tor usage
    :param client_ip:  The client IP
    :return: Returns a user session in case of success
    """
    user = None

    for u in session.query(User).filter(User.username == username,
                                        User.state == 'enabled',
                                        User.tid == tid):
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

    if user is None:
        log.debug("Login: Invalid credentials")
        login_error(tid)

    connection_check(tid, client_ip, user.role, client_using_tor)

    crypto_prv_key = ''
    if user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode(), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(
            user_key, Base64Encoder.decode(user.crypto_prv_key))
    elif State.tenant_cache[tid].encryption:
        # Force the password change on which the user key will be created
        user.password_change_needed = True

    # Require password change if password change threshold is exceeded
    if State.tenant_cache[tid].password_change_period > 0 and \
       user.password_change_date < datetime_now() - timedelta(days=State.tenant_cache[tid].password_change_period):
        user.password_change_needed = True

    if user.two_factor_enable:
        if authcode != '':
            # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec
            if not pyotp.TOTP(user.two_factor_secret).verify(authcode,
                                                             valid_window=1):
                raise errors.InvalidTwoFactorAuthCode

        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    return Sessions.new(tid, user.id, user.tid, user.role,
                        user.password_change_needed, user.two_factor_enable,
                        crypto_prv_key, user.crypto_escrow_prv_key)
Exemple #14
0
def db_create_user(session, tid, request, language):
    request['tid'] = tid

    fill_localized_keys(request, models.User.localized_keys, language)

    if request['username']:
        user = session.query(models.User).filter(
            models.User.username == text_type(request['username']),
            models.UserTenant.user_id == models.User.id,
            models.UserTenant.tenant_id == tid).one_or_none()
        if user is not None:
            raise errors.InputValidationError('Username already in use')

    user = models.User({
        'tid':
        tid,
        'username':
        request['username'],
        'role':
        request['role'],
        'state':
        u'enabled',
        'name':
        request['name'],
        'description':
        request['description'],
        'language':
        language,
        'password_change_needed':
        request['password_change_needed'],
        'mail_address':
        request['mail_address'],
        'can_edit_general_settings':
        request['can_edit_general_settings']
    })

    if not request['username']:
        user.username = user.id = uuid4()

    password = u'password'
    if request['password']:
        password = request['password']

    user.hash_alg = GCE.HASH
    user.salt = GCE.generate_salt()
    user.password = GCE.hash_password(password, user.salt)

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    session.add(user)

    session.flush()

    db_create_usertenant_association(session, user.id, tid)

    return user
Exemple #15
0
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != u'disabled',
                                       UserTenant.user_id == User.id,
                                       UserTenant.tenant_id == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    if State.tenant_cache[
            1].two_factor_auth and user.last_login != datetime_null():
        token = TwoFactorTokens.get(user.id)

        if token is not None and authcode != '':
            if token.token == authcode:
                TwoFactorTokens.revoke(user.id)
            else:
                raise errors.InvalidTwoFactorAuthCode

        elif token is None and authcode == '':
            token = TwoFactorTokens.new(user.id)

            data = {'type': '2fa', 'authcode': str(token.token)}

            data['node'] = db_admin_serialize_node(session, tid, user.language)
            data['notification'] = db_get_notification(session, tid,
                                                       user.language)

            subject, body = Templating().get_mail_subject_and_body(data)
            State.sendmail(1, user.mail_address, subject, body)
            raise errors.TwoFactorAuthCodeRequired
        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key)

    return Sessions.new(tid, user.id, user.role, user.password_change_needed,
                        crypto_prv_key)
Exemple #16
0
    def get(self, rtip_id):
        tip_export = yield get_tip_export(self.request.tid,
                                          self.current_user.user_id, rtip_id,
                                          self.request.language)

        if tip_export['crypto_tip_prv_key']:
            tip_export['tip'] = yield deferToThread(
                decrypt_tip, self.current_user.cc,
                tip_export['crypto_tip_prv_key'], tip_export['tip'])

            for file_dict in tip_export['tip']['rfiles'] + tip_export['tip'][
                    'wbfiles']:
                if file_dict.get('status',
                                 '') == 'encrypted' or file_dict.get('forged'):
                    continue

                tip_prv_key = GCE.asymmetric_decrypt(
                    self.current_user.cc, tip_export['crypto_tip_prv_key'])
                file_dict['fo'] = GCE.streaming_encryption_open(
                    'DECRYPT', tip_prv_key, file_dict['path'])
                del file_dict['path']

        for file_dict in tip_export['tip']['rfiles']:
            file_dict['name'] = 'files/' + file_dict['name']
            if file_dict.get('status', '') == 'encrypted':
                file_dict['name'] += '.pgp'

        for file_dict in tip_export['tip']['wbfiles']:
            file_dict[
                'name'] = 'files_attached_from_recipients/' + file_dict['name']

        tip_export['comments'] = tip_export['tip']['comments']
        tip_export['messages'] = tip_export['tip']['messages']

        files = tip_export['tip']['rfiles'] + tip_export['tip']['wbfiles']
        del tip_export['tip']['rfiles'], tip_export['tip']['wbfiles']

        export_template = Templating().format_template(
            tip_export['notification']['export_template'],
            tip_export).encode()
        export_template = msdos_encode(export_template.decode()).encode()

        files.append({
            'fo': BytesIO(export_template),
            'name': 'data.txt',
            'forged': True
        })

        self.request.setHeader(b'X-Download-Options', b'noopen')
        self.request.setHeader(b'Content-Type', b'application/octet-stream')
        self.request.setHeader(b'Content-Disposition',
                               b'attachment; filename="submission.zip"')

        self.zip_stream = iter(ZipStream(files))

        yield ZipStreamProducer(self, self.zip_stream).start()
def login(session, tid, username, password, client_using_tor, client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != u'disabled',
                                       UserTenant.user_id == User.id,
                                       UserTenant.tenant_id == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    if not client_using_tor and not State.tenant_cache[tid]['https_' +
                                                            user.role]:
        log.err("Denied login request over Web for role '%s'" % user.role)
        raise errors.TorNetworkRequired

    # Check if we're doing IP address checks today
    if State.tenant_cache[tid]['ip_filter_authenticated_enable']:
        ip_networks = parse_csv_ip_ranges_to_ip_networks(
            State.tenant_cache[tid]['ip_filter_authenticated'])

        if isinstance(client_ip, binary_type):
            client_ip = client_ip.decode()

        client_ip_obj = ipaddress.ip_address(client_ip)

        # Safety check, we always allow localhost to log in
        success = False
        if client_ip_obj.is_loopback is True:
            success = True

        for ip_network in ip_networks:
            if client_ip_obj in ip_network:
                success = True

        if success is not True:
            raise errors.AccessLocationInvalid

    user.last_login = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key)

    return Sessions.new(tid, user.id, user.role, user.password_change_needed,
                        crypto_prv_key)
def validate_password_reset(session, reset_token, auth_code, recovery_key):
    """
    Retrieves a user given a password reset validation token

    :param session: An ORM session
    :param reset_token: A reset token
    :param auth_code: A two factor authentication code (optional)
    :param recovery_key: An encryption recovery key (optional)
    :return: A descriptor describing the result of the operation
    """
    now = datetime.now()
    prv_key = ''

    user = session.query(models.User).filter(
        models.User.reset_password_token == reset_token,
        models.User.reset_password_date >= now - timedelta(hours=72)
    ).one_or_none()

    # If the authentication token is invalid
    if user is None:
        return {'status': 'invalid_reset_token_provided'}

    # If encryption is enabled require the recovery key
    if user.crypto_prv_key:
        try:
            x = State.TempKeys.pop(user.id, None)
            if x:
                enc_key = GCE.derive_key(reset_token.encode(), user.salt)
                prv_key = GCE.symmetric_decrypt(enc_key, Base64Encoder.decode(x.key))
            else:
                recovery_key = recovery_key.replace('-', '').upper() + '===='
                recovery_key = Base32Encoder.decode(recovery_key.encode())
                prv_key = GCE.symmetric_decrypt(recovery_key, Base64Encoder.decode(user.crypto_bkp_key))
        except:
            return {'status': 'require_recovery_key'}

    elif user.two_factor_enable:
        two_factor_secret = user.two_factor_secret
        if not pyotp.TOTP(two_factor_secret).verify(auth_code, valid_window=1):
            return {'status': 'require_two_factor_authentication'}

    # Token is used, void it out
    user.reset_password_token = None
    user.reset_password_date = now

    # Require password change
    user.password_change_needed = True

    session = Sessions.new(user.tid, user.id,
                           user.tid, user.role,
                           user.password_change_needed,
                           user.two_factor_enable,
                           prv_key,
                           user.crypto_escrow_prv_key)

    return {'status': 'success', 'token': session.id}
Exemple #19
0
    def get(self, rfile_id):
        rfile, tip_prv_key = yield self.download_rfile(self.request.tid, self.current_user.user_id, rfile_id)

        filelocation = os.path.join(Settings.attachments_path, rfile['filename'])

        directory_traversal_check(Settings.attachments_path, filelocation)

        if tip_prv_key:
            tip_prv_key = GCE.asymmetric_decrypt(self.current_user.cc, tip_prv_key)
            fo = GCE.streaming_encryption_open('DECRYPT', tip_prv_key, filelocation)
            yield self.write_file_as_download_fo(rfile['name'], fo)
        else:
            yield self.write_file_as_download(rfile['name'], filelocation)
Exemple #20
0
    def get(self, rfile_id):
        rfile, tip_prv_key = yield self.download_rfile(self.request.tid, self.current_user.user_id, rfile_id)

        filelocation = os.path.join(Settings.attachments_path, rfile['filename'])

        directory_traversal_check(Settings.attachments_path, filelocation)

        if tip_prv_key:
            tip_prv_key = GCE.asymmetric_decrypt(self.current_user.cc, tip_prv_key)
            fo = GCE.streaming_encryption_open('DECRYPT', tip_prv_key, filelocation)
            yield self.write_file_as_download_fo(rfile['name'], fo)
        else:
            yield self.write_file_as_download(rfile['name'], filelocation)
Exemple #21
0
def generate_password_reset_token(session, tid, user_session, user_id):
    user = session.query(User).filter(User.tid == tid, User.id == user_id).one_or_none()
    if user is None:
        return

    db_generate_password_reset_token(session, user)

    if user_session.ek and user.crypto_pub_key:
        crypto_escrow_prv_key = GCE.asymmetric_decrypt(user_session.cc, Base64Encoder.decode(user_session.ek))
        user_cc = GCE.asymmetric_decrypt(crypto_escrow_prv_key, Base64Encoder.decode(user.crypto_escrow_bkp1_key))
        enc_key = GCE.derive_key(user.reset_password_token.encode(), user.salt)
        key = Base64Encoder.encode(GCE.symmetric_encrypt(enc_key, user_cc))
        State.TempKeys[user_id] = TempKey(key)
Exemple #22
0
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
Exemple #23
0
def decrypt_tip(user_key, tip_prv_key, tip):
    tip_key = GCE.asymmetric_decrypt(user_key, tip_prv_key)

    for questionnaire in tip['questionnaires']:
        questionnaire['answers'] = json.loads(GCE.asymmetric_decrypt(tip_key, base64.b64decode(questionnaire['answers'].encode())).decode())

    for k in ['whistleblower_identity']:
        if k in tip['data'] and tip['data'][k]['encrypted'] and tip['data'][k]['value']:
            tip['data'][k]['value'] = json.loads(GCE.asymmetric_decrypt(tip_key, base64.b64decode(tip['data'][k]['value'].encode())).decode())

    for x in tip['comments'] + tip['messages']:
        x['content'] = GCE.asymmetric_decrypt(tip_key, base64.b64decode(x['content'].encode())).decode()

    return tip
Exemple #24
0
def decrypt_tip(user_key, tip_prv_key, tip):
    tip_key = GCE.asymmetric_decrypt(user_key, tip_prv_key)

    for questionnaire in tip['questionnaires']:
        questionnaire['answers'] = json.loads(GCE.asymmetric_decrypt(tip_key, base64.b64decode(questionnaire['answers'].encode())).decode())

    for k in ['whistleblower_identity']:
        if k in tip['data'] and tip['data'][k]['encrypted'] and tip['data'][k]['value']:
            tip['data'][k]['value'] = json.loads(GCE.asymmetric_decrypt(tip_key, base64.b64decode(tip['data'][k]['value'].encode())).decode())

    for x in tip['comments'] + tip['messages']:
        x['content'] = GCE.asymmetric_decrypt(tip_key, base64.b64decode(x['content'].encode())).decode()

    return tip
Exemple #25
0
def db_create_user(session, tid, request, language):
    """
    Transaction for creating a new user

    :param session: An ORM session
    :param tid: A tenant ID
    :param request: The request data
    :param language: The language of the request
    :return: The serialized descriptor of the created object
    """
    request['tid'] = tid

    fill_localized_keys(request, models.User.localized_keys, language)

    if not request['public_name']:
        request['public_name'] = request['name']

    user = models.User(request)

    if not request['username']:
        user.username = user.id

    user.salt = GCE.generate_salt()

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    session.add(user)

    session.flush()

    if request.get('send_account_activation_link', False):
        db_generate_password_reset_token(session, user)

    return user
Exemple #26
0
def create_comment(session, tid, wbtip_id, user_key, content):
    wbtip, itip = session.query(models.WhistleblowerTip, models.InternalTip)\
                         .filter(models.WhistleblowerTip.id == wbtip_id,
                                 models.InternalTip.id == models.WhistleblowerTip.id,
                                 models.InternalTip.tid == tid).one_or_none()

    if wbtip is None:
        raise errors.ModelNotFound(models.WhistleblowerTip)

    itip.update_date = itip.wb_last_access = datetime_now()

    comment = models.Comment()
    comment.internaltip_id = wbtip_id
    comment.type = u'whistleblower'

    if itip.crypto_tip_pub_key:
        comment.content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
    else:
        comment.content = content

    session.add(comment)
    session.flush()

    ret = serialize_comment(session, comment)
    ret['content'] = content

    return ret
Exemple #27
0
def get_recovery_key(session, user_tid, user_id, user_cc):
    user = db_get_user(session, user_tid, user_id)

    if not user.crypto_rec_key:
        return ''

    return Base32Encoder().encode(GCE.asymmetric_decrypt(user_cc, user.crypto_rec_key)).replace(b'=', b'')
Exemple #28
0
def create_message(session, tid, wbtip_id, user_key, receiver_id, content):
    wbtip, itip, rtip_id = session.query(models.WhistleblowerTip, models.InternalTip, models.ReceiverTip.id) \
                                  .filter(models.WhistleblowerTip.id == wbtip_id,
                                          models.ReceiverTip.internaltip_id == wbtip_id,
                                          models.ReceiverTip.receiver_id == receiver_id,
                                          models.InternalTip.id == models.WhistleblowerTip.id,
                                          models.InternalTip.tid == tid).one_or_none()

    if wbtip is None:
        raise errors.ModelNotFound(models.WhistleblowerTip)

    itip.update_date = itip.wb_last_access = datetime_now()

    msg = models.Message()
    msg.receivertip_id = rtip_id
    msg.type = u'whistleblower'

    if itip.crypto_tip_pub_key:
        msg.content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
    else:
        msg.content = content

    session.add(msg)
    session.flush()

    ret = serialize_message(session, msg)
    ret['content'] = content

    return ret
Exemple #29
0
def create_message(session, tid, user_id, rtip_id, content):
    """
    Transaction for registering a new message
    :param session: An ORM session
    :param tid: A tenant ID
    :param user_id: The user id of the user creating the message
    :param rtip_id: The rtip associated to the message to be created
    :param content: The content of the message
    :return: A serialized descriptor of the message
    """
    rtip, itip = db_access_rtip(session, tid, user_id, rtip_id)

    itip.update_date = rtip.last_access = datetime_now()

    _content = content
    if itip.crypto_tip_pub_key:
        _content = base64.b64encode(
            GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()

    msg = models.Message()
    msg.receivertip_id = rtip.id
    msg.type = 'receiver'
    msg.content = _content
    session.add(msg)
    session.flush()

    ret = serialize_message(session, msg)
    ret['content'] = content
    return ret
Exemple #30
0
def create_comment(session, tid, wbtip_id, user_key, content):
    wbtip, itip = session.query(models.WhistleblowerTip, models.InternalTip)\
                         .filter(models.WhistleblowerTip.id == wbtip_id,
                                 models.InternalTip.id == models.WhistleblowerTip.id,
                                 models.InternalTip.tid == tid).one_or_none()

    if wbtip is None:
        raise errors.ModelNotFound(models.WhistleblowerTip)

    itip.update_date = itip.wb_last_access = datetime_now()

    comment = models.Comment()
    comment.internaltip_id = wbtip_id
    comment.type = u'whistleblower'

    if itip.crypto_tip_pub_key:
        comment.content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
    else:
        comment.content = content

    session.add(comment)
    session.flush()

    ret = serialize_comment(session, comment)
    ret['content'] = content

    return ret
Exemple #31
0
def create_comment(session, tid, user_id, rtip_id, content):
    """
    Transaction for registering a new comment
    :param session: An ORM session
    :param tid: A tenant ID
    :param user_id: The user id of the user creating the comment
    :param rtip_id: The rtip associated to the comment to be created
    :param content: The content of the comment
    :return: A serialized descriptor of the comment
    """
    rtip, itip = db_access_rtip(session, tid, user_id, rtip_id)

    itip.update_date = rtip.last_access = datetime_now()

    _content = content
    if itip.crypto_tip_pub_key:
        _content = base64.b64encode(
            GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()

    comment = models.Comment()
    comment.internaltip_id = itip.id
    comment.type = 'receiver'
    comment.author_id = rtip.receiver_id
    comment.content = _content
    session.add(comment)
    session.flush()

    ret = serialize_comment(session, comment)
    ret['content'] = content

    return ret
Exemple #32
0
def register_ifile_on_db(session, tid, internaltip_id, uploaded_file):
    now = datetime_now()

    itip = session.query(models.InternalTip) \
                  .filter(models.InternalTip.id == internaltip_id, models.InternalTip.tid == tid).one()

    itip.update_date = now
    itip.wb_last_access = now

    if itip.crypto_tip_pub_key:
        for k in ['name', 'type', 'size']:
            uploaded_file[k] = base64.b64encode(
                GCE.asymmetric_encrypt(itip.crypto_tip_pub_key,
                                       uploaded_file[k]))

    new_file = models.InternalFile()
    new_file.name = uploaded_file['name']
    new_file.content_type = uploaded_file['type']
    new_file.size = uploaded_file['size']
    new_file.internaltip_id = internaltip_id
    new_file.filename = uploaded_file['filename']
    new_file.submission = uploaded_file['submission']
    new_file.internaltip_id = internaltip_id

    session.add(new_file)

    return serializers.serialize_ifile(session, new_file)
Exemple #33
0
def create_message(session, tid, wbtip_id, receiver_id, content):
    wbtip, itip, rtip_id = db_get(session,
                                  (models.WhistleblowerTip, models.InternalTip, models.ReceiverTip.id),
                                  (models.WhistleblowerTip.id == wbtip_id,
                                   models.ReceiverTip.internaltip_id == wbtip_id,
                                   models.ReceiverTip.receiver_id == receiver_id,
                                   models.InternalTip.id == models.WhistleblowerTip.id,
                                   models.InternalTip.enable_two_way_messages.is_(True),
                                   models.InternalTip.status != 'closed',
                                   models.InternalTip.tid == tid))

    itip.update_date = itip.wb_last_access = datetime_now()

    _content = content
    if itip.crypto_tip_pub_key:
        _content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()

    msg = models.Message()
    msg.receivertip_id = rtip_id
    msg.type = 'whistleblower'
    msg.content = _content
    session.add(msg)
    session.flush()

    ret = serialize_message(session, msg)
    ret['content'] = content

    return ret
Exemple #34
0
def store_additional_questionnaire_answers(session, tid, tip_id, answers,
                                           language):
    itip = session.query(models.InternalTip) \
                  .filter(models.InternalTip.id == tip_id,
                          models.InternalTip.status != 'closed',
                          models.InternalTip.tid == tid).one()

    if not itip.additional_questionnaire_id:
        return

    steps = db_get_questionnaire(session, tid,
                                 itip.additional_questionnaire_id,
                                 None)['steps']
    questionnaire_hash = db_archive_questionnaire_schema(session, steps)

    db_save_plaintext_answers(session, tid, itip.id, answers,
                              itip.crypto_tip_pub_key != '')

    if itip.crypto_tip_pub_key:
        answers = base64.b64encode(
            GCE.asymmetric_encrypt(itip.crypto_tip_pub_key,
                                   json.dumps(answers).encode())).decode()

    db_set_internaltip_answers(session, itip.id, questionnaire_hash, answers)

    itip.additional_questionnaire_id = ''
Exemple #35
0
def create_comment(session, tid, wbtip_id, content):
    wbtip, itip = db_get(session,
                         (models.WhistleblowerTip, models.InternalTip),
                         (models.WhistleblowerTip.id == wbtip_id,
                          models.InternalTip.id == models.WhistleblowerTip.id,
                          models.InternalTip.enable_two_way_comments.is_(True),
                          models.InternalTip.status != 'closed',
                          models.InternalTip.tid == tid))

    itip.update_date = itip.wb_last_access = datetime_now()

    _content = content
    if itip.crypto_tip_pub_key:
        _content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()

    comment = models.Comment()
    comment.internaltip_id = wbtip_id
    comment.type = 'whistleblower'
    comment.content = _content
    session.add(comment)
    session.flush()

    ret = serialize_comment(session, comment)
    ret['content'] = content

    return ret
Exemple #36
0
def create_message(session, tid, wbtip_id, user_key, receiver_id, content):
    wbtip, itip, rtip_id = session.query(models.WhistleblowerTip, models.InternalTip, models.ReceiverTip.id) \
                                  .filter(models.WhistleblowerTip.id == wbtip_id,
                                          models.ReceiverTip.internaltip_id == wbtip_id,
                                          models.ReceiverTip.receiver_id == receiver_id,
                                          models.InternalTip.id == models.WhistleblowerTip.id,
                                          models.InternalTip.tid == tid).one_or_none()

    if wbtip is None:
        raise errors.ModelNotFound(models.WhistleblowerTip)

    itip.update_date = itip.wb_last_access = datetime_now()

    msg = models.Message()
    msg.receivertip_id = rtip_id
    msg.type = u'whistleblower'

    if itip.crypto_tip_pub_key:
        msg.content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
    else:
        msg.content = content

    session.add(msg)
    session.flush()

    ret = serialize_message(session, msg)
    ret['content'] = content

    return ret
Exemple #37
0
def register_wbfile_on_db(session, tid, rtip_id, uploaded_file):
    rtip, itip = session.query(models.ReceiverTip, models.InternalTip) \
                        .filter(models.ReceiverTip.id == rtip_id,
                                models.ReceiverTip.internaltip_id == models.InternalTip.id,
                                models.InternalTip.tid == tid).one()

    itip.update_date = rtip.last_access = datetime_now()

    if itip.crypto_tip_pub_key:
        for k in ['name', 'description', 'type', 'size']:
            uploaded_file[k] = base64.b64encode(
                GCE.asymmetric_encrypt(itip.crypto_tip_pub_key,
                                       text_type(uploaded_file[k])))

    new_file = models.WhistleblowerFile()

    new_file.name = uploaded_file['name']
    new_file.description = uploaded_file['description']
    new_file.content_type = uploaded_file['type']
    new_file.size = uploaded_file['size']

    new_file.receivertip_id = rtip_id
    new_file.filename = uploaded_file['filename']

    session.add(new_file)

    return serializers.serialize_wbfile(session, tid, new_file)
Exemple #38
0
def db_create_user(session, tid, request, language):
    request['tid'] = tid

    fill_localized_keys(request, models.User.localized_keys, language)

    if request['username']:
        user = session.query(models.User).filter(models.User.username == text_type(request['username']),
                                                 models.UserTenant.user_id == models.User.id,
                                                 models.UserTenant.tenant_id == tid).one_or_none()
        if user is not None:
            raise errors.InputValidationError('Username already in use')

    user = models.User({
        'tid': tid,
        'username': request['username'],
        'role': request['role'],
        'state': u'enabled',
        'name': request['name'],
        'description': request['description'],
        'language': language,
        'password_change_needed': request['password_change_needed'],
        'mail_address': request['mail_address'],
        'can_edit_general_settings': request['can_edit_general_settings']
    })

    if not request['username']:
        user.username = user.id = uuid4()

    password = u'password'
    if request['password']:
        password = request['password']

    user.hash_alg = GCE.HASH
    user.salt = GCE.generate_salt()
    user.password = GCE.hash_password(password, user.salt)

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    session.add(user)

    session.flush()

    db_create_usertenant_association(session, user.id, tid)

    return user
Exemple #39
0
    def get_internalfiles_by_receipt(self, session, receipt):
        hashed_receipt = GCE.hash_password(receipt, State.tenant_cache[1].receipt_salt)

        ifiles = session.query(models.InternalFile) \
                        .filter(models.InternalFile.internaltip_id == models.WhistleblowerTip.id,
                                models.WhistleblowerTip.receipt_hash == hashed_receipt)

        return [models.serializers.serialize_ifile(session, ifile) for ifile in ifiles]
Exemple #40
0
    def get(self):
        user = yield get_user(self.request.tid,
                              self.current_user.user_id,
                              self.request.language)

        user['cc'] = ''
        if self.current_user.cc:
            user['cc'] = GCE.export_private_key(self.current_user.cc)

        returnValue(user)
Exemple #41
0
def update_identity_information(session, tid, tip_id, identity_field_id, wbi, language):
    itip = models.db_get(session, models.InternalTip, models.InternalTip.id == tip_id, models.InternalTip.tid == tid)

    if itip.crypto_tip_pub_key:
        wbi = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, json.dumps(wbi).encode())).decode()

    db_set_internaltip_data(session, itip.id, 'identity_provided', True, False)
    db_set_internaltip_data(session, itip.id, 'whistleblower_identity', wbi, True)

    now = datetime_now()
    itip.update_date = now
    itip.wb_last_access = now
Exemple #42
0
def write_encrypted_file(key, sf, dest_path):
    try:
        with sf.open('rb') as encrypted_file, \
             GCE.streaming_encryption_open('ENCRYPT', key, dest_path) as seo:
            chunk = encrypted_file.read(abstract.FileDescriptor.bufferSize)
            while True:
                x = encrypted_file.read(abstract.FileDescriptor.bufferSize)
                if not x:
                    seo.encrypt_chunk(chunk, 1)
                    break

                seo.encrypt_chunk(chunk, 0)

                chunk = x
    except Exception as excep:
        log.err("Unable to create plaintext file %s: %s", dest_path, excep)
Exemple #43
0
def create_message(session, tid, user_id, user_key, rtip_id, content):
    rtip, itip = db_access_rtip(session, tid, user_id, rtip_id)

    itip.update_date = rtip.last_access = datetime_now()

    msg = models.Message()
    msg.receivertip_id = rtip.id
    msg.type = u'receiver'

    if itip.crypto_tip_pub_key:
        msg.content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
    else:
        msg.content = content

    session.add(msg)
    session.flush()

    ret = serialize_message(session, msg)
    ret['content'] = content
    return ret
Exemple #44
0
def create_comment(session, tid, user_id, user_key, rtip_id, content):
    rtip, itip = db_access_rtip(session, tid, user_id, rtip_id)

    itip.update_date = rtip.last_access = datetime_now()

    comment = models.Comment()
    comment.internaltip_id = itip.id
    comment.type = u'receiver'
    comment.author_id = rtip.receiver_id

    if itip.crypto_tip_pub_key:
        comment.content = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
    else:
        comment.content = content

    session.add(comment)
    session.flush()

    ret = serialize_comment(session, comment)
    ret['content'] = content

    return ret
Exemple #45
0
# -*- coding: utf-8
import filecmp
import os

from globaleaks.settings import Settings
from globaleaks.tests import helpers
from globaleaks.utils.crypto import GCE

password = b'password'
message = b'message'
salt = GCE.generate_salt()


class TestCryptoUtils(helpers.TestGL):
    def test_generate_key(self):
        GCE.generate_key()

    def test_generate_keypair(self):
        key = GCE.generate_key()
        prv_key, pub_key = GCE.generate_keypair()
        prv_key_enc = GCE.symmetric_encrypt(key, prv_key)
        self.assertEqual(prv_key, GCE.symmetric_decrypt(key, prv_key_enc))

    def test_export_import_key(self):
        x1, _ = GCE.generate_keypair()
        x2 = GCE.export_private_key(x1)
        x3 = GCE.import_private_key(x2)
        self.assertEqual(x1, x3._private_key)

    def test_derive_key(self):
        GCE.derive_key(password, salt)
Exemple #46
0
 def test_generate_key(self):
     GCE.generate_key()
Exemple #47
0
 def test_generate_keypair(self):
     key = GCE.generate_key()
     prv_key, pub_key = GCE.generate_keypair()
     prv_key_enc = GCE.symmetric_encrypt(key, prv_key)
     self.assertEqual(prv_key, GCE.symmetric_decrypt(key, prv_key_enc))
Exemple #48
0
 def test_crypto_generate_encrypt_decrypt_message(self):
     prv_key, pub_key = GCE.generate_keypair()
     enc = GCE.asymmetric_encrypt(pub_key, message)
     dec = GCE.asymmetric_decrypt(prv_key, enc)
     self.assertEqual(dec, message)
Exemple #49
0
# -*- encoding: utf-8 -*-
from globaleaks import __version__, DATABASE_VERSION
from globaleaks.models.config_desc import Unicode, Int, Bool
from globaleaks.utils.crypto import GCE
from globaleaks.utils.utility import datetime_null, iso_strf_time


GLConfig_v_37 = {
    'private': {
        'receipt_salt': Unicode(default=GCE.generate_salt()),
        'smtp_password': Unicode(default=u'yes_you_really_should_change_me'),

        'version': Unicode(default=Unicode(__version__)),
        'version_db': Int(default=DATABASE_VERSION),

        'https_priv_key': Unicode(),
        'https_priv_gen': Bool(default=False),
        'https_csr': Unicode(),
        'https_cert': Unicode(),
        'https_chain': Unicode(),
        'https_dh_params': Unicode(),
        'https_enabled': Bool(default=False),
    },
    'notification': {
        'server': Unicode(default=u'demo.globaleaks.org'),
        'port': Int(default=9267),

        'username': Unicode(default=u'hey_you_should_change_me'),
        # See smtp_password in private for password

        'source_name': Unicode(default=u'GlobaLeaks - CHANGE EMAIL ACCOUNT USED FOR NOTIFICATION'),
Exemple #50
0
def login(session, tid, username, password, authcode, client_using_tor, client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != u'disabled',
                                       UserTenant.user_id == User.id,
                                       UserTenant.tenant_id == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

        # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563
        if State.tenant_cache[1].creation_date < datetime.timestamp(datetime(2019, 5, 3, 0, 0)):
            u_password = '******'' + u.password + '\''
            if GCE.check_password(u.hash_alg, password, u.salt, u_password):
                user = u
                break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    if State.tenant_cache[1].two_factor_auth and user.last_login != datetime_null():
        token = TwoFactorTokens.get(user.id)

        if token is not None and authcode != '':
            if token.token == authcode:
                TwoFactorTokens.revoke(user.id)
            else:
                raise errors.InvalidTwoFactorAuthCode

        elif token is None and authcode == '':
            token = TwoFactorTokens.new(user.id)

            data = {
                'type': '2fa',
                'authcode': str(token.token)
            }

            data['node'] = db_admin_serialize_node(session, tid, user.language)
            data['notification'] = db_get_notification(session, tid, user.language)

            subject, body = Templating().get_mail_subject_and_body(data)
            State.sendmail(1, user.mail_address, subject, body)
            raise errors.TwoFactorAuthCodeRequired
        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key)

    return Sessions.new(tid, user.id, user.role, user.password_change_needed, crypto_prv_key)
Exemple #51
0
 def test_derive_key(self):
     GCE.derive_key(password, salt)
Exemple #52
0
def db_create_submission(session, tid, request, token, client_using_tor):
    if not request['receivers']:
        raise errors.InputValidationError("need at least one recipient")

    answers = request['answers']

    context, questionnaire = session.query(models.Context, models.Questionnaire) \
                                    .filter(models.Context.id == request['context_id'],
                                            models.Questionnaire.id == models.Context.questionnaire_id,
                                            models.Questionnaire.tid.in_(set([1, tid]))).one_or_none()

    if not context:
        raise errors.ModelNotFound(models.Context)

    steps = db_get_questionnaire(session, tid, questionnaire.id, None)['steps']
    questionnaire_hash = db_archive_questionnaire_schema(session, steps)

    itip = models.InternalTip()
    itip.tid = tid
    itip.status = db_get_id_for_system_status(session, tid, u'new')

    itip.progressive = db_assign_submission_progressive(session, tid)

    itip.additional_questionnaire_id = context.additional_questionnaire_id

    if context.tip_timetolive > 0:
        itip.expiration_date = get_expiration(context.tip_timetolive)

    # Evaluate the score level
    itip.total_score = request['total_score']

    # The status https is used to keep track of the security level adopted by the whistleblower
    itip.https = not client_using_tor

    itip.context_id = context.id
    itip.enable_two_way_comments = context.enable_two_way_comments
    itip.enable_two_way_messages = context.enable_two_way_messages
    itip.enable_attachments = context.enable_attachments

    x = session.query(models.Field, models.FieldAttr.value) \
               .filter(models.Field.template_id == u'whistleblower_identity',
                       models.Field.step_id == models.Step.id,
                       models.Step.questionnaire_id == context.questionnaire_id,
                       models.FieldAttr.field_id == models.Field.id,
                       models.FieldAttr.name == u'visibility_subject_to_authorization').one_or_none()

    whistleblower_identity = None
    can_access_whistleblower_identity = True

    if x:
        whistleblower_identity = x[0]
        can_access_whistleblower_identity = not x[1]

    itip.enable_whistleblower_identity = whistleblower_identity is not None

    itip.preview = extract_answers_preview(steps, answers)

    session.add(itip)
    session.flush()

    crypto_is_available = State.tenant_cache[1].encryption

    # Evaluate if encryption is available
    if crypto_is_available:
        users_count = session.query(models.User) \
                             .filter(models.User.id.in_(request['receivers']),
                                     models.User.crypto_prv_key != b'').count()

        crypto_is_available = users_count == len(request['receivers'])

        if crypto_is_available:
            crypto_tip_prv_key, itip.crypto_tip_pub_key = GCE.generate_keypair()

    # Evaluate if the whistleblower tip should be generated
    if ((not context.enable_scoring_system) or
        (context.score_threshold_receipt == 0) or
        (context.score_threshold_receipt == 1 and itip.total_score >= 2) or
        (context.score_threshold_receipt == 2 and itip.total_score == 3)):
        receipt = GCE.generate_receipt()
        receipt_salt = State.tenant_cache[tid].receipt_salt
        wbtip = models.WhistleblowerTip()
        wbtip.id = itip.id
        wbtip.tid = tid
        wbtip.hash_alg = GCE.HASH
        wbtip.receipt_hash = GCE.hash_password(receipt, receipt_salt)

        # Evaluate if the whistleblower tip should be encrypted
        if crypto_is_available:
            crypto_tip_prv_key, itip.crypto_tip_pub_key = GCE.generate_keypair()
            wb_key = GCE.derive_key(receipt.encode(), receipt_salt)
            wb_prv_key, wb_pub_key = GCE.generate_keypair()
            wbtip.crypto_prv_key = GCE.symmetric_encrypt(wb_key, wb_prv_key)
            wbtip.crypto_pub_key = wb_pub_key
            wbtip.crypto_tip_prv_key = GCE.asymmetric_encrypt(wb_pub_key, crypto_tip_prv_key)

        session.add(wbtip)
    else:
        receipt = ''

    # Apply special handling to the whistleblower identity question
    if itip.enable_whistleblower_identity and request['identity_provided'] and answers[whistleblower_identity.id]:
        if crypto_is_available:
            wbi = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, json.dumps(answers[whistleblower_identity.id][0]).encode())).decode()
            answers[whistleblower_identity.id] = ''
        else:
            wbi = answers[whistleblower_identity.id][0]

        db_set_internaltip_data(session, itip.id, 'identity_provided', True, False)
        db_set_internaltip_data(session, itip.id, 'whistleblower_identity', wbi, crypto_is_available)

    if crypto_is_available:
        answers = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, json.dumps(answers).encode())).decode()
    else:
        db_save_questionnaire_answers(session, tid, itip.id, answers)

    db_set_internaltip_answers(session,
                               itip.id,
                               questionnaire_hash,
                               answers,
                               crypto_is_available)

    for filedesc in token.uploaded_files:
        new_file = models.InternalFile()
        new_file.tid = tid
        new_file.encrypted = crypto_is_available
        new_file.name = filedesc['name']
        new_file.description = ""
        new_file.content_type = filedesc['type']
        new_file.size = filedesc['size']
        new_file.internaltip_id = itip.id
        new_file.submission = filedesc['submission']
        new_file.filename = filedesc['filename']
        session.add(new_file)
        log.debug("=> file associated %s|%s (%d bytes)",
                  new_file.name, new_file.content_type, new_file.size)

    if context.maximum_selectable_receivers > 0 and \
                    len(request['receivers']) > context.maximum_selectable_receivers:
        raise errors.InputValidationError("selected an invalid number of recipients")

    for user in session.query(models.User).filter(models.User.id.in_(request['receivers'])):
        if not crypto_is_available and not user.pgp_key_public and not State.tenant_cache[tid].allow_unencrypted:
            continue

        _tip_key = b''
        if crypto_is_available:
            _tip_key = GCE.asymmetric_encrypt(user.crypto_pub_key, crypto_tip_prv_key)

        db_create_receivertip(session, user, itip, can_access_whistleblower_identity, _tip_key)

    return {
        'receipt': receipt,
        'score': itip.total_score
    }
Exemple #53
0
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

        user.hash_alg = GCE.HASH
        user.salt = GCE.generate_salt()
        user.password = GCE.hash_password(new_password, user.salt)
        user.password_change_date = datetime_now()

        if State.tenant_cache[1].encryption:
            enc_key = GCE.derive_key(request['password'].encode(), user.salt)
            if not user_session.cc:
                user_session.cc, user.crypto_pub_key = GCE.generate_keypair()

            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)

        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, 1, 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
Exemple #54
0
 def test_crypto_generate_key_encrypt_decrypt_key(self):
     enc_key = GCE.generate_key()
     enc = GCE.symmetric_encrypt(enc_key, message)
     dec = GCE.symmetric_decrypt(enc_key, enc)
     self.assertEqual(dec, message)
Exemple #55
0
from globaleaks.utils.securetempfile import SecureTemporaryFile
from globaleaks.utils.utility import datetime_null, datetime_now, datetime_to_ISO8601, \
    sum_dicts
from globaleaks.utils.log import log

from globaleaks.workers import process
from globaleaks.workers.supervisor import ProcessSupervisor

GCE.ALGORITM_CONFIGURATION['KDF']['ARGON2']['OPSLIMIT'] = GCE.ALGORITM_CONFIGURATION['HASH']['ARGON2']['OPSLIMIT'] = 1
GCE.ALGORITM_CONFIGURATION['HASH']['SCRYPT']['N'] = 1<<1

################################################################################
# BEGIN MOCKS NECESSARY FOR DETERMINISTIC ENCRYPTION
VALID_PASSWORD1 = u'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 = u'antani'

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 = GCE.symmetric_encrypt(USER_KEY, USER_PRV_KEY)
GCE_orig_generate_key = GCE.generate_key
GCE_orig_generate_keypair = GCE.generate_keypair


@staticmethod
Exemple #56
0
 def test_export_import_key(self):
     x1, _ = GCE.generate_keypair()
     x2 = GCE.export_private_key(x1)
     x3 = GCE.import_private_key(x2)
     self.assertEqual(x1, x3._private_key)
Exemple #57
0
 def test_check_password(self):
     hash = GCE.hash_password(password, salt)
     self.assertTrue(GCE.check_password(GCE.HASH, password, salt, hash))
     self.assertFalse(GCE.check_password(GCE.HASH, password, salt, 'nohashnoparty'))