{
  "openapi": "3.1.1",
  "info": {
    "title": "Local File Encryption Studio API",
    "version": "1.0.0",
    "summary": "Encrypt and decrypt files with AES-256-GCM and a password, locally in your browser.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://fileencryptionstudio.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Encrypt and decrypt files with AES-256-GCM and a password, locally in your browser.",
        "description": "Encrypts any file up to 100 MB with AES-256-GCM, using a password (PBKDF2-SHA-256, at least 600,000 iterations) or a raw 256-bit key, and decrypts it again. The output is a small documented container. With JavaScript on, everything runs in your browser via WebCrypto and the file never leaves your device.\n\nMethodology:\n- Encryption: AES-256 in GCM mode (authenticated encryption) with a random 96-bit IV. The 16-byte authentication tag detects a wrong key and any modification of the file or its header.\n- Password mode: the key is PBKDF2-HMAC-SHA-256(password in Unicode NFC, UTF-8; random 16-byte salt; ≥ 600,000 iterations; 32 bytes). Raw-key mode uses your 32-byte key directly (or a random one generated for you).\n- Container \"UWFE\" v1, all integers big-endian: bytes 0–3 \"UWFE\"; 4 version (1); 5 KDF (1 = PBKDF2-SHA-256, 0 = raw key); 6–9 iterations (0 for raw key); 10 salt length S; then S salt bytes; then IV length (12) and the IV; then ciphertext followed by the 16-byte tag. The whole header is authenticated as GCM additional data.\n- With JavaScript on, the browser does everything with WebCrypto (crypto.subtle: PBKDF2, AES-GCM) and offers the result as a local download; the file and password never leave your device.\n- Without JavaScript or via the API/MCP, the server performs the same steps with Node.js crypto. It then receives the file and the password; the output is kept as a download for about 2 hours and then deleted.\n\nIf you forget the password or lose the key, the file cannot be recovered. Keep an unencrypted backup until you have tested decryption.",
        "tags": [
          "crypto"
        ],
        "x-mcp-tool": "file_encryption_studio",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileEncryptionStudioInput"
              },
              "examples": {
                "example1": {
                  "summary": "Encrypt a text file with a password (demo seed)",
                  "value": {
                    "action": "encrypt",
                    "file": {
                      "filename": "notes.txt",
                      "contentType": "text/plain",
                      "contentBase64": "TWVldGluZyBub3RlczogdGhlIHNwYXJlIGtleSBpcyB1bmRlciB0aGUgYmx1ZSBmbG93ZXJwb3QuCg=="
                    },
                    "keyMode": "password",
                    "password": "correct horse battery staple",
                    "seed": "demo"
                  }
                },
                "example2": {
                  "summary": "Decrypt the demo file",
                  "value": {
                    "action": "decrypt",
                    "file": {
                      "filename": "notes.txt.uwenc",
                      "contentType": "application/octet-stream",
                      "contentBase64": "VVdGRQEBAAknwBDpZOKuJvfa5dh6b4uQWgxhDBz+qzPNLpyER5uJf0+lqHctv57Gg4dAu9etoo9XyTMcu4qngNaolW3xIPUsAFquU/AQK9yw1zMFh2AKPSCkQVO45yYcipxdJ/Geh65IpBMyFXIxSia1"
                    },
                    "keyMode": "password",
                    "password": "correct horse battery staple"
                  }
                },
                "example3": {
                  "summary": "Encrypt with a raw AES-256 key",
                  "value": {
                    "action": "encrypt",
                    "file": {
                      "filename": "data.csv",
                      "contentType": "text/csv",
                      "contentBase64": "aWQsYW1vdW50CjEsNDIK"
                    },
                    "keyMode": "rawkey",
                    "rawKey": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
                    "seed": "raw-demo"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileEncryptionStudioResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "FileEncryptionStudioInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "action": {
            "title": "Action",
            "type": "string",
            "enum": [
              "encrypt",
              "decrypt"
            ],
            "default": "encrypt"
          },
          "file": {
            "title": "File",
            "description": "Up to 100 MB. With JavaScript on, the file is processed in your browser and never uploaded. Upload as {filename, contentType?, contentBase64}. Max 102400 KiB. Accepts */*.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "keyMode": {
            "title": "Key",
            "type": "string",
            "enum": [
              "password",
              "rawkey"
            ],
            "default": "password"
          },
          "password": {
            "title": "Password",
            "description": "Use a long passphrase. It cannot be recovered: without it the file is lost.",
            "type": "string",
            "maxLength": 1024
          },
          "rawKey": {
            "title": "Raw key (64 hex or 44 Base64 characters)",
            "description": "Raw-key mode. Leave empty when encrypting to generate a random key (shown once).",
            "type": "string",
            "maxLength": 200
          },
          "iterations": {
            "title": "PBKDF2 iterations (encrypt)",
            "description": "At least 600,000 (OWASP 2023 recommendation for PBKDF2-HMAC-SHA-256). Decryption reads the value from the file.",
            "type": "integer",
            "minimum": 600000,
            "maximum": 10000000,
            "default": 600000
          },
          "seed": {
            "title": "Demo seed (optional; fixes salt and IV — never for real files)",
            "description": "Only for reproducible demos. Reusing a salt/IV with the same password breaks AES-GCM security.",
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "file"
        ]
      },
      "FileEncryptionStudioResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "action",
              "format",
              "kdf",
              "iterations",
              "saltHex",
              "ivHex",
              "headerBytes",
              "inputBytes",
              "outputBytes",
              "generatedKeyHex",
              "seeded",
              "artifact"
            ],
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "encrypt",
                  "decrypt"
                ]
              },
              "format": {
                "type": "string",
                "description": "Container format id."
              },
              "kdf": {
                "type": "string",
                "enum": [
                  "pbkdf2-sha256",
                  "raw-key"
                ]
              },
              "iterations": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "saltHex": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "ivHex": {
                "type": "string"
              },
              "headerBytes": {
                "type": "integer"
              },
              "inputBytes": {
                "type": "integer"
              },
              "outputBytes": {
                "type": "integer"
              },
              "generatedKeyHex": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Only when a random raw key was generated for you."
              },
              "seeded": {
                "type": "boolean"
              },
              "artifact": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "artifactId",
                  "filename",
                  "mime",
                  "bytes",
                  "sha256",
                  "path"
                ],
                "properties": {
                  "artifactId": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "sha256": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}