Как безопасно сохранить закрытый ключ PyNaCl (libsodium) на диске в Python (избегайте простых файлов)? [закрыто]Python

Программы на Python
Ответить
Anonymous
 Как безопасно сохранить закрытый ключ PyNaCl (libsodium) на диске в Python (избегайте простых файлов)? [закрыто]

Сообщение Anonymous »

Я создаю небольшой клиент Python для службы FastAPI, которая отправляет одноразовые зашифрованные сообщения. Ключи должны оставаться на клиенте (никогда не отправляться на сервер и не храниться им).
Env/Libraries
  • Python 3.11
  • [PyNaCl] для X25519/box (nacl.public)
  • Необязательно криптография для KDF + AEAD
    Цель
Сохранять долгоживущую пару ключей PyNaCl между запусками. Я хочу, чтобы закрытый ключ хранился на диске и расшифровывался только после того, как пользователь введет парольную фразу (или, альтернативно, используйте связку ключей ОС, если это считается лучшей практикой).
Что я пробовал
  • Запись необработанного 32-байтового закрытого ключа в файл → легко, но явно небезопасно в состоянии покоя.
  • Использование криптографии для получения ключа из парольной фразы (Scrypt) и шифрования закрытый ключ с помощью AES-GCM перед записью на диск. Это работает, но я не уверен насчет рекомендуемых параметров/шаблонов.
  • Использование пакета ключей для хранения закрытого ключа в хранилище учетных данных ОС (Windows DPAPI/macOS Keychain/Secret Service). Это позволяет избежать использования парольных фраз, но я не уверен в переносимости и резервном копировании/восстановлении.
    Минимальное воспроизведение (эскиз)

Код: Выделить всё

# Python 3.11
# pip install pynacl cryptography

from nacl.public import PrivateKey
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
import os, json, base64

# 1) Generate
sk = PrivateKey.generate()
pk = sk.public_key
sk_bytes = bytes(sk)  # 32 bytes
pk_bytes = bytes(pk)  # 32 bytes (saved in clear is fine)

# 2) Derive wrap key from passphrase
def derive_key(passphrase: str, salt: bytes) -> bytes:
kdf = Scrypt(salt=salt, length=32, n=2 ** 15, r=8, p=1,
backend=default_backend())
return kdf.derive(passphrase.encode("utf-8"))

# 3) Encrypt secret key with AES-GCM and store (salt, nonce, ct)
def store_key(sk_bytes: bytes, passphrase: str, path="keystore.json"):
salt = os.urandom(16)
nonce = os.urandom(12)
aead_key = derive_key(passphrase, salt)
ct = AESGCM(aead_key).encrypt(nonce, sk_bytes, associated_data=None)
data = {
"salt": base64.b64encode(salt).decode(),
"nonce": base64.b64encode(nonce).decode(),
"ct": base64.b64encode(ct).decode(),
"pub": base64.b64encode(pk_bytes).decode(),
}
with open(path, "w") as f:
json.dump(data, f)

# 4) Load + decrypt
def load_key(passphrase: str, path="keystore.json") -> bytes:
data = json.load(open(path))
salt = base64.b64decode(data["salt"])
nonce = base64.b64decode(data["nonce"])
ct = base64.b64decode(data["ct"])
aead_key = derive_key(passphrase, salt)
sk_bytes = AESGCM(aead_key).decrypt(nonce, ct, associated_data=None)
return sk_bytes

# Usage:
# store_key(sk_bytes, "my passphrase")
# recovered = load_key("my passphrase")
# assert recovered == sk_bytes
Вопросы
  • Является ли «ключ, полученный из Scrypt + упаковка AES-GCM, а затем сохранение JSON в файле» разумным шаблоном для сохранения ключа на стороне клиента с помощью PyNaCl? Какие-либо рекомендуемые параметры Scrypt для настольных компьютеров в 2025 году?
  • Рекомендуете ли вы вместо этого использовать связку ключей ОС через связку ключей (и если да, то как безопасно и портативно хранить 32 необработанных байта)?
  • Есть ли подводные камни с ключами X25519 в PyNaCl при такой сериализации/десериализации?
    Ограничения
    Я не могу хранить секреты на сервер. Можно запросить у пользователя парольную фразу при запуске; никаких инфраструктур пользовательского интерфейса не требуется.
    Ожидается:
    руководство или пример кода, демонстрирующий рекомендуемый подход (файл с парольной фразой или связка ключей ОС) и выбор параметров (стоимость шифрования, обработка nonce AES-GCM и т. д.).


Подробнее здесь: https://stackoverflow.com/questions/798 ... ython-avoi
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»