Example #1
0
    def test_invalid_verify(self, backend):
        prk = binascii.unhexlify(b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")

        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        with pytest.raises(InvalidKey):
            hkdf.verify(prk, b"wrong key")
Example #2
0
    def test_already_finalized(self, backend):
        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        hkdf.derive(b"first")

        with pytest.raises(AlreadyFinalized):
            hkdf.derive(b"second")
def aeskeygen(shared_key):
    backend = default_backend()
    info = b"hkdf-example"
    hkdf = HKDFExpand(algorithm=hashes.SHA256(),
                      length=32,
                      info=info,
                      backend=backend)
    key = hkdf.derive(shared_key)
    return key
Example #4
0
    def test_verify(self, backend):
        prk = binascii.unhexlify(b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")

        okm = b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" b"5bf34007208d5b887185865"

        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        assert hkdf.verify(prk, binascii.unhexlify(okm)) is None
Example #5
0
    def generate_session_keys(self, shared_secret):
        hkdf = HKDFExpand(algorithm=hashes.SHA256(), backend=default_backend(), length=72, info=b"key_generation")
        key = hkdf.derive(shared_secret)

        kf = key[:32]
        kb = key[32:64]
        sf = key[64:68]
        sb = key[68:72]
        return [kf, kb, sf, sb, 1, 1]
Example #6
0
    def generate_session_keys(self, shared_secret):
        hkdf = HKDFExpand(algorithm=hashes.SHA256(), backend=default_backend(), length=40, info=b"key_generation")
        key = hkdf.derive(shared_secret)

        kf = key[:16]
        kb = key[16:32]
        sf = key[32:36]
        sb = key[36:40]
        return [kf, kb, sf, sb, 1, 1]
Example #7
0
def hkdf_expand_test(backend, algorithm, params):
    hkdf = HKDFExpand(algorithm,
                      int(params["l"]),
                      info=binascii.unhexlify(params["info"]) or None,
                      backend=backend)

    okm = hkdf.derive(binascii.unhexlify(params["prk"]))

    assert okm == binascii.unhexlify(params["okm"])
Example #8
0
    def test_random_source_verify_default_backend(self, backend):
        key_material = urandom(16)
        identifier = b'region123'
        derived_key = derive_key(key_material, identifier, strong=True)
        kdf = HKDFExpand(algorithm=hashes.SHA256(),
                         length=32,
                         info=identifier,
                         backend=backend)

        kdf.verify(key_material, derived_key)
Example #9
0
    def test_invalid_verify(self, backend):
        prk = binascii.unhexlify(
            b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
        )

        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        with pytest.raises(InvalidKey):
            hkdf.verify(prk, b"wrong key")
Example #10
0
def hkdf_expand_test(backend, algorithm, params):
    hkdf = HKDFExpand(
        algorithm,
        int(params["l"]),
        info=binascii.unhexlify(params["info"]) or None,
        backend=backend
    )

    okm = hkdf.derive(binascii.unhexlify(params["prk"]))

    assert okm == binascii.unhexlify(params["okm"])
Example #11
0
def aeskeygen(shared_key):
   backend = default_backend()
   info = b"hkdf-example"
   hkdf = HKDFExpand(
      algorithm=hashes.SHA256(),
         length=32,
         info=info,
         backend=backend
   )
   key = hkdf.derive(shared_key)
   return key
Example #12
0
    def test_verify(self, backend):
        prk = binascii.unhexlify(
            b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
        )

        okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
               b"5bf34007208d5b887185865")

        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        hkdf.verify(prk, binascii.unhexlify(okm))
Example #13
0
    def test_buffer_protocol(self, backend):
        prk = bytearray(
            binascii.unhexlify(
                b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2"
                b"b3e5"))

        okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
               b"5bf34007208d5b887185865")

        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        assert binascii.hexlify(hkdf.derive(prk)) == okm
