예제 #1
0
def init(device_id, password, owner_id, action_names):
    table = get_tinydb_table(path, 'device')
    table.upsert(
        {
            'id': device_id,
            'password': password,
            "owner_id": owner_id,
            "actions": action_names
        },
        Query().id.exists())
    db = TinyDB(path)
    db.purge_table('users')
    table = get_tinydb_table(path, 'users')
    table.insert({'integrity': init_integrity_data(), "id": int(owner_id)})
예제 #2
0
def create_device_type(description, token):
    if len(get_tinydb_table(path, 'device_type_keys')) == 0:
        init_device_type_keys()
    table = get_tinydb_table(path, 'device_type_keys')
    doc = table.all()[0]
    desc_ciphertext = encrypt_using_fernet_hex(doc["description"], description)
    data = {
        "description": desc_ciphertext,
        "correctness_hash": correctness_hash(description)
    }
    r = requests.post(URL_CREATE_DEVICE_TYPE,
                      headers={"Authorization": token},
                      data=data,
                      verify=VERIFY_CERTS)
    click.echo(r.content.decode('unicode-escape'))
예제 #3
0
def save_column_keys(data):
    """ Can be trigger by: `./cli.py -b "172.26.0.8" user send-column-keys 1 23` """
    try:
        if bool(re.search('\"\w+:\w+\"', data)):

            data = json.loads(data)
            if get_owner_id() != int(data["user_id"]):
                click.echo("This command is only available for device owner.")
                return
            table = get_tinydb_table(path, 'users')
            doc = table.all()[0]
            data.pop("user_id", None)

            fernet_key = hex_to_fernet(doc["shared_key"])
            keys = {}
            for k, v in data.items():
                if k == "device_data:data":
                    keys[k] = json.loads(
                        fernet_key.decrypt(data[k].encode()).decode())
                else:
                    keys[k] = key_to_hex(fernet_key.decrypt(data[k].encode()))

            doc = {**doc, **keys}
            table.update(doc)

    except Exception as e:  # pragma: no exc cover
        _, _, exc_tb = sys.exc_info()
        line = exc_tb.tb_lineno
        click.echo(f"{repr(e)} at line: {line}")
예제 #4
0
def send_key_to_device(device_id, token):
    if not is_device_bi_key_missing(
            device_id, create_device,
            "Blind index key for device name is missing"):
        private_key = ec.generate_private_key(ec.SECP384R1(),
                                              default_backend())
        public_key = private_key.public_key()
        public_pem = public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(
                'utf-8')

        private_pem = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()).decode()
        table = get_tinydb_table(path, 'device_keys')
        table.upsert(
            {
                'device_id': device_id,
                'public_key': public_pem,
                'private_key': private_pem,
                'bi_key': key_to_hex(get_device_bi_key(device_id))
            },
            Query().device_id == device_id)

        data = {'device_id': device_id, 'public_key': public_pem}
        r = requests.post(URL_START_KEY_EXCHANGE,
                          headers={"Authorization": token},
                          data=data,
                          verify=VERIFY_CERTS)
        click.echo(r.content.decode('unicode-escape'))
예제 #5
0
def attr_auth_device_keygen(device_id, attr_list, token):
    if device_id not in " ".join(attr_list):
        click.echo(
            f"attr_list argument should contain device_id ({device_id})")
        return
    doc = search_tinydb_doc(path, 'aa_keys', where('public_key').exists())
    if not doc:
        with click.Context(get_attr_auth_keys) as ctx:
            click.echo(
                f"Public key not present, please use: {ctx.command.name}")
            click.echo(get_attr_auth_keys.get_help(ctx))
            return

    data = {"attr_list": " ".join(attr_list)}
    r = requests.post(AA_URL_DEVICE_KEYGEN,
                      headers={"Authorization": token},
                      data=data,
                      verify=VERIFY_CERTS)
    content = r.content.decode('unicode-escape')
    json_content = json_string_with_bytes_to_dict(content)
    if not json_content["success"]:
        click.echo(json_content)
        return

    t = get_tinydb_table(path, "device_keys")
    device_data_doc = {
        "private_key": json_content["private_key"],
        "attr_list": attr_list,
    }
    t.update(set("device_data:data", device_data_doc),
             Query().device_id == device_id)
