def test_keys():
    privkey = PrivateKey()
    pubkey = privkey.public_key()

    message = "Hello World"

    sig = privkey.sign(message.encode("utf-8"))
    pubkey.verify(sig, message.encode("utf-8"))

    c = pubkey.encrypt(message.encode("utf-8"))

    m = privkey.decrypt(c).decode("utf-8")
    assert (m == message)

    privkey2 = PrivateKey()
    sig2 = privkey2.sign(message.encode("utf-8"))

    with pytest.raises(SignatureVerificationError):
        pubkey.verify(sig2, message.encode("utf-8"))

    bytes = privkey.bytes("testPass32")

    PrivateKey.read_bytes(bytes, "testPass32")

    privkey.write("test.pem", "testPass32")

    PrivateKey.read("test.pem", "testPass32")

    bytes = pubkey.bytes()
    pubkey2 = PublicKey.read_bytes(bytes)

    assert (bytes == pubkey2.bytes())

    long_message = str([random.getrandbits(8)
                        for _ in range(4096)]).encode("utf-8")

    c = pubkey.encrypt(long_message)

    m = privkey.decrypt(c)

    assert (m == long_message)

    os.unlink("test.pem")

    data = pubkey.to_data()

    pubkey2 = PublicKey.from_data(data)

    assert (pubkey.bytes() == pubkey2.bytes())

    data = privkey.to_data("testPass33")

    privkey2 = PrivateKey.from_data(data, "testPass33")

    assert (privkey == privkey2)
    def validate_password(self, password, otpcode, remember_device=False,
                          device_secret=None):
        """Validate that the passed password and one-time-code are valid.
           If they are, then do nothing. Otherwise raise an exception.
           If 'remember_device' is true, then this returns the provisioning
           uri needed to initialise the OTP code for this account
        """
        if not self.is_active():
            raise UserValidationError(
                "Cannot validate against an inactive account")

        # see if we can decrypt the private key using the password
        privkey = _PrivateKey.read_bytes(self._privkey, password)

        if device_secret:
            # decrypt the passed device secret and check the supplied
            # otpcode for that...
            otp = _OTP.decrypt(_string_to_bytes(device_secret), privkey)
            otp.verify(otpcode)
        else:
            # now decrypt the secret otp and validate the supplied otpcode
            otp = _OTP.decrypt(self._otp_secret, privkey)
            otp.verify(otpcode)

        if remember_device:
            # create a new OTP that is unique for this device and return
            # this together with the provisioning code
            otp = _OTP()
            otpsecret = _bytes_to_string(otp.encrypt(privkey.public_key()))
            return (otpsecret, otp.provisioning_uri(self.username()))
Beispiel #3
0
    def _get_wallet_key(self):
        """Return the private key used to encrypt everything in the wallet.
           This will ask for the users password
        """
        if self._wallet_key:
            return self._wallet_key

        wallet_dir = ServiceWallet._wallet_dir()

        keyfile = "%s/wallet_key.pem" % wallet_dir

        if not _os.path.exists(keyfile):
            self._wallet_key = self._create_wallet_key(keyfile)
            return self._wallet_key

        # read the keyfile and decrypt
        with open(keyfile, "rb") as FILE:
            bytes = FILE.read()

        # get the user password
        wallet_key = None
        while not wallet_key:
            password = _getpass.getpass(
                prompt="Please enter your wallet password: "******"Invalid password. Please try again.")

        self._wallet_key = wallet_key
        return wallet_key
Beispiel #4
0
    def reset_admin_password(self, password, otpcode, new_password):
        """Change the admin password for this service. Note that
           you must pass in a valid password and otpcode to make the change"""

        self.verify_admin_user(password, otpcode)

        if password == new_password:
            return

        key = _PrivateKey.read_bytes(self._admin_password, password)
        otp = _OTP.decrypt(self._otpsecret, key)
        otp.verify(otpcode)

        newkey = _PrivateKey()
        self._admin_password = newkey.bytes(new_password)
        self._otpsecret = otp.encrypt(newkey.public_key())
Beispiel #5
0
    def verify_admin_user(self, password, otpcode, remember_device=False):
        """Verify that we are the admin user verifying that
           the passed password and otpcode are correct. This does
           nothing if they are correct, but raises an exception
           if they are wrong. If 'remember_device' this this returns
           the provisioning_uri for the OTP generator"""

        try:
            key = _PrivateKey.read_bytes(self._admin_password, password)
        except Exception as e:
            raise ServiceError("Could not log into admin account: %s" % str(e))

        try:
            otp = _OTP.decrypt(self._otpsecret, key)
            otp.verify(otpcode)
            if remember_device:
                return otp.provisioning_uri("admin", self.service_url())
        except Exception as e:
            raise ServiceError("Could not log into admin account: %s" % str(e))
Beispiel #6
0
def run(args):
    """This function will allow a user to register an account with a
       username and password"""

    status = 0
    message = None
    provisioning_uri = None

    username = args["username"]
    password = args["password"]

    # generate a sanitised version of the username
    user_account = UserAccount(username)

    # generate the encryption keys and otp secret
    privkey = PrivateKey()
    pubkey = privkey.public_key()
    otp = OTP()

    provisioning_uri = otp.provisioning_uri(username)

    # save the encrypted private key (encrypted using the user's password)
    # and encrypted OTP secret (encrypted using the public key)
    user_account.set_keys(privkey.bytes(password), pubkey.bytes(),
                          otp.encrypt(pubkey))

    # remove the key and password from memory
    privkey = None
    password = None

    # now log into the central identity account to either register
    # the user, or to update to a new password
    bucket = login_to_service_account()
    account_key = "accounts/%s" % user_account.sanitised_name()

    try:
        existing_data = ObjectStore.get_object_from_json(bucket,
                                                         account_key)
    except:
        existing_data = None

    message = "Created a new account for '%s'" % username
    status = 0

    if existing_data is None:
        # save the new account details
        ObjectStore.set_object_from_json(bucket, account_key,
                                         user_account.to_data())

        # need to update the "whois" database with the uuid of this user
        ObjectStore.set_string_object(bucket,
                                      "whois/%s" % user_account.uuid(),
                                      user_account.username())
    else:
        # The account already exists. See if this is a password change
        # request
        old_password = None

        try:
            old_password = args["old_password"]
        except:
            raise ExistingAccountError(
                "An account by this name already exists!")

        if old_password != password:
            # this is a change of password request - validate that
            # the existing password unlocks the existing key
            user_account = UserAccount.from_data(existing_data)

            testkey = PrivateKey.read_bytes(user_account.private_key(),
                                            old_password)

            # decrypt the old secret
            old_secret = testkey.decrypt(user_account.otp_secret())

            # now encrypt the secret with the new key
            new_key = PublicKey.read_bytes(pubkey)
            new_secret = new_key.encrypt(old_secret)

            user_account.set_keys(privkey, pubkey, new_secret)

            # save the new account details
            ObjectStore.set_object_from_json(bucket, account_key,
                                             user_account.to_data())

            message = "Updated the password for '%s'" % username
        else:
            message = "No need to change account '%s'" % username

    return_value = create_return_value(status, message)

    if provisioning_uri:
        return_value["provisioning_uri"] = provisioning_uri

    return return_value