Зашифровать payload#
Алгоритм принадлежит приложению.
Eazy SDK задаёт порядок преобразований, но не поставляет cipher, keyring или KMS-клиент. Алгоритм, ключи, nonce и их ротация остаются в приложении.
# examples/mail/http/encryption.py
MAIL_CRYPTO = payload_crypto(
"mail-send-v1",
outbound=encrypt_outbound(
encrypt_field(NewMessage, lambda message: message.subject, using=FIELD_CIPHER),
encrypt_field(NewMessage, lambda message: message.body, using=FIELD_CIPHER),
encoded=encrypt_encoded(
using=BODY_CIPHER,
max_input_bytes=16_000,
max_output_bytes=24_000,
),
),
inbound=decrypt_inbound(
encoded=decrypt_encoded(
using=BODY_CIPHER,
max_input_bytes=24_000,
max_output_bytes=16_000,
)
),
)
MAIL_WIRE = http_encrypted(
content_type=MAIL_ENCRYPTED_CONTENT_TYPE,
clear_content_type="application/json",
plaintext_statuses=frozenset({401, 403}),
)
Профиль сначала шифрует выбранные поля модели, затем JSON-кодек создаёт байты и
encrypt_encoded(...) шифрует тело целиком. Входящий ответ проходит обратные стадии.
# examples/mail/http/encryption.py
@dataclass(frozen=True, slots=True, kw_only=True)
class SendEncryptedMessage(HttpOperation[SendResult]):
__http__ = Http.post(
"/api/v1/messages/send",
success={200: Json(SendEnvelope)},
errors={200: (Json(RejectedEnvelope), RecipientRejected)},
security=MAIL_BEARER,
signing=MAIL_HMAC,
crypto=MAIL_CRYPTO,
wire=Wire(encrypted=MAIL_WIRE),
)
body: Annotated[NewMessage, JsonBody()]
class EncryptedMailApi(SyncApi):
base_url = "https://mail.example"
send = op(SendEncryptedMessage)
sent = op(FindSent)
http_encrypted(...) объявляет внешний и открытый Content-Type. Статусы из
plaintext_statuses разрешено разбирать без расшифровки; остальные несовпадения закрывают вызов
ошибкой.
# examples/docs/encryption.py
def main() -> None:
message_id, clear_subject = send_encrypted_message()
print(f"message: {message_id}")
print(f"decrypted subject: {clear_subject}")
Запускаемый файл целиком
"""Run the documented field and whole-body encryption profile."""
from examples.mail.http.encryption import send_encrypted_message
# region docs: encryption-run
# examples/docs/encryption.py
def main() -> None:
message_id, clear_subject = send_encrypted_message()
print(f"message: {message_id}")
print(f"decrypted subject: {clear_subject}")
# endregion docs: encryption-run
if __name__ == "__main__":
main()
message: 100
decrypted subject: Секретная встреча
Порядок стадий#
исходящий: модель → поля → кодек → байты → подпись → отправка
входящий: ответ → байты → кодек → поля → проверка модели
Подпись видит ciphertext, если операция использует и шифрование, и signing. Каждая повторная попытка заново выполняет преобразования, поэтому nonce и ciphertext предыдущей попытки не переиспользуются.
Для WebSocket укажите websocket_encrypted(...). Шифрование всего frame обычно требует binary
frame; text разрешён только для алгоритма, который гарантирует валидный UTF-8, тогда как ping,
pong и close остаются управляющими frames и вообще не проходят payload crypto.
Typed metadata для key id или nonce объявляется через CryptoResult и связывается с конкретным
wire-slot. Необъявленное, пропущенное или конфликтующее значение приводит к закрытой ошибке.