Example #14
0
async def ingameRegistration(request: Request) -> Union[dict, bytes]:
    start = time.time()
    mpargs = request.args

    name = mpargs["user[username]"].strip()  # what is this setup osu lol
    email = mpargs["user[user_email]"].strip()
    pw = mpargs["user[password]"].strip()

    if not mpargs.get("check") or not all((name, email, pw)):
        return b"missing required paramaters"

    errors = defaultdict(list)
    if " " in name and "_" in name:
        errors["username"].append('Username cannot contain both "_" and " "')

    if await glob.db.fetchval("SELECT 1 FROM users WHERE name = %s", [name]):
        errors["username"].append("Username already taken!")

    if await glob.db.fetchval("SELECT 1 FROM users WHERE email = %s", [email]):
        errors["user_email"].append("Email already in use!")

    if not len(pw) >= 8:
        errors["password"].append("Password must be 8+ characters!")

    if errors:
        return {"form_error": {"user": errors}}

    if int(mpargs["check"]) == 0:
        md5 = hashlib.md5(pw.encode()).hexdigest().encode()
        k = HKDFExpand(
            algorithm=hashes.SHA256(),
            length=32,
            info=b"",
            backend=backend(),
        )
        bc = k.derive(md5).decode("unicode-escape")

        glob.cache["pw"][bc] = md5

        uid = await glob.db.execute(
            "INSERT INTO users (name, email, pw, safe_name, registered_at) VALUES (%s, %s, %s, %s, %s)",
            [name, email, bc,
             name.lower().replace(" ", "_"),
             time.time()],
        )
        await glob.db.execute("INSERT INTO stats (id) VALUES (%s)", [uid])
        info(
            f"{name} successfully registered. | Time Elapsed: {(time.time() - start) * 1000:.2f}ms",
        )

    return b"ok"
Example #15
0
async def ingameRegistration(request: Request) -> Union[dict, bytes]:
    start = time.time()
    mpargs = request.args

    name = mpargs['user[username]'].strip()  # what is this setup osu lol
    email = mpargs['user[user_email]'].strip()
    pw = mpargs['user[password]'].strip()

    if not mpargs.get('check') or not all((name, email, pw)):
        return b'missing required paramaters'

    errors = defaultdict(list)
    if ' ' in name and '_' in name:
        errors['username'].append('Username cannot contain both "_" and " "')

    if await glob.db.fetchval("SELECT 1 FROM users WHERE name = %s", [name]):
        errors['username'].append('Username already taken!')

    if await glob.db.fetchval("SELECT 1 FROM users WHERE name = %s", [email]):
        errors['user_email'].append('Email already in use!')

    if not len(pw) >= 8:
        errors['password'].append('Password must be 8+ characters!')

    if errors:
        return {'form_error': {'user': errors}}

    if int(mpargs['check']) == 0:
        md5 = hashlib.md5(pw.encode()).hexdigest().encode()
        k = HKDFExpand(algorithm=hashes.SHA256(),
                       length=32,
                       info=b'',
                       backend=backend())
        bc = k.derive(md5).decode('unicode-escape')

        glob.cache['pw'][bc] = md5

        uid = await glob.db.execute(
            "INSERT INTO users (name, email, pw, safe_name, registered_at) VALUES (%s, %s, %s, %s, %s)",
            [name, email, bc,
             name.lower().replace(' ', '_'),
             time.time()])
        await glob.db.execute('INSERT INTO stats (id) VALUES (%s)', [uid])
        log(
            f'{name} successfully registered. | Time Elapsed: {(time.time() - start) * 1000:.2f}ms',
            Ansi.LBLUE)

    return b'ok'
Example #16
0
 def hkdf_expand(algorithm="SHA256", length=256, info='', backend=BACKEND):
     """ Returns an hmac based key derivation function (expand only) from
         cryptography.hazmat.primitives.hkdf. """
     return HKDFExpand(algorithm=getattr(hashes, algorithm.upper())(),
                       length=length,
                       info=info,
                       backend=BACKEND)
Example #17
0
    def initate_connection(self, target_host, no_exchange=False):
        """Tries the primary and alternate ports."""
        global connected, fernet
        # establish an initial connection
        try:
            self.outgoing.connect((target_host, REMOTE_PORT))
        except Exception as e:
            logging.error(str(e))
            logging.info("Trying alternate remote")
            try:
                self.outgoing.connect((target_host, REMOTE_ALT_PORT))
            except Exception as e:
                logging.error(str(e))
                return

        # setup connection from server thread
        connected = target_host
        if no_exchange:
            return

        # exchange the ec public key
        try:
            self.outgoing.sendall(private_key.public_key().public_bytes(
                Encoding.PEM, PublicFormat.SubjectPublicKeyInfo))
            peer_public_key = load_pem_public_key(self.outgoing.recv(4096))
            shared_key = private_key.exchange(peer_public_key)
            derived_key = HKDFExpand(algorithm=hashes.SHA256(),
                                     length=32,
                                     info=None).derive(shared_key)
            fernet = Fernet(base64.urlsafe_b64encode(derived_key))
        except Exception as e:
            logging.error(str(e))
            connected = None