예제 #6
0
def init_scene_keys():
    table = get_tinydb_table(path, 'scene_keys')
    table.upsert(
        {
            'name': key_to_hex(os.urandom(32)),
            'description': key_to_hex(os.urandom(32))
        },
        where('name').exists() & where('description').exists())
예제 #7
0
def init_global_keys():
    table = get_tinydb_table(path, 'global')
    table.upsert(
        {
            'bi_key': key_to_hex(os.urandom(32)),
            'scene_key': key_to_hex(os.urandom(32)),
        },
        where('bi_key').exists() & where('scene_key').exists())
예제 #8
0
def create_scene(name, description, token):
    if not is_global_bi_key_missing(
            init_global_keys, "Blind index key for scene name is missing"):
        if len(get_tinydb_table(path, 'scene_keys')) == 0:
            init_scene_keys()
        table = get_tinydb_table(path, 'scene_keys')
        doc = table.all()[0]
        name_ciphertext = encrypt_using_fernet_hex(doc["name"], name)
        desc_ciphertext = encrypt_using_fernet_hex(doc["description"],
                                                   description)
        data = {
            "name": name_ciphertext,
            "correctness_hash": correctness_hash(name),
            "name_bi": blind_index(get_global_bi_key(), name),
            "description": desc_ciphertext
        }
        r = requests.post(URL_CREATE_SCENE,
                          headers={"Authorization": token},
                          data=data,
                          verify=VERIFY_CERTS)
        click.echo(r.content.decode('unicode-escape'))
예제 #9
0
def send_column_keys(user_id, device_id, policy):
    table = get_tinydb_table(path, 'device_keys')
    doc = table.get(Query().device_id == device_id)

    if not doc:
        with click.Context(send_key_to_device) as ctx:
            click.echo(
                f"Keys for device {device_id} not present, please use: {ctx.command.name}"
            )
            click.echo(get_attr_auth_keys.get_help(ctx))
            return

    fernet_key = hex_to_fernet(doc["shared_key"])

    keys = {
        "action:name": None,
        "device_data:added": None,
        "device_data:num_data": None,
        "device_data:tid": None
    }

    payload_keys = {}
    for k in keys:
        random_bytes = os.urandom(32)
        keys[k] = key_to_hex(
            random_bytes)  # NOTE: retrieve key as `key_to_hex(key)`
        payload_keys[k] = fernet_key.encrypt(random_bytes).decode()

    # payload_keys["device_data:data"] = fernet_key.encrypt(get_aa_public_key().encode()).decode()
    abe_key_and_policy = json.dumps({
        "public_key": get_aa_public_key(),
        "policy": policy
    }).encode()

    payload_keys["device_data:data"] = fernet_key.encrypt(
        abe_key_and_policy).decode()
    payload_keys["device:name"] = fernet_key.encrypt(
        hex_to_key(doc["device:name"])).decode()
    payload_keys["device:status"] = fernet_key.encrypt(
        hex_to_key(doc["device:status"])).decode()
    payload_keys["bi_key"] = fernet_key.encrypt(hex_to_key(
        doc["bi_key"])).decode()
    payload_keys["scene_key"] = fernet_key.encrypt(
        get_global_scene_key()).decode()

    doc = {**doc, **keys}
    table.upsert(doc, Query().device_id == device_id)

    client = _setup_client(user_id)
    payload = f'"{json.dumps(_create_payload(payload_keys, user_id))}"'
    ret = client.publish(f"u:{user_id}/d:{device_id}/", payload)
    click.echo(f"RC and MID = {ret}")
예제 #10
0
def get_attr_auth_keys(token):
    r = requests.get(AA_URL_SETUP,
                     headers={"Authorization": token},
                     verify=VERIFY_CERTS)
    content = json.loads(r.content.decode('unicode-escape'))
    click.echo(f"Saving keys to {path}")
    table = get_tinydb_table(path, 'aa_keys')
    doc = table.get(where('public_key').exists())
    data = {"public_key": content["public_key"]}
    if doc:
        table.update(data)
    else:
        table.insert(data)
