Skip to content

initial scaffolding for SDK encryption#37

Open
Lance-Drane wants to merge 9 commits into
candidate-0.9.0from
30-add-encryption
Open

initial scaffolding for SDK encryption#37
Lance-Drane wants to merge 9 commits into
candidate-0.9.0from
30-add-encryption

Conversation

@Lance-Drane

@Lance-Drane Lance-Drane commented Oct 2, 2025

Copy link
Copy Markdown
Collaborator

Needs to be completed before done:

  • - basic scaffolding for encryption (Lance)
  • - encryption implementation (Marshall/Jesse/Andrew/etc.)
  • - e2e / integration test examples (Lance/Marshall/Jesse/Andrew/etc.)

(I don't really care too much about unit tests, but you can unit test the encryption function itself if you want)

To add the capability endpoints for a Service (which, IIRC, is just the get_public_key function), add it to IntersectSdkCoreCapability (https://github.com/INTERSECT-SDK/python-sdk/blob/candidate-0.9.0/src/intersect_sdk/capability/universal_capability/universal_capability.py), it should be annotated with @intersect_message . If we need additional state in the capability, we can modify the constructor for this capability and potentially the service as well.

Then you can call the capability with intersect_sdk.<YOUR_FUNCTION_NAME_HERE> as the operation from clients.

The actual encrypt/decrypt functions I would prefer to be separated out into utility functions in another file somewhere under the _internal directory, because both the Service and the Client will use them and users also have no reason to ever use this function themselves. I have marked the areas which need the inserted functions with #TODO comments, there should be one of each in client.py and two of each in service.py.

Signed-off-by: Lance-Drane <Lance-Drane@users.noreply.github.com>
@marshallmcdonnell marshallmcdonnell changed the title Draft: initial scaffolding for SDK encryption initial scaffolding for SDK encryption Feb 6, 2026
@marshallmcdonnell

Copy link
Copy Markdown
Collaborator

UPDATE:

  • I finally took a stab at adding the encryption into the SDK for this PR!
  • Mainly, added the encryption module to hold data models and utility functions for encryption and decryption
  • I am WIP for the service.py and client.py adding in the encryption and decryption TODO spots
    • The decryption is relatively simple since it is just to receive an encrypted message and, using local key pair stuff, decrypt the message; I am probably messing it up where I also try to cast it to the unencrypted data model, though
    • The more challenging one is the encryption, since this requires client or service to first send a message to get the public key, receive it, and then do the encryption
      • In all honestly, the current state is me throwing LLM coding agent at it first to get an idea of how to start; doesn't seem to work so I'll start working on that

One thing that is sort of blocking me:

  • I have unit tests passing but need integration and end-to-end testing
  • Trying to use the docker compose, I cannot get the rabbitmq and minio to work now for me (getting connection refused and such); it might be a network thing locally for me but also noticed we are now on RabbitMQ 4, so not sure if that could also be a culprit
  • Digging into that now!

)

@intersect_message()
def get_public_key(self) -> Dict[str, str]:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should be more explicit with the typing here, we can use Union types if necessary

from pydantic import BaseModel

class IntersectDecryptedPayload(BaseModel):
model: BaseModel

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might need to be an Any typing because we don't necessarily require BaseModels as the input/output models

- If your Content-Type value is ANYTHING ELSE, you MUST mark it as "bytes" . In this instance, INTERSECT will not base64-encode or base64-decode the value.
"""

IntersectEncryptionScheme = Literal['NONE', 'RSA']

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lance-Drane Lance-Drane Jun 24, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

be more explicit in the RSA typing, i.e. RSA_AES_2048

Comment on lines +1 to +9
from .aes_cypher import AESCipher
from .client_encryption import intersect_payload_encrypt
from .service_decryption import intersect_payload_decrypt


__all__ = (
'AESCipher',
'intersect_payload_encrypt',
'intersect_payload_decrypt',

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything in this namespace should probably be moved to intersect-sdk-common: https://github.com/INTERSECT-SDK/intersect-python-common

Comment on lines +315 to +331
# Generate a key pair for encryption
self._private_key: rsa.RSAPrivateKey = rsa.generate_private_key(
public_exponent=65537, key_size=2048
)
self._public_key = self._private_key.public_key()

# Get the PEM encoded public key
self._public_key_pem = self._public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
).decode()

self._private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use a configuration parameter (both here and the Client) to ensure that we can always regenerate the same public/private key. We should also have some logic to allow for key rotation without necessarily restarting the Service/Client.

"""Basic status function which returns a hard-coded string."""
return 'Up'

@intersect_message()

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may want to explicitly set the encryption schemes to the RSA scheme only, to enforce the encryption

step three: start up client with user callback
"""
intersect_client.startup(user_callback=user_callback)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will need to call intersect_sdk.get_public_key before calling say_hello_to_name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants