Skip to content

Migrating from RSA to ML-KEM

This use case describes the process of migrating encrypted data from RSA-2048 to ML-KEM. The migration is performed via streaming, ensuring that the data is never exposed in plaintext at any stage of the process.

Process Overview

  1. Generate an RSA-2048 key – Used to encrypt a file initially.
  2. Encrypt a file (streaming) with RSA – Data is encrypted using the RSA-2048 key.
  3. Generate a ML-KEM1024 key – A new post-quantum key is created.
  4. Re-encrypt the file (streaming) from RSA to ML-KEM1024 – The data is decrypted with RSA and immediately re-encrypted with ML-KEM1024, without being exposed in plaintext.
  5. Decrypt using ML-KEM1024 (streaming) – The final decryption step using the ML-KEM1024 key.
flowchart TD
    Start(("Start")) --> Step1[Generate an RSA-2048 key]
    Step1 --> Step2["Encrypt a file (streaming) using RSA-2048"]
    Step2 --> Step3[Generate a ML-KEM1024 key]
    Step3 --> Step4["Re-encrypt file (streaming) from RSA to ML-KEM1024"]
    Step4 --> Step5["Decrypt file (streaming) using ML-KEM1024"]
    Step5 --> End(("End"))

API Endpoints Involved

Below are the five steps outlined above, along with the endpoints and example requests needed to complete each phase of the RSA-to-ML-KEM migration.

1. Generate an RSA-2048 Key

Purpose: Create a classical RSA-2048 key that will be used to encrypt data.

  • Endpoint: POST /api/key-management/keys
  • Request (JSON):

{
    "kid": "myOldRsaKid",
    "kty": "RSA",
    "alg": "RSA-2048",
    "keyOps": ["encrypt", "decrypt"],
    "exportable": true
}
- Response: - 201 Created if the key is successfully generated. - (No body or a minimal JSON body acknowledging success.)


2. Encrypt a File (Streaming) with RSA

Purpose: Encrypt the file using RSA-2048 in streaming mode, ensuring large data is handled without exposing it in memory as a single object.

  • Endpoint: POST /api/crypto/stream/encrypt
  • Multipart Form Fields:
    1. metadata (JSON) -- Must contain the kid of the RSA key.
    2. file (binary) -- The plaintext file to be encrypted.

Example (multipart/form-data):

Sample Request (pseudo raw HTTP)

POST /api/crypto/stream/encrypt HTTP/1.1
Host: demo.ankatech.co
Authorization: Bearer <token>
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
  "kid": "myOldRsaKid"
}
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="secret.txt"
Content-Type: application/octet-stream

<RAW_FILE_CONTENTS>
------WebKitFormBoundary--`

Response

  • Returns the encrypted data as raw bytes (application/octet-stream).

3. Generate a ML-KEM1024 Key

Purpose: Create a post-quantum key (ML-KEM1024), which will replace RSA as the target encryption key.

  • Endpoint: POST /api/key-management/keys
  • Request (JSON):

{
    "kid": "myNewML-KEMKid",
    "kty": "ML-KEM",
    "alg": "ML-KEM-1024",
    "keyOps": ["encrypt", "decrypt"],
    "exportable": true
}
- Response: - 201 Created if the key is successfully generated.


4. Re-Encrypt the File (Streaming) from RSA to ML-KEM1024

Purpose: Decrypt the file using the RSA private key and re-encrypt it immediately using the ML-KEM public key, all in streaming mode so the data is never revealed in plaintext.

  • Endpoint: POST /api/crypto/stream/reencrypt
  • Multipart Form Fields:
    1. metadata (JSON) of type ReencryptStreamRequest, containing oldKid (RSA) and newKid (ML-KEM).
    2. file (binary) -- The file currently encrypted under RSA.

Example (multipart/form-data):

Sample Request (pseudo raw HTTP)

POST /api/crypto/stream/reencrypt HTTP/1.1
Host: demo.ankatech.co
Authorization: Bearer <token>
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
  "oldKid": "myOldRsaKid",
  "newKid": "myNewML-KEMKid"
}
------Boundary
Content-Disposition: form-data; name="file"; filename="enc_rsa.bin"
Content-Type: application/octet-stream

<ENCRYPTED_FILE_CONTENTS>
------Boundary--`

Response

  • Streams back the re-encrypted data (application/octet-stream), now under ML-KEM1024.

5. Decrypt the File (Streaming) Using ML-KEM1024

Purpose: Finally decrypt the newly re-encrypted file using the ML-KEM1024 private key.

  • Endpoint: POST /api/crypto/stream/decrypt
  • Multipart Form Fields:
    1. metadata (JSON) -- Must contain kid corresponding to the ML-KEM1024 private key.
    2. file (binary) -- The file encrypted under ML-KEM1024.

Example (multipart/form-data):

Sample Request (pseudo raw HTTP)

POST /api/crypto/stream/decrypt HTTP/1.1
Host: demo.ankatech.co
Authorization: Bearer <token>
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
  "kid": "myNewML-KEMKid"
}
------Boundary
Content-Disposition: form-data; name="file"; filename="enc_ML-KEM.bin"
Content-Type: application/octet-stream

<ENCRYPTED_FILE_CONTENTS>
------Boundary--`

Response

  • Streams back the decrypted plaintext as raw bytes.

Key Considerations

  • Data is never exposed in plaintext\ Using streaming endpoints, the decryption and re-encryption happen in a pipeline. The plaintext is neither written to disk nor exposed to external processes.

  • Streaming processing\ This approach supports large files, preventing memory overload and ensuring a continuous read/write flow of data.

  • Post-quantum security\ Migrating to ML-KEM significantly enhances long-term resilience against future quantum-based attacks.

This strategy guarantees a secure and seamless transition from classical RSA encryption to quantum-resistant ML-KEM-based encryption.