def load_device_with_password(key_file: Path, password: str) -> LocalDevice: """ LocalDeviceNotFoundError LocalDeviceCryptoError LocalDeviceValidationError LocalDevicePackingError """ try: ciphertext = key_file.read_bytes() except OSError as exc: raise LocalDeviceNotFoundError( f"Config file `{key_file}` is missing") from exc try: data = key_file_serializer.loads(ciphertext) except LocalDeviceError: data = legacy_key_file_serializer.loads(ciphertext) try: key, _ = derivate_secret_key_from_password(password, data["salt"]) plaintext = key.decrypt(data["ciphertext"]) except CryptoError as exc: raise LocalDeviceCryptoError(str(exc)) from exc try: return LocalDevice.load(plaintext) except DataError as exc: raise LocalDeviceValidationError( f"Cannot load local device: {exc}") from exc
def test_supports_legacy_is_admin_field(alice): # Manually craft a local user in legacy format raw_legacy_local_user = { "organization_addr": alice.organization_addr.to_url(), "device_id": str(alice.device_id), "signing_key": alice.signing_key.encode(), "private_key": alice.private_key.encode(), "is_admin": True, "user_manifest_id": UUID(alice.user_manifest_id.hex), "user_manifest_key": bytes(alice.user_manifest_key.secret), "local_symkey": bytes(alice.local_symkey.secret), } dumped_legacy_local_user = packb(raw_legacy_local_user) # Make sure the legacy format can be loaded legacy_local_user = LocalDevice.load(dumped_legacy_local_user) assert legacy_local_user == alice # Manually decode new format to check it is compatible with legacy dumped_local_user = alice.dump() raw_local_user = unpackb(dumped_local_user) assert raw_local_user == { **raw_legacy_local_user, "profile": alice.profile.value, "human_handle": None, "device_label": None, }
async def load_recovery_device(key_file: PurePath, passphrase: str) -> LocalDevice: """ Raises: LocalDeviceError LocalDeviceNotFoundError LocalDeviceCryptoError LocalDeviceValidationError LocalDevicePackingError """ key_file = trio.Path(key_file) try: ciphertext = await key_file.read_bytes() except OSError as exc: raise LocalDeviceNotFoundError( f"Recovery file `{key_file}` is missing") from exc try: data = key_file_serializer.loads(ciphertext) except LocalDevicePackingError as exc: raise LocalDeviceValidationError("Not a device recovery file") from exc if data["type"] != DeviceFileType.RECOVERY: raise LocalDeviceValidationError("Not a device recovery file") try: key = derivate_secret_key_from_recovery_passphrase(passphrase) except ValueError as exc: # Not really a crypto operation, but it is more coherent for the caller raise LocalDeviceCryptoError("Invalid passphrase") from exc try: plaintext = key.decrypt(data["ciphertext"]) except CryptoError as exc: raise LocalDeviceCryptoError(str(exc)) from exc try: return LocalDevice.load(plaintext) except DataError as exc: raise LocalDeviceValidationError( f"Cannot load local device: {exc}") from exc
def _load_device(key_file: Path, decryptor: BaseLocalDeviceDecryptor) -> LocalDevice: """ Raises: LocalDeviceNotFoundError LocalDeviceCryptoError LocalDeviceValidationError LocalDevicePackingError """ try: ciphertext = key_file.read_bytes() except OSError as exc: raise LocalDeviceNotFoundError( f"Config file {key_file} is missing") from exc raw = decryptor.decrypt(ciphertext) try: return LocalDevice.load(raw) except DataError as exc: raise LocalDeviceValidationError( f"Cannot load local device: {exc}") from exc
def _load_device(key_file: Path, decrypt_ciphertext: Callable[[dict], bytes]) -> LocalDevice: try: ciphertext = key_file.read_bytes() except OSError as exc: raise LocalDeviceNotFoundError( f"Config file `{key_file}` is missing") from exc try: data = key_file_serializer.loads(ciphertext) except LocalDeviceError: data = legacy_key_file_serializer.loads(ciphertext) plaintext = decrypt_ciphertext(data) try: local_device = LocalDevice.load(plaintext) except DataError as exc: raise LocalDeviceValidationError( f"Cannot load local device: {exc}") from exc _KEY_FILE_DATA[local_device.device_id] = data return local_device