Example #18
0
def test_invalid_backend():
    pretend_backend = object()

    with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
        HKDF(hashes.SHA256(), 16, None, None, pretend_backend)

    with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
        HKDFExpand(hashes.SHA256(), 16, None, pretend_backend)
Example #19
0
def hkdf_expand_label(
    algorithm: hashes.HashAlgorithm,
    secret: bytes,
    label: bytes,
    hash_value: bytes,
    length: int,
) -> bytes:
    return HKDFExpand(
        algorithm=algorithm,
        length=length,
        info=hkdf_label(label, hash_value, length),
        backend=default_backend(),
    ).derive(secret)
Example #20
0
def derive_reply_keys(message_id):
    """Derive the lookup key and encrytion key from an aliased message id."""
    algorithm = hashes.SHA256()
    hkdf = HKDFExpand(algorithm=algorithm, length=16, info=b"replay replies lookup key")
    lookup_key = hkdf.derive(message_id)
    hkdf = HKDFExpand(algorithm=algorithm, length=32, info=b"replay replies encryption key")
    encryption_key = hkdf.derive(message_id)
    return (lookup_key, encryption_key)
Example #21
0
    def test_already_finalized(self, backend):
        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        hkdf.derive(b"first")

        with pytest.raises(AlreadyFinalized):
            hkdf.derive(b"second")
Example #22
0
def HKDF_Expand_Label(key,
                      label,
                      context,
                      length,
                      backend=default_backend(),
                      algorithm=hashes.SHA256()):
    tmp_label = b"tls13 " + label.encode()
    hkdf_label = (struct.pack(">h", length) +
                  struct.pack("b", len(tmp_label)) + tmp_label +
                  struct.pack("b", len(context)) + context)
    return HKDFExpand(algorithm=algorithm,
                      length=length,
                      info=hkdf_label,
                      backend=backend).derive(key)
Example #23
0
def derive_key(key_material,
               identifier,
               length=32,
               strong=False,
               backend=DEFAULT_BACKEND):
    if not isinstance(key_material, bytes):
        raise TypeError('key_material must be bytes.')

    if not isinstance(identifier, bytes):
        raise TypeError('identifier must be bytes.')

    if strong:
        kdf = HKDFExpand(algorithm=DEFAULT_HASH,
                         length=length,
                         info=identifier,
                         backend=backend)
    else:
        kdf = PBKDF2HMAC(algorithm=DEFAULT_HASH,
                         length=length,
                         salt=identifier,
                         iterations=131072,
                         backend=backend)

    return kdf.derive(key_material)
Example #24
0
 def accept_connection(self):
     """Accepts connection and derives a shared key."""
     global connected, fernet
     try:
         # exchange the ec public key
         peer_public_key = load_pem_public_key(self.peer.recv(4096))
         self.peer.sendall(private_key.public_key().public_bytes(
             Encoding.PEM, PublicFormat.SubjectPublicKeyInfo))
         shared_key = private_key.exchange(peer_public_key)
         derived_key = HKDFExpand(algorithm=hashes.SHA256(),
                                  length=32,
                                  info=None).derive(shared_key)
         fernet = Fernet(base64.urlsafe_b64encode(derived_key))
     except Exception as e:
         logging.error(str(e))
Example #25
0
def hkdf_expand_label(secret: bytes, label: bytes, context: GroupContext, cipher_suite: CipherSuite) -> bytes:
    """
    Generates a secret from given secret, label and GroupContext object
    :param secret: secret argument for HKDFExpand
    :param label: label used in HKDFExpand
    :param context: GroupContext object used in HKDFExpand
    :param cipher_suite: CipherSuite which should be used
    :return: secret derived from given parameters
    """
    context_hash = cipher_suite.get_hash()
    context_hash.update(bytes(context))
    label_part = bytes(HkdfLabel(context_hash.finalize(), cipher_suite.get_hash_length(), label, context))
    hkdf_label: bytes = b'mls10 ' + label_part

    # todo: support hash from cipher suite
    return HKDFExpand(length=cipher_suite.get_hash_length(), info=hkdf_label,
                      algorithm=hashes.SHA256(), backend=default_backend()).derive(secret)
