Пример #1
0
    def create(self, cb, pwd, user, host, char_classes, size=0):
        if set(char_classes) - {'u', 'l', 's', 'd'}:
            raise ValueError("error: rules can only contain ulsd.")
        try:
            size = int(size)
        except:
            raise ValueError("error: size has to be integer.")
        self.namesite = {'name': user, 'site': host}

        rules = sum(1 << i for i, c in enumerate(('u', 'l', 's', 'd'))
                    if c in char_classes)
        # pack rule
        rule = struct.pack('>H', (rules << 7) | (size & 0x7f))
        # encrypt rule
        sk = self.getkey()
        rk = pysodium.crypto_generichash(sk, self.getsalt())
        nonce = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES)
        rule = nonce + pysodium.crypto_secretbox(rule, nonce, rk)

        b, c = sphinxlib.challenge(pwd)
        message = b''.join([
            CREATE,
            self.getid(host, user), c, rule,
            pysodium.crypto_sign_sk_to_pk(sk)
        ])
        self.doSphinx(message, b, pwd, cb)
Пример #2
0
 def change(self, cb, pwd, user, host):
   b, c = sphinxlib.challenge(pwd)
   self.namesite={'name': user, 'site': host}
   message = b''.join([CHANGE,
                       self.getid(host, user),
                       c])
   self.doSphinx(message, host, b, pwd, cb)
Пример #3
0
def delete(s, pwd, user, host):
    # run sphinx to recover rwd for authentication
    id = getid(host, user)
    r, alpha = sphinxlib.challenge(pwd)
    msg = b''.join([DELETE, id, alpha])
    s.send(msg)  # alpha
    rwd = auth(s, id, pwd, r)

    # delete user from user list for this host
    # a malicous server could correlate all accounts on this services to this users here
    # first query user record for this host
    id = getid(host, '')
    s.send(id)
    # wait for user blob
    bsize = s.recv(2)
    bsize = struct.unpack('!H', bsize)[0]
    if bsize == 0:
        # this should not happen, it means something is corrupt
        print("error: server has no associated user record for this host")
        return

    blob = s.recv(bsize)
    # todo handle this
    if blob == b'fail':
        return
    blob = decrypt_blob(blob)
    users = set(blob.decode().split('\x00'))
    # todo/fix? we do not recognize if the user is already included in this list
    # this should not happen, but maybe it's a sign of corruption?
    users.remove(user)
    blob = ('\x00'.join(sorted(users))).encode()
    # notice we do not add rwd to encryption of user blobs
    blob = encrypt_blob(blob)
    bsize = len(blob)
    if bsize >= 2**16:
        raise ValueError("error: blob is bigger than 64KB.")
    blob = struct.pack("!H", bsize) + blob
    blob = sign_blob(blob, id, b'')

    s.send(blob)

    if b'ok' != s.recv(2):
        return

    clearmem(rwd)
    return True
Пример #4
0
def doSphinx(s, op, pwd, user, host):
    id = getid(host, user)
    r, alpha = sphinxlib.challenge(pwd)
    msg = b''.join([op, id, alpha])
    s.send(msg)
    if op != GET:  # == CHANGE, UNDO, COMMIT
        # auth: do sphinx with current seed, use it to sign the nonce
        auth(s, id, pwd, r)

    resp = s.recv(32 + RULE_SIZE)  # beta + sealed rules
    if resp == b'\x00\x04fail' or len(resp) != 32 + RULE_SIZE:
        raise ValueError("error: sphinx protocol failure.")
    beta = resp[:32]
    rules = resp[32:]
    rwd = sphinxlib.finish(pwd, r, beta, id)

    try:
        classes, size = unpack_rule(rules)
    except ValueError:
        return
    if op != GET:  # == CHANGE, UNDO, COMMIT
        # in case of undo/commit we also need to rewrite the rules and pub auth signing key blob
        if op in {UNDO, COMMIT}:
            sk, pk = get_signkey(id, rwd)
            clearmem(sk)
            rule = encrypt_blob(pack_rule(classes, size))

            # send over new signed(pubkey, rule)
            msg = b''.join([pk, rule])
            msg = sign_blob(msg, id, rwd)
            s.send(msg)
            if s.recv(2) != b'ok':
                print(
                    "ohoh, something is corrupt, and this is a bad, very bad error message in so many ways"
                )
                return

    ret = bin2pass.derive(pysodium.crypto_generichash(PASS_CTX, rwd), classes,
                          size).decode()
    clearmem(rwd)

    return ret
Пример #5
0
def create(s, pwd, user, host, char_classes, size=0):
    # 1st step OPRF on the new seed
    id = getid(host, user)
    r, alpha = sphinxlib.challenge(pwd)
    msg = b''.join([CREATE, id, alpha])
    s.send(msg)

    # wait for response from sphinx server
    beta = s.recv(32)
    if beta == b'\x00\x04fail':
        raise ValueError("error: sphinx protocol failure.")
    rwd = sphinxlib.finish(pwd, r, beta, id)

    # second phase, derive new auth signing pubkey
    sk, pk = get_signkey(id, rwd)
    clearmem(sk)

    try:
        size = int(size)
    except:
        raise ValueError("error: size has to be integer.")
    rule = encrypt_blob(pack_rule(char_classes, size))

    # send over new signed(pubkey, rule)
    msg = b''.join([pk, rule])
    msg = sign_blob(msg, id, rwd)
    s.send(msg)

    # add user to user list for this host
    # a malicous server could correlate all accounts on this services to this users here
    update_rec(s, host, user)

    ret = bin2pass.derive(pysodium.crypto_generichash(PASS_CTX, rwd),
                          char_classes, size).decode()
    clearmem(rwd)
    return ret