Secure Channel v2 Protocol
Protocol Identity
| Property | Value |
|---|---|
| Magic | SC |
| Version | 2 |
| Content-Type | application/json;charset=UTF-8 |
Message Types
| Constant | Value | Description |
|---|---|---|
TYPE_KEY_EXCHANGE | 1 | Key exchange handshake type. Contains an RSA-encrypted AES key. |
TYPE_SESSION_DATA | 2 | Session reuse type. No longer carries the RSA-encrypted key. |
TYPE_RESPONSE_DATA | 129 | Response data type. Encrypted with the session response key. |
Key Sizes
| Constant | Bytes | Description |
|---|---|---|
KEY_ID_LEN_SIZE | 1 | KEY_ID length field size. Uses 1 byte for compact encoding. |
REQ_KEY_LEN_SIZE | 2 | REQ_KEY length field size. Uses 2 bytes for length encoding. |
RESP_KEY_LEN_SIZE | 2 | RESP_KEY length field size. Uses 2 bytes for length encoding. |
Protocol Headers
| Header | Constant | Description |
|---|---|---|
X-SC-Session-Id | SESSION_ID_HEADER | Secure Channel session identifier |
X-SC-Version | VERSION_HEADER | Protocol version (currently 2) |
Client-Side Integration
Binary Envelope Format
The SCv2 binary envelope is a compact byte layout used for encrypted request payloads. When a client sends an encrypted request, the HTTP body is replaced with this binary format instead of JSON.
Type 1 -- Key Exchange (first request in a session):
[2B magic "SC"] [1B version] [1B type=1]
[1B keyIdLen] [keyIdLen B keyId]
[2B reqKeyLen] [reqKeyLen B encryptedReqKey]
[2B respKeyLen] [respKeyLen B encryptedRespKey]
[remaining bytes: AES-GCM encrypted payload]Type 2 -- Session Data (subsequent requests):
[2B magic "SC"] [1B version] [1B type=2]
[remaining bytes: AES-GCM encrypted payload]Type 129 -- Response Data (server responses):
[2B magic "SC"] [1B version] [1B type=129]
[remaining bytes: AES-GCM encrypted payload]The AES-GCM encrypted payload contains a 12-byte IV (nonce) followed by the ciphertext with a 16-byte authentication tag appended.
Key Exchange Flow
- Get server public key:
GET /web/v1/secure-channel/public-key- Returns the active RSA public key (
keyId,publicKey,algorithm)
- Returns the active RSA public key (
- Generate AES session keys: Client generates two random AES-256 keys:
- Request key -- used by the client to encrypt request payloads
- Response key -- used by the server to encrypt response payloads
- Create session:
POST /web/v1/secure-channel/session- Client RSA-encrypts both AES keys using the server's public key
- Server decrypts and stores the keys, returns a
sessionId
- Client stores the
sessionIdand both AES keys locally
Request Encryption Flow
Once a session is established:
- Serialize the JSON request body to UTF-8 bytes
- Encrypt the bytes using AES-256-GCM with the request key and a random 12-byte IV
- Build the binary envelope:
- First request: use Type 1 (includes the RSA-encrypted keys)
- Subsequent requests: use Type 2 (session reuse, no key material)
- Set the
X-SC-Session-Idheader to the session ID - Send the binary envelope as the HTTP body (Content-Type remains
application/json;charset=UTF-8)
Response Decryption Flow
- Read the binary response body
- Verify the magic bytes (
SC) and version (2) - Confirm message type is 129 (response data)
- Extract the AES-GCM payload (IV + ciphertext + auth tag)
- Decrypt using the response key
- Parse the decrypted bytes as UTF-8 JSON
Session Lifecycle
- Sessions expire after a configured TTL (server-side)
- Sessions are bound to a user after authentication (
bindSessionToUser) - Per-user session limits are enforced
- Clients should explicitly close sessions when flows complete:
POST /web/v1/secure-channel/session/close
Server SDK Reference
getPublicKey()
Returns: RsaPublicKeyInfo
Retrieves the active RSA public key used for client key exchange.
getActiveKeyId()
Returns: String
Returns the active RSA key ID.
rotateKeys()
Returns: void
Rotates the RSA key pair.
decrypt(byte[])
Returns: DecryptionResult
Decrypts an SCv2 envelope-formatted encrypted payload.
decrypt(byte[], String)
Returns: DecryptionResult
Decrypts an encrypted payload with optional session reuse.
encrypt(byte[], String)
Returns: byte[]
Encrypts a response payload using the session's AES key.
encrypt(byte[], SessionContext)
Returns: byte[]
Encrypts a response payload using an existing session context.
encryptPayload(byte[], SessionContext)
Returns: AesGcmCipher.GcmPayload
Encrypts a response payload using the session response key.
decryptPayload(AesGcmCipher.GcmPayload, String)
Returns: byte[]
Decrypts a request payload using the session request key.
createSession(String, String, String)
Returns: SessionContext
Creates a session from RSA-encrypted AES keys.
getSession(String)
Returns: Optional<SessionContext>
Retrieves an existing session by ID.
isSessionValid(String)
Returns: boolean
Checks whether a session exists and is valid.
invalidateSession(String)
Returns: void
Invalidates a session.
clearAllSessions()
Returns: void
Clears all sessions.
getConfig()
Returns: SecureChannelConfig
Returns the SDK configuration.
bindSessionToUser(String, String)
Returns: void
Binds an unbound KEY_EXCHANGE session to an authenticated user and enforces per-user session limits.
isEncryptedPayload(byte[])
Returns: boolean
Checks if a payload appears to be encrypted using SCv2 format.
Builder Methods
| Method | Returns | Description |
|---|---|---|
sessionTtl(Duration) | Builder | Sets the session TTL (time to live) |
maxSessions(int) | Builder | Sets the maximum sessions per user |
sessionStore(SessionStore) | Builder | Sets a custom session store implementation |
keyStore(KeyStore) | Builder | Sets a custom key store implementation |
build() | SecureChannelSDK | Builds the SDK instance |