Example #26
0
    def _hkdf_expand(self, length: int, label: str, prk: bytes,
                     transcript: bytes) -> bytes:
        """
        Derive the encryption key and the IV to protect the COSE_Encrypt0 message in the EDHOC message 2.

        :return:
        """
        hash_func = self.cipher_suite.hash.hash_cls

        info = EdhocKDFInfo(edhoc_aead_id=self.cipher_suite.aead.identifier,
                            transcript_hash=self.transcript(
                                hash_func, transcript),
                            label=label,
                            length=length)

        derived_bytes = HKDFExpand(algorithm=hash_func(),
                                   length=info.length,
                                   info=info.encode()).derive(prk)

        return derived_bytes
Example #27
0
def hkdf_sha256(key, length=16, info=''):
    hkdf = HKDFExpand(algorithm=hashes.SHA256(),
                      length=length,
                      info=info,
                      backend=bend)
    return hkdf.derive(key)
Example #28
0
    def test_unicode_error(self, backend):
        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        with pytest.raises(TypeError):
            hkdf.derive("first")  # type: ignore[arg-type]
Example #29
0
def getBitwardenSecrets(email, password, kdfIterations, encKey, encPrivateKey):
    BitwardenSecrets = {}
    BitwardenSecrets['email']           = email
    BitwardenSecrets['kdfIterations']   = kdfIterations
    BitwardenSecrets['MasterPassword']  = password
    BitwardenSecrets['ProtectedSymmetricKey'] = encKey
    BitwardenSecrets['ProtectedRSAPrivateKey'] = encPrivateKey

    
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=bytes(BitwardenSecrets['email'], 'utf-8'),
        iterations=BitwardenSecrets['kdfIterations'],
        backend=default_backend()
        )
    BitwardenSecrets['MasterKey']       = kdf.derive(BitwardenSecrets['MasterPassword'])
    BitwardenSecrets['MasterKey_b64']   = base64.b64encode(BitwardenSecrets['MasterKey']).decode('utf-8')


    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=bytes(BitwardenSecrets['MasterPassword']),
        iterations=1,
        backend=default_backend()
        )
    BitwardenSecrets['MasterPasswordHash']  = base64.b64encode(kdf.derive(BitwardenSecrets['MasterKey'])).decode('utf-8')


    hkdf = HKDFExpand(
        algorithm=hashes.SHA256(),
        length=32,
        info=b"enc",
        backend=default_backend()
        )
    BitwardenSecrets['StretchedEncryptionKey']      = hkdf.derive(BitwardenSecrets['MasterKey'])
    BitwardenSecrets['StretchedEncryptionKey_b64']  = base64.b64encode(BitwardenSecrets['StretchedEncryptionKey']).decode('utf-8')

    hkdf = HKDFExpand(
        algorithm=hashes.SHA256(),
        length=32,
        info=b"mac",
        backend=default_backend()
        )
    BitwardenSecrets['StretchedMacKey']     = hkdf.derive(BitwardenSecrets['MasterKey'])
    BitwardenSecrets['StretchedMacKey_b64'] = base64.b64encode(BitwardenSecrets['StretchedMacKey']).decode('utf-8')

    BitwardenSecrets['StretchedMasterKey']      = BitwardenSecrets['StretchedEncryptionKey'] + BitwardenSecrets['StretchedMacKey']
    BitwardenSecrets['StretchedMasterKey_b64']  = base64.b64encode(BitwardenSecrets['StretchedMasterKey']).decode('utf-8')

    BitwardenSecrets['GeneratedSymmetricKey'], \
    BitwardenSecrets['GeneratedEncryptionKey'], \
    BitwardenSecrets['GeneratedMACKey']             = decryptMasterEncryptionKey(BitwardenSecrets['ProtectedSymmetricKey'], BitwardenSecrets['StretchedEncryptionKey'], BitwardenSecrets['StretchedMacKey'])
    BitwardenSecrets['GeneratedSymmetricKey_b64']   = base64.b64encode(BitwardenSecrets['GeneratedSymmetricKey']).decode('utf-8')
    BitwardenSecrets['GeneratedEncryptionKey_b64']  = base64.b64encode(BitwardenSecrets['GeneratedEncryptionKey']).decode('utf-8')
    BitwardenSecrets['GeneratedMACKey_b64']         = base64.b64encode(BitwardenSecrets['GeneratedMACKey']).decode('utf-8')


    BitwardenSecrets['RSAPrivateKey'] = decryptRSAPrivateKey(BitwardenSecrets['ProtectedRSAPrivateKey'], \
                                                            BitwardenSecrets['GeneratedEncryptionKey'], \
                                                            BitwardenSecrets['GeneratedMACKey'])

    return(BitwardenSecrets)
