Skip to content

Migrating from RSA to ML-KEM (Kyber)

This use case describes the process of migrating encrypted data from RSA-2048 to ML-KEM (Kyber). 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 Kyber1024 key – A new post-quantum key is created.
  4. Re-encrypt the file (streaming) from RSA to Kyber1024 – The data is decrypted with RSA and immediately re-encrypted with Kyber1024, without being exposed in plaintext.
  5. Decrypt using Kyber1024 (streaming) – The final decryption step using the Kyber1024 key.
flowchart TD
    Start(("Start")) --> Step1[Generate an RSA-2048 key]
    Step1 --> Step2["Encrypt a file (streaming) using RSA-2048"]
    Step2 --> Step3[Generate a Kyber1024 key]
    Step3 --> Step4["Re-encrypt file (streaming) from RSA to Kyber1024"]
    Step4 --> Step5["Decrypt file (streaming) using Kyber1024"]
    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-Kyber 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 Kyber1024 Key

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

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

{
    "kid": "myNewKyberKid",
    "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 Kyber1024

Purpose: Decrypt the file using the RSA private key and re-encrypt it immediately using the Kyber 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 (Kyber).
    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": "myNewKyberKid"
}
------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 Kyber1024.

5. Decrypt the File (Streaming) Using Kyber1024

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

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

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": "myNewKyberKid"
}
------Boundary
Content-Disposition: form-data; name="file"; filename="enc_kyber.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 (Kyber) 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 Kyber-based encryption.