예제 #11
0
def retrieve_device_public_key(device_id, token):
    data = {"device_id": device_id}

    table = get_tinydb_table(path, 'device_keys')
    doc = table.get(Query().device_id == device_id)

    if not doc:
        with click.Context(send_key_to_device) as ctx:
            click.echo(
                f"Keys for device {device_id} not present, please use: {ctx.command.name}"
            )
            click.echo(get_attr_auth_keys.get_help(ctx))
            return

    r = requests.post(URL_RECEIVE_PUBLIC_KEY,
                      headers={"Authorization": token},
                      data=data,
                      verify=VERIFY_CERTS)
    if r.status_code != 200:
        click.echo(r.content.decode('unicode-escape'))
        return

    content = r.content.decode('unicode-escape')
    json_content = json_string_with_bytes_to_dict(content)

    private_key = load_pem_private_key(doc["private_key"].encode(),
                                       password=None,
                                       backend=default_backend())
    assert isinstance(
        private_key, EllipticCurvePrivateKey
    ), "Loading private key failed! - private_key is not instance of EllipticCurvePrivateKey"
    device_public_key = load_pem_public_key(
        json_content["device_public_key"].encode(), backend=default_backend())
    assert isinstance(
        device_public_key, EllipticCurvePublicKey
    ), "Loading public key failed! - private_key is not instance of EllipticCurvePublicKey"
    shared_key = private_key.exchange(ec.ECDH(), device_public_key)

    derived_key = HKDF(algorithm=hashes.SHA256(),
                       length=32,
                       salt=None,
                       info=b'handshake data',
                       backend=default_backend()).derive(shared_key)

    key = key_to_hex(derived_key)  # NOTE: retrieve key as `key_to_hex(key)`

    table.update(delete("public_key"), Query().device_id == device_id)
    table.update(delete("private_key"), Query().device_id == device_id)
    table.update(set("shared_key", key), Query().device_id == device_id)
예제 #12
0
def register_to_broker(password, token):
    password_hash = pbkdf2_hash(password)
    data = {"password": password_hash}
    r = requests.post(URL_REGISTER_TO_BROKER,
                      headers={"Authorization": token},
                      data=data,
                      verify=VERIFY_CERTS)
    content = json.loads(r.content.decode('unicode-escape'))
    table = get_tinydb_table(path, 'credentials')
    table.upsert(
        {
            "broker_id": content["broker_id"],
            "broker_password": password
        },
        Query().broker_id == content["broker_id"])
    click.echo(r.content.decode('unicode-escape'))
예제 #13
0
def receive_pk(data):
    try:
        if "user_public_key" in data:
            json_data = json.loads(data.replace("'", '"'), strict=False)

            pk_user_pem = json.dumps(json_data['user_public_key'])
            user_id = int(json.dumps(json_data['user_id'])[1:-1])

            if get_owner_id() != user_id:
                click.echo("This command is only available for device owner.")
                return

            key = pk_user_pem[1:-1].encode('utf-8').replace(b"\\n", b"\n")
            public_key = load_pem_public_key(key, backend=default_backend())
            assert isinstance(public_key, EllipticCurvePublicKey)

            private_key = ec.generate_private_key(ec.SECP384R1(),
                                                  default_backend())
            shared_key = private_key.exchange(ec.ECDH(), public_key)
            derived_key = HKDF(algorithm=hashes.SHA256(),
                               length=32,
                               salt=None,
                               info=b'handshake data',
                               backend=default_backend()).derive(shared_key)

            table = get_tinydb_table(path, 'users')
            key = key_to_hex(
                derived_key)  # NOTE: retrieve key as `key_to_hex(key)`
            table.upsert({
                'id': user_id,
                'shared_key': key,
                'tid': -1
            },
                         Query().id == user_id)

            public_key = private_key.public_key()
            public_pem = public_key.public_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(
                    'utf-8').replace("\n", "\\n")
            payload = f'{{"user_id": {int(user_id)}, "device_public_key": "{public_pem}"}}'
            click.echo(payload)

    except Exception as e:  # pragma: no exc cover
        _, _, exc_tb = sys.exc_info()
        line = exc_tb.tb_lineno
        click.echo(f"{repr(e)} at line: {line}")