Example #30
0
def hkdf(key, length=16, info=''):
    hkdf = HKDFExpand(algorithm=SHA256(), length=length, info=info, backend=bend)
    return hkdf.derive(key)
Example #31
0
 def expand(self, prk, info, L):
     h = self.hash
     hkdf = HKDFExpand(h, L, info, default_backend())
     return hkdf.derive(prk)
Example #32
0
    def test_unicode_error(self, backend):
        info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
        hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)

        with pytest.raises(TypeError):
            hkdf.derive(u"first")
Example #33
0
async def register_post():
    if 'authenticated' in session:
        return await flash('error', "You're already logged in.", 'home')

    if not glob.config.registration:
        return await flash('error', 'Registrations are currently disabled.', 'home')

    form = await request.form
    username = form.get('username', type=str)
    email = form.get('email', type=str)
    passwd_txt = form.get('password', type=str)

    if username is None or email is None or passwd_txt is None:
        return await flash('error', 'Invalid parameters.', 'home')

    if glob.config.hCaptcha_sitekey != 'changeme':
        captcha_data = form.get('h-captcha-response', type=str)
        if (
            captcha_data is None or
            not await utils.validate_captcha(captcha_data)
        ):
            return await flash('error', 'Captcha failed.', 'register')

    # Usernames must:
    # - be within 2-15 characters in length
    # - not contain both ' ' and '_', one is fine
    # - not be in the config's `disallowed_names` list
    # - not already be taken by another player
    # check if username exists
    if not regexes.username.match(username):
        return await flash('error', 'Invalid username syntax.', 'register')

    if '_' in username and ' ' in username:
        return await flash('error', 'Username may contain "_" or " ", but not both.', 'register')

    if username in glob.config.disallowed_names:
        return await flash('error', 'Disallowed username; pick another.', 'register')

    if await glob.db.fetch('SELECT 1 FROM users WHERE name = %s', username):
        return await flash('error', 'Username already taken by another user.', 'register')

    # Emails must:
    # - match the regex `^[^@\s]{1,200}@[^@\s\.]{1,30}\.[^@\.\s]{1,24}$`
    # - not already be taken by another player
    if not regexes.email.match(email):
        return await flash('error', 'Invalid email syntax.', 'register')

    if await glob.db.fetch('SELECT 1 FROM users WHERE email = %s', email):
        return await flash('error', 'Email already taken by another user.', 'register')

    # Passwords must:
    # - be within 8-32 characters in length
    # - have more than 3 unique characters
    # - not be in the config's `disallowed_passwords` list
    if not 8 <= len(passwd_txt) <= 32:
        return await flash('error', 'Password must be 8-32 characters in length.', 'register')

    if len(set(passwd_txt)) <= 3:
        return await flash('error', 'Password must have more than 3 unique characters.', 'register')

    if passwd_txt.lower() in glob.config.disallowed_passwords:
        return await flash('error', 'That password was deemed too simple.', 'register')

    # TODO: add correct locking
    # (start of lock)
    pw_md5 = hashlib.md5(passwd_txt.encode()).hexdigest().encode()
    k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend())
    pw_hash = k.derive(pw_md5).decode('unicode-escape')
    glob.cache['pw'][pw_hash] = pw_md5 # cache pw

    safe_name = utils.get_safe_name(username)

    # fetch the users' country
    if 'CF-Connecting-IP' in request.headers:
        ip = request.headers['CF-Connecting-IP']
    else:
        ip = request.headers['X-Forwarded-For'].split(',')[0]
    
    try:
        country = await utils.fetch_geoloc(ip)
    except:
        country = 'xx'

    user = await glob.db.execute(
        'INSERT INTO users '
        '(name, safe_name, email, pw, country, registered_at) '
        'VALUES (%s, %s, %s, %s, %s, UNIX_TIMESTAMP())',
        [username, safe_name, email, pw_hash, country]
    )
        
    user_id = user

    # add to `stats` table.
    await glob.db.execute(
        'INSERT INTO stats '
        '(id) VALUES (%s)',
        user_id
    )

    # (end of lock)

    if glob.config.debug:
        log(f'{username} has registered - awaiting verification.', Ansi.LGREEN)

    # user has successfully registered
    return await render_template('verify.html')
