Skip to content

Format-preserving encryption capabilities #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Conversation

alberto-crossmint
Copy link
Contributor

@alberto-crossmint alberto-crossmint commented May 2, 2025

FF1 is a NIST-approved format preserving encryption (FPE) algorithm. This allows us to compute an AES256-encrypted OTP-like payload from an OTP-like payload!

This PR creates a FPEService that uses the encryptionService to derive an AES256-GCM key from the shared secret that is present after ECDH exchange that we already performed for HPKE and uses that symmetric key to perform the OTP encryption.

This is disabled. To be enabled by just uncommenting the line in the send OTP handler.

Tested it by running a local instance of the iframe and performing encryption-decryption within it! Will test end to end and enable when the corresponding part lands on the TEE-ts side

Tested the whole flow with the code in https://github.com/Paella-Labs/tee-ts/pull/3

Copy link

vercel bot commented May 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
simple-ncs-demo ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 5, 2025 8:16pm

@alberto-crossmint alberto-crossmint changed the title FPE.init() Format preserving encryption capabilities May 2, 2025
@alberto-crossmint alberto-crossmint requested a review from devlyn37 May 2, 2025 15:30
@alberto-crossmint alberto-crossmint changed the title Format preserving encryption capabilities Format-preserving encryption capabilities May 2, 2025
@@ -67,7 +67,7 @@ export class CrossmintApiService extends XMIFService {
static createSignerInputSchema = z.object({ authId: z.string() });
static createSignerOutputSchema = z.object({});

static sendOtpInputSchema = z.object({ otp: z.string() });
static sendOtpInputSchema = z.object({ otp: z.string(), publicKey: z.string() });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We add the public key for the TEE to derive the corresponding AES256 encryption key

ciphertext: ArrayBuffer,
encapsulatedKey: ArrayBuffer,
{ validateTeeSender }: { validateTeeSender: boolean } = { validateTeeSender: true }
async decrypt<T extends Record<string, unknown>, U extends string | ArrayBuffer>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Integrated decrypt and decryptBase64 into a single function. Having both felt reduntant

async getEncryptionData(): Promise<EncryptionData> {
// Key derivation

private async deriveAES256EncryptionKey(): Promise<CryptoKey> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here we derive the AES key for the FF1 algorithm!

this.assertInitialized();
// biome-ignore lint/style/noNonNullAssertion: asserted before
return this.suite.kem.serializePublicKey(this.ephemeralKeyPair!.publicKey);
private async serializePrivateKey(key: CryptoKey): Promise<ArrayBuffer> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We were using the kem serialization function but this had a problem in which, when we deserialized and reconstructed the keys, the usages of the key were not re'included, so it will fail later when trying to use it. That's why we built this custom serialization/deserialization functions

Copy link
Contributor

@devlyn37 devlyn37 left a comment

Choose a reason for hiding this comment

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

Sweet!

Looks great, but lets keep this in mind during our red team week.

@@ -54,7 +54,7 @@ export class AttestationService extends XMIFService {
}

private async fetchAttestationDoc(): Promise<AttestationDocument> {
const response = await fetch('https://tee-ts.onrender.com/attestation', {});
const response = await fetch('http://localhost:3001/attestation', {});
Copy link
Contributor

Choose a reason for hiding this comment

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

intentional?

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.

2 participants