1"use strict";(self.webpackChunkiotauth_github_io=self.webpackChunkiotauth_github_io||[]).push([[583],{1367(e,n,s){s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>a,frontMatter:()=>t,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"python-api-reference","title":"Python API Reference","description":"Overview","source":"@site/docs/python-api-reference.md","sourceDirName":".","slug":"/python-api-reference","permalink":"/docs/python-api-reference","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"python-api-reference","title":"Python API Reference","sidebar_label":"Python API Reference"},"sidebar":"docs","previous":{"title":"Node.js API Reference","permalink":"/docs/nodejs-api-reference"},"next":{"title":"Message Types","permalink":"/docs/message-types"}}');var r=s(4848),c=s(8453);const t={id:"python-api-reference",title:"Python API Reference",sidebar_label:"Python API Reference"},o="Python API Reference",d={},l=[{value:"Overview",id:"overview",level:2},{value:"Common setup: <code>IoTAuthContext</code>",id:"common-setup-iotauthcontext",level:2},{value:"Constructors",id:"constructors",level:3},{value:"<code>IoTAuthContext.from_config</code>",id:"iotauthcontextfrom_config",level:4},{value:"1. Create a secure channel",id:"1-create-a-secure-channel",level:2},{value:"<code>SecureClient</code>",id:"secureclient",level:3},{value:"Constructor",id:"constructor",level:4},{value:"<code>connect</code>",id:"connect",level:4},{value:"Client example",id:"client-example",level:4},{value:"<code>SecureServer</code>
1",id:"secureserver",level:3},{value:"Constructor",id:"constructor-1",level:4},{value:"<code>serve_once</code>",id:"serve_once",level:4},{value:"Server example",id:"server-example",level:4},{value:"<code>SecureChannel</code>",id:"securechannel",level:3},{value:"Methods",id:"methods",level:4},{value:"<code>send</code>",id:"send",level:4},{value:"<code>recv</code>",id:"recv",level:4},{value:"<code>close</code>",id:"close",level:4},{value:"2. Manage session keys explicitly",id:"2-manage-session-keys-explicitly",level:2},{value:"<code>IoTAuthContext.request_session_keys</code>",id:"iotauthcontextrequest_session_keys",level:3},{value:"Request and select a key",id:"request-and-select-a-key",level:3},{value:"<code>SessionKeyCache</code>",id:"sessionkeycache",level:3},{value:"<code>SessionKey</code>",id:"sessionkey",level:3},{value:"Buffer cryptography",id:"buffer-cryptography",level:2},{value:"Exceptions",id:"exceptions",level:2}];function h(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,c.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"python-api-reference",children:"Python API Reference"})}),"\n",(0,r.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(n.p,{children:"The Python entity-side API supports two application workflows:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Create a secure channel"})," with ",(0,r.jsx)(n.code,{children:"SecureClient"}),", ",(0,r.jsx)(n.code,{children:"SecureServer"}),", and\n",(0,r.jsx)(n.code,{children:"SecureChannel"}),". This is the recommended workflow for most applications."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Manage session keys explicitly"})," with ",(0,r.jsx)(n.code,{children:"IoTAuthContext.request_session_keys()"}),"\nand ",(0,r.jsx)(n.code,{children:"SessionKeyCache"})," when an application needs to select or reuse keys."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Most applications only need these top-level imports:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"from iotauth import IoTAuthContext, SecureClient, SecureServer, SecureChannel, IoTAuthError\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"iotauth"})," package root intentionally exposes only the application-facing\nclient, server, channel, context, configuration and key models, and public\nexceptions. Low-level protocol, cryptography, handshake, serialization,\ntransport, and credential helpers remain available from their dedicated\nmodules and are not top-level imports. For example:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"from iotauth.protocol import IoTSPFrame, MessageType, parse_frame\nfrom iotauth.crypto import symmetric_encrypt_authenticate\nfrom iotauth.transports import recv_frame, send_frame\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Applications should normally use ",(0,r.jsx)(n.code,{children:"SecureClient"}),", ",(0,r.jsx)(n.code,{children:"SecureServer"}),", and\n",(0,r.jsx)(n.code,{children:"SecureChannel"})," instead of calling those low-level helpers directly."]}),"\n",(0,r.jsxs)(n.h2,{id:"common-setup-iotauthcontext",children:["Common setup: ",(0,r.jsx)(n.code,{children:"IoTAuthContext"})]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"IoTAuthContext"})," class holds the runtime state of a Python entity: configuration parameters, cryptographic keys, distribution-key settings, and cached session keys."]}),"\n",(0,r.jsx)(n.h3,{id:"constructors",children:"Constructors"}),"\n",(0,r.jsx)(n.h4,{id:"iotauthcontextfrom_config",children:(0,r.jsx)(n.code,{children:"IoTAuthContext.from_config"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"@classmethod\ndef from_config(cls, path: str | Path, *, validate_paths: bool = True) -> IoTAuthContext\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Reads an entity configuration file, loads its configured credentials or\npermanent distribution key, and initializes an ",(0,r.jsx)(n.code,{children:"IoTAuthContext"}),". This is the\nonly public configuration entry point and is the method applications should\nuse."]}),"\n",(0,r.jsxs)(n.p,{children:["The internal parser supports both ",(0,r.jsx)(n.strong,{children:"C-style dotted properties"})," (",(0,r.jsx)(n.code,{children:"key=value"}),") and ",(0,r.jsx)(n.strong,{children:"Node-style JSON"})," configuration files.\nIt detects JSON from the first non-whitespace character (",(0,r.jsx)(n.code,{children:"{"}),"), rather than relying on the filename extension.\nBoth formats produce the same runtime context."]}),"\n",(0,r.jsx)(n.p,{children:"Relative credential and key paths are resolved differently by format:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Properties paths are relative to the directory containing the config file."}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"JSON paths are relative to the current working directory from which the Python process is started."}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Absolute paths work in both formats."}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Parameters"}),":"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"path"}),": Path to a properties or JSON configuration file, commonly using the ",(0,r.jsx)(n.code,{children:".config"})," extension."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"val
1idate_paths"}),": If ",(0,r.jsx)(n.code,{children:"True"}),", verifies that configured credential and key files exist during initialization."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Returns"}),": An initialized ",(0,r.jsx)(n.code,{children:"IoTAuthContext"})," instance with an empty ",(0,r.jsx)(n.code,{children:"SessionKeyCache"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Raises"}),": ",(0,r.jsx)(n.code,{children:"ConfigError"})," or ",(0,r.jsx)(n.code,{children:"CredentialError"})," if the configuration is invalid or files cannot be loaded."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["The parsed configuration is available as ",(0,r.jsx)(n.code,{children:"ctx.config"})," for inspection.\nApplications should treat it as file-owned runtime configuration and should not modify it in code.\nTo change configuration, update the source file and create a new context with ",(0,r.jsx)(n.code,{children:"from_config()"}),"."]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"1-create-a-secure-channel",children:"1. Create a secure channel"}),"\n",(0,r.jsxs)(n.p,{children:["Use this workflow when an application only needs to establish an encrypted\nconnection and exchange messages. ",(0,r.jsx)(n.code,{children:"SecureClient"})," and ",(0,r.jsx)(n.code,{children:"SecureServer"})," handle key\nacquisition and the secure handshake. Application data is always sent through\nthe returned ",(0,r.jsx)(n.code,{children:"SecureChannel"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"secureclient",children:(0,r.jsx)(n.code,{children:"SecureClient"})}),"\n",(0,r.jsx)(n.p,{children:"A wrapper for client-side key acquisition, connection establishment, and the\nsecure handshake."}),"\n",(0,r.jsx)(n.h4,{id:"constructor",children:"Constructor"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def __init__(\n self,\n ctx: IoTAuthContext,\n *,\n key: SessionKey | None = None,\n purpose: dict[str, object] | str | None = None,\n host: str | None = None,\n port: int | None = None,\n timeout: float | None = 5.0,\n)\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ctx"}),": The runtime ",(0,r.jsx)(n.code,{children:"IoTAuthContext"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"key"}),": Optional session key. If omitted, ",(0,r.jsx)(n.code,{children:"connect()"})," requests one from Auth."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"purpose"}),": Optional purpose override used when requesting a key."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"host"})," / ",(0,r.jsx)(n.code,{children:"port"}),": Optional peer address. If omitted, the first configured target is used."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"timeout"}),": Timeout for Auth, connection, and handshake operations."]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"connect",children:(0,r.jsx)(n.code,{children:"connect"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def connect(self) -> SecureChannel\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Returns an open ",(0,r.jsx)(n.code,{children:"SecureChannel"}),". If the client has no selected key, this method requests keys from Auth and\nselects the first before connecting to the peer. It retains that key for later\nconnections; it does not automatically select a key from the context cache or\nrefresh an expired key. Pass ",(0,r.jsx)(n.code,{children:"key="})," to reuse a specific cached key."]}),"\n",(0,r.jsxs)(n.p,{children:["Each ",(0,r.jsx)(n.code,{children:"SecureClient"})," owns at most one open channel. Close the returned channel\nbefore calling ",(0,r.jsx)(n.code,{children:"connect()"})," again; otherwise ",(0,r.jsx)(n.code,{children:"connect()"})," raises\n",(0,r.jsx)(n.code,{children:"SecureClientStateError"}),"."]}),"\n",(0,r.jsx)(n.h4,{id:"client-example",children:"Client example"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'ctx = IoTAuthContext.from_config("path/to/client.config")\n\nwith SecureClient(ctx) as client:\n channel = client.connect()\n channel.send(b"hello")\n reply = channel.recv(timeout=5.0)\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Exiting the ",(0,r.jsx)(n.code,{children:"with"})," block closes the active channel. To close it earlier, call\n",(0,r.jsx)(n.code,{children:"channel.close()"}),"."]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"secureserver",children:(0,r.jsx)(n.code,{children:"SecureServer"})}),"\n",(0,r.jsx)(n.p,{children:"A wrapper that listens for incoming TCP connections from peer entities and completes secure handshakes."}),"\n",(0,r.jsx)(n.h4,{id:"constructor-1",children:"Constructor"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def __init__(\n self,\n ctx: IoTAuthContext,\n *,\n host: str | None = None,\n port: int | None = None,\n backlog: int = 5,\n accept_timeout: float | None = None,\n handshake_timeout: float | None = 5.0,\n)\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ctx"}),": The runtime ",(0,r.jsx)(n.code,{children:"IoTAuthContext"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"host"})," / ",(0,r.jsx)(n.code,{children:"port"}),": Listen address. If omitted, the first configured target is used."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"backlog"}),": Maximum pending TCP connections passed to ",(0,r.jsx)(n.code,{children:"socket.listen()"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"accept_timeout"}),": Maximum seconds to wait for an incoming TCP connection.\nThe default, ",(0,r.jsx)(n.code,{children:"None"}),", waits indefinitely."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"handshake_timeout"}),": Maximum seconds to complete the secure handshake after\naccepting a peer. The default is five seconds. Use ",(0,r.jsx)(n.code,{children:"None"})," to wait indefinitely."]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"serve_once",children:(0,r.jsx)(n.code,{children:"serve_once"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def serve_once(self) -> SecureChannel\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Blocks until a single client TCP connection is accepted, reads the session key ID from the initial handshake frame, fetches the key if necessary, completes the challenge/response verification, and returns a connected ",(0,r.jsx)(n.code,{children:"SecureChannel"}),"."]}),"\n",(0,r.jsx)(n.h4,{id:"server-example",children:"Server example"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'ctx = IoTAuthContext.from_config("path/to/server.config")\n\nwith SecureServer(ctx) as server:\n channel = server.serve_once()\n try:\n message = channel.recv()\n channel.send(b"ack")\n finally:\n channel.close()\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Exiting the ",(0,r.jsx)(n.code,{children:"with"})," block closes the server's listening socket. The application\ncloses each channel returned by ",(0,r.jsx)(n.code,{children:"serve_once()"}),"."]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"securechannel",children:(0,r.jsx)(n.code,{children:"SecureChannel"})}),"\n",(0,r.jsxs)(n.p,{children:["Represents an established, bidirectional encrypted communication session between two entities.\nThe socket, session key, and send/receive sequence counters are managed\ninternally. Applications can inspect the read-only ",(0,r.jsx)(n.code,{children:"closed"})," property and use\nthe methods below."]}),"\n",(0,r.jsx)(n.h4,{id:"methods",children:"Methods"}),"\n",(0,r.jsx)(n.h4,{id:"send",children:(0,r.jsx)(n.code,{children:"send"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def send(self, data: bytes) -> None\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Encrypts ",(0,r.jsx)(n.code,{children:"data"})," using the active session key and cryptographic mode (for\nexample, ",(0,r.jsx)(n.code,{children:"AES_128_CBC"})," or ",(0,r.jsx)(n.code,{children:"AES_128_GCM"}),") and transmits the framed bytes over the\nTCP socket."]}),"\n",(0,r.jsx)(n.h4,{id:"recv",children:(0,r.jsx)(n.code,{children:"recv"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def recv(self, *, timeout: float | None = None) -> bytes\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Reads an incoming frame from the TCP socket, verifies any HMAC/GCM\nauthentication tags, decrypts the payload using the session key, and returns\nthe raw plaintext ",(0,r.jsx)(n.code,{children:"bytes"}),". ",(0,r.jsx)(n.code,{children:"timeout"})," limits how many seconds the operation\nwaits for a complete message; ",(0,r.jsx)(n.code,{children:"None"})," waits indefinitely. The socket's previous\ntimeout is restored after the call succeeds or fails."]}),"\n",(0,r.jsx)(n.h4,{id:"close",children:(0,r.jsx)(n.code,{children:"close"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def close(self) -> None\n"})}),"\n",(0,r.jsx)(n.p,{children:"Closes the underlying TCP connection."}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"2-manage-session-keys-explicitly",children:"2. Manage session keys explicitly"}),"\n",(0,r.jsx)(n.p,{children:"Use this workflow when an application needs to request several keys, inspect the\nkey cache, or choose a specific key before creating a secure channel."}),"\n",(0,r.jsx)(n.h3,{id:"iotauthcontextrequest_session_keys",children:(0,r.jsx)(n.code,{children:"IoTAuthContext.request_session_keys"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def request_session_keys(\n self,\n *,\n purpose: dict[str, object] | str | None = None,\n count: int | None = None,\n timeout: float | None = 5.0,\n) -> list[SessionKey]\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"purpose"}),": Optional purpose override. If omitted, the configured purpose is used."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"count"}),": Number of keys to request. If omitted, the configured key count is used."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"timeout"}),": Socket timeout in seconds for communication with Auth."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Returns"}),": The keys returned by Auth. They are also added to ",(0,r.jsx)(n.code,{children:"ctx.session_keys"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Raises"}),": ",(0,r.jsx)(n.code,{children:"AuthConnectionError"}
1)," when Auth is unreachable and\n",(0,r.jsx)(n.code,{children:"AuthProtocolError"})," when Auth returns an unexpected response."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"request-and-select-a-key",children:"Request and select a key"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'ctx = IoTAuthContext.from_config("path/to/client.config")\n\nkeys = ctx.request_session_keys(\n purpose={"group": "Servers"},\n count=2,\n)\n\nwith SecureClient(ctx, key=keys[0]) as client:\n channel = client.connect()\n channel.send(b"hello")\n reply = channel.recv()\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Passing ",(0,r.jsx)(n.code,{children:"key="})," prevents ",(0,r.jsx)(n.code,{children:"SecureClient.connect()"})," from requesting another key."]}),"\n",(0,r.jsx)(n.h3,{id:"sessionkeycache",children:(0,r.jsx)(n.code,{children:"SessionKeyCache"})}),"\n",(0,r.jsxs)(n.p,{children:["The context exposes its in-memory cache as ",(0,r.jsx)(n.code,{children:"ctx.session_keys"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"ctx.session_keys.add(key, replace=False)\nkey = ctx.session_keys.get(key_id)\nkey = ctx.session_keys.require(key_id)\nkeys = ctx.session_keys.values()\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"add()"})," stores a key. Set ",(0,r.jsx)(n.code,{children:"replace=True"})," to replace a key with the same ID."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"get()"})," returns ",(0,r.jsx)(n.code,{children:"None"})," when the key is absent."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"require()"})," raises ",(0,r.jsx)(n.code,{children:"KeyCacheError"})," when the key is absent."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"values()"})," returns all cached keys."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"sessionkey",children:(0,r.jsx)(n.code,{children:"SessionKey"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"SessionKey(\n id: bytes,\n cipher_key: bytes,\n mac_key: bytes | None,\n abs_validity: int | None,\n rel_validity: int | None,\n encryption_mode: str,\n hmac_enabled: bool,\n permanent_distribution_key: bool,\n first_use_ms: int | None = None,\n)\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"id"}),": Eight-byte session-key identifier."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"cipher_key"}),": Symmetric encryption key."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"mac_key"}),": Message-authentication key, or ",(0,r.jsx)(n.code,{children:"None"})," when HMAC is disabled."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"abs_validity"}),": Absolute expiration time in epoch milliseconds."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"rel_validity"}),": Validity duration in milliseconds after first use."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"encryption_mode"}),": Configured symmetric encryption mode."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"hmac_enabled"}),": Whether messages require HMAC authentication."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"permanent_distribution_key"}),": Whether Auth issued the session key using\npermanent distribution-key mode."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"first_use_ms"}),": First-use time in epoch milliseconds used to evaluate\nrelative validity. It is ",(0,r.jsx)(n.code,{children:"None"})," until the key is first used."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Most applications should use keys returned by ",(0,r.jsx)(n.code,{children:"request_session_keys()"})," rather\nthan constructing them directly. Cipher and MAC key material is excluded from\nthe object's representation to avoid exposing secrets in logs and tracebacks."]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"buffer-cryptography",children:"Buffer cryptography"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"iotauth.crypto"})," module exposes standalone ",(0,r.jsx)(n.code,{children:"symmetric_encrypt_authenticate()"})," and ",(0,r.jsx)(n.code,{children:"symmetric_decrypt_authenticate()"})," functions for byte buffers, with AES-128-CBC, AES-128-CTR, and AES-128-GCM support. They take cipher/MAC ke
1ys and mode settings explicitly. There is no ",(0,r.jsx)(n.code,{children:"Crypto"})," class or ",(0,r.jsx)(n.code,{children:"encrypt_payload()"})," method in the package."]}),"\n",(0,r.jsxs)(n.p,{children:["These low-level functions do not manage session-key validity, message framing, or sequence numbers. Use ",(0,r.jsx)(n.code,{children:"SecureChannel.send()"})," and ",(0,r.jsx)(n.code,{children:"recv()"})," for communication with peers."]}),"\n",(0,r.jsx)(n.h2,{id:"exceptions",children:"Exceptions"}),"\n",(0,r.jsxs)(n.p,{children:["The API-specific exceptions below inherit from ",(0,r.jsx)(n.code,{children:"IoTAuthError"})," (",(0,r.jsx)(n.code,{children:"iotauth.exceptions"}),"). Invalid arguments can also raise standard Python exceptions; for example, ",(0,r.jsx)(n.code,{children:"recv(timeout=-1)"})," raises ",(0,r.jsx)(n.code,{children:"ValueError"}),"."]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Exception"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"IoTAuthError"})}),(0,r.jsx)(n.td,{children:"Base class for all IoTAuth Python API errors."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ConfigError"})}),(0,r.jsxs)(n.td,{children:["Raised when an ",(0,r.jsx)(n.code,{children:".config"})," file is missing required fields or malformed."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CredentialError"})}),(0,r.jsx)(n.td,{children:"Raised when a private key or certificate cannot be read or verified."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"KeyCacheError"})}),(0,r.jsx)(n.td,{children:"Raised when a session-key cache operation is invalid."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SerializationError"})}),(0,r.jsx)(n.td,{children:"Raised when protocol bytes cannot be encoded or decoded."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"AuthConnectionError"})}),(0,r.jsx)(n.td,{children:"Raised when TCP communication with Auth or a peer fails."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"AuthProtocolError"})}),(0,r.jsx)(n.td,{children:"Raised when Auth returns a semantically unexpected message."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"UnsupportedCryptoError"})}),(0,r.jsx)(n.td,{children:"Raised when a configured crypto operation is unsupported."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"MessageIntegrityError"})}),(0,r.jsx)(n.td,{children:"Raised when signature, MAC, or authenticated decryption verification fails."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SecureHandshakeError"})}),(0,r.jsx)(n.td,{children:"Raised when the peer-to-peer secure handshake fails."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ExpiredKeyError"})}),(0,r.jsx)(n.td,{children:"Raised when an expired session key is used."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SecureChannelClosed"})}),(0,r.jsx)(n.td,{children:"Raised when an operation is attempted on a closed channel or the peer closes during receive."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SecureClientStateError"})}),(0,r.jsx)(n.td,{children:"Raised when a client already owns an open channel."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"InvalidSequenceNumberError"})}),(0,r.jsx)(n.td,{children:"Raised when secure-message sequence validation fails."})]})]})]})]})}function a(e={}){const{wrapper:n}={...(0,c.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},8453(e,n,s){s.d(n,{R:()=>t,x:()=>o});var i=s(6540);const r={},c=i.createContext(r);function t(e){const n=i.useContext(c);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:t(e.components),i.createElement(c.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.