Example #34
0
async def login_post():
    if 'authenticated' in session:
        return await flash('error', "You're already logged in!", 'home')

    if glob.config.debug:
        login_time = time.time_ns()

    form = await request.form
    username = form.get('username', type=str)
    passwd_txt = form.get('password', type=str)

    if username is None or passwd_txt is None:
        return await flash('error', 'Invalid parameters.', 'home')

    # check if account exists
    user_info = await glob.db.fetchrow(
        'SELECT id, name, email, priv, '
        'pw, silence_end '
        'FROM users '
        'WHERE safe_name = %s',
        [utils.get_safe_name(username)]
    )

    # user doesn't exist; deny post
    # NOTE: Bot isn't a user.
    if not user_info or user_info['id'] == 1:
        if glob.config.debug:
            log(f"{username}'s login failed - account doesn't exist.", Ansi.LYELLOW)
        return await flash('error', 'Account does not exist.', 'login')

    # cache and other related password information
    pw_cache = glob.cache['pw']
    pw_hash = user_info['pw'].encode('ISO-8859-1').decode('unicode-escape').encode('ISO-8859-1')
    pw_md5 = hashlib.md5(passwd_txt.encode()).hexdigest().encode()

    # check credentials (password) against db
    # intentionally slow, will cache to speed up
    if pw_hash in pw_cache:
        if pw_md5 != pw_cache[pw_hash]: # ~0.1ms
            if glob.config.debug:
                log(f"{username}'s login failed - pw incorrect.", Ansi.LYELLOW)
            return await flash('error', 'Password is incorrect.', 'login')
    else: # ~200ms
        k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend())
        try:
           k.verify(pw_md5, pw_hash)
        except:
            if glob.config.debug:
                log(f"{username}'s login failed - pw incorrect.", Ansi.LYELLOW)
            return await flash('error', 'Password is incorrect.', 'login')

        # login successful; cache password for next login
        pw_cache[pw_hash] = pw_md5

    # user not verified; render verify
    if not user_info['priv'] & Privileges.Verified:
        if glob.config.debug:
            log(f"{username}'s login failed - not verified.", Ansi.LYELLOW)
        return await render_template('verify.html')

    # user banned; deny post
    if user_info['priv'] & Privileges.Disallowed:
        if glob.config.debug:
            log(f"{username}'s login failed - banned.", Ansi.RED)
        return await flash('error', 'Your account is restricted. You are not allowed to log in.', 'login')

    # login successful; store session data
    if glob.config.debug:
        log(f"{username}'s login succeeded.", Ansi.LGREEN)

    session['authenticated'] = True
    session['user_data'] = {
        'id': user_info['id'],
        'name': user_info['name'],
        'email': user_info['email'],
        'priv': user_info['priv'],
        'silence_end': user_info['silence_end'],
        'is_staff': user_info['priv'] & Privileges.Staff,
        'is_donator': user_info['priv'] & Privileges.Supporter
    }

    if glob.config.debug:
        login_time = (time.time_ns() - login_time) / 1e6
        log(f'Login took {login_time:.2f}ms!', Ansi.LYELLOW)

    return await flash('success', f'Hey, welcome back {username}!', 'home')