예제 #14
0
def get_devices(device_name, device_id, token):
    """Triggered using: ./cli.py -b "172.26.0.8" user get-devices test_device 46 --token 5c36ab84439c55a3c196f4csd9bd7b3d9291f39g"""
    device_name_bi = blind_index(get_device_bi_key(device_id), device_name)
    data = {"name_bi": device_name_bi}
    r = requests.get(URL_GET_DEVICE,
                     headers={"Authorization": token},
                     params=data,
                     verify=VERIFY_CERTS)
    content = json.loads(r.content.decode('unicode-escape'))

    table = get_tinydb_table(path, 'device_keys')

    for device in content["devices"]:
        ciphertext = device["name"]
        doc = table.get(Query().device_id == str(device["id"]))
        plaintext = decrypt_using_fernet_hex(doc["device:name"], ciphertext)
        device["name"] = plaintext.decode()

    check_correctness_hash(content["devices"], "name")
    click.echo(content["devices"])
예제 #15
0
def get_fake_tuple(bound):
    try:
        table = get_tinydb_table(path, 'users')
        doc = get_user_data()

        if bound == "lower_bound" and not can_remove_fake_row(
                doc["integrity"]["device_data"]):
            return  # "Can't remove row that was not yet inserted (lower bound equals upper bound)"

        fake_tuple = {**generate(doc["integrity"]["device_data"], bound=bound)}
        fake_tuple["data"] = pad_payload_attr(str(fake_tuple["data"]),
                                              fake=True)

        keys = get_key_type_pair(doc)

        fake_tuple_hash = correctness_hash([
            fake_tuple["added"], fake_tuple["data"], fake_tuple["num_data"],
            fake_tuple["tid"]
        ])
        encrypted_fake_tuple = encrypt_row(fake_tuple, keys)
        row = {
            **encrypted_fake_tuple, "correctness_hash": fake_tuple_hash,
            "tid_bi": blind_index(hex_to_key(get_bi_key()),
                                  str(fake_tuple["tid"]))
        }

        if bound == "upper_bound":
            doc["integrity"]["device_data"] = increment_bounds(
                doc["integrity"]["device_data"])
        if bound == "lower_bound":
            doc["integrity"]["device_data"] = increment_bounds(
                doc["integrity"]["device_data"], bound=bound)

        payload = dict_to_payload(**row)
        table.update(doc)
        click.echo(payload)

    except Exception as e:  # pragma: no exc cover
        _, _, exc_tb = sys.exc_info()
        line = exc_tb.tb_lineno
        click.echo(f"{repr(e)} at line: {line}")
예제 #16
0
def get_global_scene_key():
    table = get_tinydb_table(path, 'global')
    doc_global = table.all()[0]
    return hex_to_key(doc_global["scene_key"])
예제 #17
0
def get_self_id():
    table = get_tinydb_table(path, 'device')
    device_id = table.all()[0]["id"]
    return device_id
예제 #18
0
def get_next_tid():
    table = get_tinydb_table(path, 'users')
    tid = table.all()[0]["tid"]
    table.update(decrement('tid'))
    return tid
예제 #19
0
def get_user_data():
    table = get_tinydb_table(path, 'users')
    return table.all()[0]
예제 #20
0
def get_bi_key():
    table = get_tinydb_table(path, 'users')
    return table.all()[0]["bi_key"]
예제 #21
0
def init_device_type_keys():
    table = get_tinydb_table(path, 'device_type_keys')
    table.upsert({
        'description': key_to_hex(os.urandom(32)),
    },
                 where('description').exists())
예제 #22
0
def get_owner_id():
    table = get_tinydb_table(path, 'device')
    return int(table.all()[0]["owner_id"])