mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-04 07:03:44 +08:00
08e85808c5
# Conflicts: # .github/workflows/ci_weekly_run.yaml # .github/workflows/raylib_ui_preview.yaml # .github/workflows/tests.yaml # .gitmodules # README.md # SConstruct # common/api.py # common/params_keys.h # docs/CARS.md # msgq_repo # opendbc_repo # panda # selfdrive/car/tests/test_car_interfaces.py # selfdrive/controls/controlsd.py # selfdrive/controls/lib/latcontrol.py # selfdrive/controls/lib/latcontrol_angle.py # selfdrive/controls/lib/latcontrol_pid.py # selfdrive/controls/lib/latcontrol_torque.py # selfdrive/controls/tests/test_latcontrol.py # selfdrive/monitoring/helpers.py # selfdrive/ui/SConscript # selfdrive/ui/main.cc # selfdrive/ui/qt/body.h # selfdrive/ui/qt/home.cc # selfdrive/ui/qt/home.h # selfdrive/ui/qt/network/networking.cc # selfdrive/ui/qt/network/networking.h # selfdrive/ui/qt/network/wifi_manager.cc # selfdrive/ui/qt/offroad/developer_panel.cc # selfdrive/ui/qt/offroad/developer_panel.h # selfdrive/ui/qt/offroad/experimental_mode.cc # selfdrive/ui/qt/offroad/firehose.cc # selfdrive/ui/qt/offroad/firehose.h # selfdrive/ui/qt/offroad/onboarding.cc # selfdrive/ui/qt/offroad/onboarding.h # selfdrive/ui/qt/offroad/settings.cc # selfdrive/ui/qt/offroad/settings.h # selfdrive/ui/qt/offroad/software_settings.cc # selfdrive/ui/qt/onroad/alerts.cc # selfdrive/ui/qt/onroad/annotated_camera.h # selfdrive/ui/qt/onroad/buttons.cc # selfdrive/ui/qt/onroad/buttons.h # selfdrive/ui/qt/onroad/driver_monitoring.cc # selfdrive/ui/qt/onroad/hud.cc # selfdrive/ui/qt/onroad/hud.h # selfdrive/ui/qt/onroad/model.cc # selfdrive/ui/qt/onroad/model.h # selfdrive/ui/qt/onroad/onroad_home.cc # selfdrive/ui/qt/onroad/onroad_home.h # selfdrive/ui/qt/request_repeater.h # selfdrive/ui/qt/sidebar.cc # selfdrive/ui/qt/sidebar.h # selfdrive/ui/qt/util.cc # selfdrive/ui/qt/widgets/cameraview.h # selfdrive/ui/qt/widgets/controls.cc # selfdrive/ui/qt/widgets/controls.h # selfdrive/ui/qt/widgets/input.cc # selfdrive/ui/qt/widgets/input.h # selfdrive/ui/qt/widgets/prime.cc # selfdrive/ui/qt/widgets/prime.h # selfdrive/ui/qt/widgets/ssh_keys.h # selfdrive/ui/qt/widgets/toggle.h # selfdrive/ui/qt/widgets/wifi.cc # selfdrive/ui/qt/widgets/wifi.h # selfdrive/ui/qt/window.cc # selfdrive/ui/qt/window.h # selfdrive/ui/tests/cycle_offroad_alerts.py # selfdrive/ui/tests/test_ui/run.py # selfdrive/ui/translations/main_ar.ts # selfdrive/ui/translations/main_de.ts # selfdrive/ui/translations/main_es.ts # selfdrive/ui/translations/main_fr.ts # selfdrive/ui/translations/main_ja.ts # selfdrive/ui/translations/main_ko.ts # selfdrive/ui/translations/main_nl.ts # selfdrive/ui/translations/main_pl.ts # selfdrive/ui/translations/main_pt-BR.ts # selfdrive/ui/translations/main_th.ts # selfdrive/ui/translations/main_tr.ts # selfdrive/ui/translations/main_zh-CHS.ts # selfdrive/ui/translations/main_zh-CHT.ts # selfdrive/ui/ui.cc # selfdrive/ui/ui.h # system/manager/build.py # system/version.py
171 lines
5.0 KiB
Python
171 lines
5.0 KiB
Python
"""
|
|
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|
|
|
This file is part of sunnypilot and is licensed under the MIT License.
|
|
See the LICENSE.md file in the root directory for more details.
|
|
"""
|
|
|
|
import base64
|
|
import hashlib
|
|
import zlib
|
|
import re
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from cryptography.hazmat.backends import default_backend
|
|
from cryptography.hazmat.primitives import serialization
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
|
|
from openpilot.sunnypilot.sunnylink.backups.AESCipher import AESCipher
|
|
from openpilot.system.hardware.hw import Paths
|
|
|
|
|
|
class KeyDerivation:
|
|
@staticmethod
|
|
def _load_key(file_path: str) -> bytes:
|
|
with open(file_path, 'rb') as f:
|
|
return f.read()
|
|
|
|
@staticmethod
|
|
def derive_aes_key_iv_from_rsa(key_path: str, use_aes_256: bool) -> tuple[bytes, bytes]:
|
|
rsa_key_pem: bytes = KeyDerivation._load_key(key_path)
|
|
key_plain = rsa_key_pem.decode(errors="ignore")
|
|
|
|
if "private" in key_plain.lower():
|
|
private_key = serialization.load_pem_private_key(rsa_key_pem, password=None, backend=default_backend())
|
|
if not isinstance(private_key, rsa.RSAPrivateKey):
|
|
raise ValueError("Invalid RSA key format: Unable to determine if key is public or private.")
|
|
|
|
der_data = private_key.private_bytes(
|
|
encoding=serialization.Encoding.DER,
|
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
encryption_algorithm=serialization.NoEncryption()
|
|
)
|
|
elif "public" in key_plain.lower():
|
|
public_key = serialization.load_pem_public_key(rsa_key_pem, backend=default_backend())
|
|
if not isinstance(public_key, rsa.RSAPublicKey):
|
|
raise ValueError("Invalid RSA key format: Unable to determine if key is public or private.")
|
|
|
|
der_data = public_key.public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.PKCS1)
|
|
else:
|
|
raise ValueError("Unknown key format: Unable to determine if key is public or private.")
|
|
|
|
sha256_hash = hashlib.sha256(der_data).digest()
|
|
aes_key = sha256_hash[:32] if use_aes_256 else sha256_hash[:16]
|
|
aes_iv = sha256_hash[16:32]
|
|
|
|
return aes_key, aes_iv
|
|
|
|
|
|
def qUncompress(data):
|
|
"""
|
|
Decompress data using zlib.
|
|
|
|
Args:
|
|
data (bytes): Compressed data
|
|
|
|
Returns:
|
|
bytes: Decompressed data
|
|
"""
|
|
data_stripped_4 = data[4:]
|
|
return zlib.decompress(data_stripped_4)
|
|
|
|
|
|
def qCompress(data):
|
|
"""
|
|
Compress data using zlib.
|
|
|
|
Args:
|
|
data (bytes): Data to compress
|
|
|
|
Returns:
|
|
bytes: Compressed data
|
|
"""
|
|
compressed_data = zlib.compress(data, level=9)
|
|
return b"ZLIB" + compressed_data
|
|
|
|
|
|
def decrypt_compressed_data(encrypted_base64, use_aes_256=False):
|
|
"""
|
|
Decrypt and decompress data from base64 string.
|
|
|
|
Args:
|
|
encrypted_base64 (str): Base64 encoded encrypted data
|
|
key_path (str, optional): Path to RSA public key
|
|
|
|
Returns:
|
|
str: Decrypted and decompressed string
|
|
"""
|
|
key_path = Path(f"{Paths.persist_root()}/comma/id_rsa") if use_aes_256 else Path(f"{Paths.persist_root()}/comma/id_rsa.pub")
|
|
try:
|
|
# Decode base64
|
|
encrypted_data = base64.b64decode(encrypted_base64)
|
|
|
|
# Decrypt
|
|
key, iv = KeyDerivation.derive_aes_key_iv_from_rsa(str(key_path), use_aes_256)
|
|
cipher = AESCipher(key, iv)
|
|
decrypted_data = cipher.decrypt(encrypted_data)
|
|
|
|
# Decompress
|
|
decompressed_data = qUncompress(decrypted_data)
|
|
|
|
# Decode UTF-8
|
|
result = decompressed_data.decode('utf-8')
|
|
return result
|
|
except Exception as e:
|
|
print(f"Decryption and decompression failed: {e}")
|
|
return ""
|
|
|
|
|
|
def encrypt_compress_data(text, use_aes_256=True):
|
|
"""
|
|
Compress and encrypt string data to base64.
|
|
|
|
Args:
|
|
text (str): Text to compress and encrypt
|
|
key_path (str, optional): Path to RSA public key
|
|
|
|
Returns:
|
|
str: Base64 encoded encrypted data
|
|
"""
|
|
key_path = Path(f"{Paths.persist_root()}/comma/id_rsa") if use_aes_256 else Path(f"{Paths.persist_root()}/comma/id_rsa.pub")
|
|
try:
|
|
# Encode to UTF-8
|
|
text_bytes = text.encode('utf-8')
|
|
|
|
# Compress
|
|
compressed_data = qCompress(text_bytes)
|
|
|
|
# Encrypt
|
|
key, iv = KeyDerivation.derive_aes_key_iv_from_rsa(str(key_path), use_aes_256)
|
|
cipher = AESCipher(key, iv)
|
|
encrypted_data = cipher.encrypt(compressed_data)
|
|
|
|
# Encode to base64
|
|
result = base64.b64encode(encrypted_data).decode('utf-8')
|
|
return result
|
|
except Exception as e:
|
|
print(f"Compression and encryption failed: {e}")
|
|
return ""
|
|
|
|
|
|
def camel_to_snake(name):
|
|
"""Convert camelCase to snake_case."""
|
|
name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
|
|
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()
|
|
|
|
|
|
def transform_dict(obj):
|
|
"""Recursively transform dictionary keys from camelCase to snake_case."""
|
|
if isinstance(obj, dict):
|
|
return {camel_to_snake(k): transform_dict(v) for k, v in obj.items()}
|
|
elif isinstance(obj, list):
|
|
return [transform_dict(item) for item in obj]
|
|
return obj
|
|
|
|
|
|
class SnakeCaseEncoder(json.JSONEncoder):
|
|
def encode(self, obj):
|
|
transformed_obj = transform_dict(obj)
|
|
return super().encode(transformed_obj)
|