Example #35
0
async def settings_password_post():
    form = await request.form
    old_password = form.get('old_password')
    new_password = form.get('new_password')
    repeat_password = form.get('repeat_password')

    # new password and repeat password don't match; deny post
    if new_password != repeat_password:
        return await flash('error', "Your new password doesn't match your repeated password!", 'settings/password')

    # new password and old password match; deny post
    if old_password == new_password:
        return await flash('error', 'Your new password cannot be the same as your old password!', 'settings/password')

    # Passwords must:
    # - be within 8-32 characters in length
    # - have more than 3 unique characters
    # - not be in the config's `disallowed_passwords` list
    if not 8 < len(new_password) <= 32:
        return await flash('error', 'Your new password must be 8-32 characters in length.', 'settings/password')

    if len(set(new_password)) <= 3:
        return await flash('error', 'Your new password must have more than 3 unique characters.', 'settings/password')

    if new_password.lower() in glob.config.disallowed_passwords:
        return await flash('error', 'Your new password was deemed too simple.', 'settings/password')

    # cache and other password related information
    pw_cache = glob.cache['pw']
    pw_hash = (await glob.db.fetchval(
        'SELECT pw '
        'FROM users '
        'WHERE id = %s',
        [session['user_data']['id']])
    ).encode('ISO-8859-1').decode('unicode-escape').encode('ISO-8859-1')

    pw_md5 = hashlib.md5(old_password.encode()).hexdigest().encode()

    # check old password against db
    # intentionally slow, will cache to speed up
    if pw_hash in pw_cache:
        if pw_md5 != pw_cache[pw_hash]: # ~0.1ms
            if glob.config.debug:
                log(f"{session['user_data']['name']}'s change pw failed - pw incorrect.", Ansi.LYELLOW)
            return await flash('error', 'Your old password is incorrect.', 'settings/password')
    else: # ~200ms
        k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend())
        try:
            k.verify(pw_hash, pw_md5)
        except:
            if glob.config.debug:
                log(f"{session['user_data']['name']}'s change pw failed - pw incorrect.", Ansi.LYELLOW)
            return await flash('error', 'Your old password is incorrect.', 'settings/password')

    # remove old password from cache
    if pw_hash in pw_cache:
        del pw_cache[pw_hash]

    # calculate new md5 & bcrypt pw
    pw_md5 = hashlib.md5(new_password.encode()).hexdigest().encode()
    k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend())
    pw_hash_new = k.derive(pw_md5).decode('unicode-escape')

    # update password in cache and db
    pw_cache[pw_hash_new] = pw_md5
    await glob.db.execute(
        'UPDATE users '
        'SET pw = %s '
        'WHERE safe_name = %s',
        [pw_hash_new, utils.get_safe_name(session['user_data']['name'])]
    )

    # logout
    session.pop('authenticated', None)
    session.pop('user_data', None)
    return await flash('success', 'Your password has been changed! Please log in again.', 'login')
Example #36
0
def derive_new_key(key):
    hkdf = HKDFExpand(algorithm=hashes.SHA256(), length=BLOCK_SIZE,
                      info=None, backend=BACKEND)
    return hkdf.derive(key)
Example #37
0
            request.resp_headers['cho-token'] = 'no' # client knows there is something up if we set token to 'no'
            return writer.userID(-1)

        # if server is migrated then passwords are previously stored as bcrypt
        # lets check if we need to convert and do so if needed
        if glob.config.server_migration and ('$' in user['pw'] and len(user['pw']) == 60):
            user_pw = user['pw'].encode()
            if not bcrypt.checkpw(pw, user_pw):
                if glob.config.debug:
                    log(f"{username}'s login attempt failed: provided an incorrect password", Ansi.LRED)

                request.resp_headers['cho-token'] = 'no' # client knows there is something up if we set token to 'no'
                return writer.userID(-1)
            else: # correct password, we allow the user to continue but lets convert the password to our new format first
                k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend())
                new_pw = k.derive(pw).decode('unicode-escape')
                await glob.db.execute('UPDATE users SET pw = %s WHERE id = %s', [new_pw, user['id']])

                # add to cache for the future
                glob.cache['pw'][new_pw] = pw

        else: # password is already converted or db already has correct formats
            bcache = glob.cache['pw'] # get our cached pws to potentially enhance speed
            user_pw = user['pw'].encode('ISO-8859-1').decode('unicode-escape').encode('ISO-8859-1') # this is cursed SHUT UP

            if user_pw in bcache:
                if pw != bcache[user_pw]: # compare provided md5 with the stored (cached) pw to ensure they have provided the correct password
                    if glob.config.debug:
                        log(f"{username}'s login attempt failed: provided an incorrect password", Ansi.LRED)
Example #38
0
 def expand(self, prk, info, L):
     h = self.hash
     hkdf = HKDFExpand(h, L, info, default_backend())
     return hkdf.derive(prk)
Example #39
0
def derivekey(key):
    hkdf = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=None, backend=BACKEND)