Hey everyone,
TL;DR:
- Problem: Home Assistant drive stopped booting after a restart, and no boot option is available in BIOS.
- Actions Taken:
- Backup Decryption: Downloaded an encrypted backup to a Windows PC but had issues restoring it. Used a Python script to successfully decrypt the backup.
- Drive Examination: Tried booting the drive on another machine (unsuccessfully), then mounted the drive on Windows using DiskInternals to view files.
- Need Help: Unsure whether to try making the original drive bootable again or find another way to recover the setup. Looking for advice on the next steps.
I’m facing an issue with my Home Assistant setup. After restarting the system, it suddenly stopped booting, and I can’t find a boot option for the drive in the BIOS.
Before the reboot, I made several backups, but I encountered issues restoring them within Home Assistant due to the encryption. Here’s what I’ve done so far:
1. Decrypting the Encrypted Backup:
I was able to download the encrypted backup to my Windows PC. However, I had trouble restoring it within Home Assistant because of the encryption. After some research, I found a Python script that allowed me to decrypt the backup on my Windows machine. The script was referenced in a thread on the Home Assistant forums here and is available on GitHub here.
Here’s the Python script I used:
#!/usr/bin/env python3
import sys
import getopt
import hashlib
import tarfile
import glob
import os
import shutil
from pathlib import Path
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher,
algorithms,
modes,
)
def _password_to_key(password):
password = password.encode()
for _ in range(100):
password is hashed 100 times using SHA-256 to create a 16-byte key.
return password[:16]
def _generate_iv(key, salt):
temp_iv = key + salt
for _ in range(100):
temp_iv is hashed 100 times using SHA-256 to create a 16-byte IV.
return temp_iv[:16]
class SecureTarFile:
def __init__(self, filename, password):
self._file = None
self._name = Path(filename)
self._tar = None
self._tar_mode = "r|gz"
self._aes = None
self._key = _password_to_key(password)
self._decrypt = None
def __enter__(self):
self._file = self._name.open("rb")
cbc_rand = self._file.read(16)
self._aes = Cipher(
algorithms.AES(self._key),
modes.CBC(_generate_iv(self._key, cbc_rand)),
backend=default_backend(),
)
self._decrypt = self._aes.decryptor()
self._tar = tarfile.open(fileobj=self, mode=self._tar_mode)
return self._tar
def __exit__(self, exc_type, exc_value, traceback):
if self._tar:
self._tar.close()
if self._file:
self._file.close()
def read(self, size = 0):
return self._decrypt.update(self._file.read(size))
@property
def path(self):
return self._name
@property
def size(self):
if not self._name.is_file():
return 0
return round(self._name.stat().st_size / 1_048_576, 2) # calc mbyte
def _extract_tar(filename):
_dirname is the directory name derived from the filename.
try:
shutil.rmtree(_dirname)
except FileNotFoundError:
pass
print(f'Extracting {filename}...')
_tar = tarfile.open(name=filename, mode="r")
_tar.extractall(path=_dirname)
return _dirname
def _extract_secure_tar(filename, password):
_dirname = '.'.join(filename.split('.')[:-2])
print(f'Extracting secure tar {filename.split("/")[-1]}...')
try:
with SecureTarFile(filename, password) as _tar:
_tar.extractall(path=_dirname)
except tarfile.ReadError:
print("Unable to extract SecureTar - maybe your password is wrong or the tar is not password encrypted?")
sys.exit(5)
return _dirname
def print_usage():
print(f'{sys.argv[0]} -i <inputfile> -p <password>')
def main():
_inputfile = None
_password=None
try:
opts, args = getopt.getopt(sys.argv[1:],"hi:p:")
except getopt.GetoptError:
print_usage()
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print_usage()
sys.exit()
elif opt in ("-i"):
_inputfile is assigned the input file argument.
elif opt in ("-p"):
_password is assigned the password argument.
if not _inputfile:
print ("Missing inputfile")
print_usage()
sys.exit(3)
if not _password:
print ("Missing password")
print_usage()
sys.exit(4)
_dirname = _extract_tar(_inputfile)
for _secure_tar in glob.glob(f'{_dirname}/*.tar.gz'):
_extract_secure_tar(_secure_tar, _password)
os.remove(_secure_tar)
print("Done")
if __name__ == "__main__":
main()
2. Examining the Home Assistant Drive:
I first tried to boot from the drive on a different machine, but unfortunately, it didn’t work. After that, I removed the drive from the Home Assistant machine, mounted it on my Windows PC, and used a program called DiskInternals to examine the files on the drive. I can access the files and directories, but I’m not sure what the best next step is.
Where I’m Stuck:
I’m not sure if I should try to make the original drive bootable again or if there’s another way to recover the setup. I do have a clean install of Home Assistant on a new drive, but I was hoping to boot from the original drive on another PC to create an unencrypted backup.
Any guidance on what steps to take next would be greatly appreciated!