Skip to content

Encryption key handling broken in sell() workflow #39

@tfius

Description

@tfius

Summary

The sell() function in packages/skill/src/skill.ts has critical issues with encryption key handling that make the escrow workflow non-functional.

Problems

1. Encryption key not stored after generation

At line 149, a random encryption key is generated:

const encryptionKey = ethers.randomBytes(32);

But at lines 197-198, there's a TODO:

// TODO: Store encryption key securely for later release
// In production, use escrow keystore (encrypted, crash-recovery safe)

Impact: After sell() returns, the encryption key is lost. The seller cannot reveal it to the buyer after escrow is funded.

2. Swarm-native encryption key embedded in reference

The uploadToSwarm() method (lines 366-392) uses Swarm-native encryption when encrypt: true:

if (encrypt) {
  headers['Swarm-Encrypt'] = 'true';
}

With Swarm-native encryption, the returned reference format is:

reference = content_hash + encryption_key (64 bytes + 32 bytes)

Impact: Anyone with the full swarmRef can decrypt the data immediately. There's no way to withhold the key for the escrow reveal phase.

3. Key mismatch in sell() workflow

sell() generates TWO different keys:

  1. encryptionKey at line 149 (never used for actual encryption)
  2. Swarm-native key embedded in reference at line 153

The keyCommitment at line 169 is computed from the first key:

const keyCommitment = ethers.keccak256(encryptionKey);

But this key has nothing to do with the Swarm-encrypted data!

Impact: Even if the seller reveals the committed key, it cannot decrypt the Swarm-encrypted data.

Expected Behavior

The escrow workflow should be:

  1. Seller encrypts data with key K (application-level encryption, NOT Swarm-native)
  2. Seller uploads encrypted blob to Swarm (without Swarm-Encrypt header)
  3. Seller creates escrow with keyCommitment = hash(K)
  4. Buyer funds escrow
  5. Seller reveals K on-chain
  6. Buyer downloads blob and decrypts with K

Suggested Fix

Option A: Don't use Swarm-native encryption for escrow

  • Encrypt data with encryptionKey before upload
  • Upload without Swarm-Encrypt: true
  • Store encryptionKey securely for later reveal

Option B: Split Swarm reference

  • Upload with Swarm-Encrypt: true
  • Split reference into content_hash (share) and key (reveal later)
  • Use the embedded key as the escrow key

Files Affected

  • packages/skill/src/skill.ts - sell() and uploadToSwarm() methods

Related

  • The CLI (sx escrows create) has a similar issue - it generates a random key unrelated to actual data encryption

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions