{"id":37707233,"url":"https://github.com/saiintbrisson/armadillo","last_synced_at":"2026-01-28T19:10:41.354Z","repository":{"id":332655701,"uuid":"1134487224","full_name":"saiintbrisson/armadillo","owner":"saiintbrisson","description":"Hytale QUIC, TLS-terminating proxy for traffic analysis, with a \"offline mode\" plugin bypassing authentication","archived":false,"fork":false,"pushed_at":"2026-01-18T01:59:12.000Z","size":75205,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-22T00:53:11.006Z","etag":null,"topics":["hytale","protocol"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saiintbrisson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-14T19:34:37.000Z","updated_at":"2026-01-21T20:55:13.000Z","dependencies_parsed_at":"2026-01-15T02:06:58.663Z","dependency_job_id":"dfe825cf-3ddb-43d5-8de9-91487f7214eb","html_url":"https://github.com/saiintbrisson/armadillo","commit_stats":null,"previous_names":["saiintbrisson/armadillo"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/saiintbrisson/armadillo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saiintbrisson%2Farmadillo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saiintbrisson%2Farmadillo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saiintbrisson%2Farmadillo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saiintbrisson%2Farmadillo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saiintbrisson","download_url":"https://codeload.github.com/saiintbrisson/armadillo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saiintbrisson%2Farmadillo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28849512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T15:15:36.453Z","status":"ssl_error","status_checked_at":"2026-01-28T15:15:13.020Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hytale","protocol"],"created_at":"2026-01-16T13:10:04.556Z","updated_at":"2026-01-28T19:10:41.348Z","avatar_url":"https://github.com/saiintbrisson.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Armadillo Proxy\n\nArmadillo is a QUIC, TLS-terminating, proxy that sits between Hytale clients and servers, handling authentication on behalf of the server. Allowing full visibility into the contents.\n\n```mermaid\nflowchart LR\n    subgraph External\n        Sessions[(sessions.hytale.com)]\n    end\n\n    Player \u003c--\u003e|TLS\u003cbr\u003eFull Hytale Auth| Proxy\n    Proxy \u003c--\u003e|TLS\u003cbr\u003eBypassed Auth| Server\n\n    Proxy --\u003e Analysis[Decrypted\u003cbr\u003eTraffic Analysis]\n\n    Player -.-\u003e|auth requests| Sessions\n    Proxy -.-\u003e|auth requests| Sessions\n```\n\n\u003cvideo src=\"https://github.com/user-attachments/assets/5bb292a4-e21b-4e46-9295-5a20fc911d77\" controls preload\u003e\u003c/video\u003e\n\n## Quick Start\n\nBuild and install the server plugin:\n\n```bash\ncd plugin\n./gradlew build\ncp build/libs/offline-mode-0.1.0.jar /path/to/server/mods/\n```\n\nRun the proxy:\n\n```bash\ncargo build --release\n\ncp /path/to/server/auth.enc . # we need a recent auth.enc to impersonate the server\n./target/release/armadillo-proxy --listen 0.0.0.0:5520 --upstream 127.0.0.1:5521\n```\n\nPoint your client to the proxy bind address. The server must listen on the upstream port with the plugin loaded. If you encounter issues like a 400 on proxy startup, refresh your `auth.enc` file by logging out (`/auth logout`) and logging in (`/auth login device`) again.\n\n## Why and how?\n\nFirst, because it's fun. Second, it's a good starting point for those looking into how to extend the server.\n\nHytale uses QUIC, which in turn uses TLS 1.3. This version of TLS comes with perfect forward secrecy out of the box, making it impossible to eavesdrop a communication\nbetween peers without actively participating. If you try simply terminating the TLS, the Hytale server will notice your certificate does not match the player's you\nare connecting on behalf.\n\nLuckily, we are in Java-land. A simple mod (plugin) is enough to patch the server in a way to bypass the certificate validation. By using reflection in 3 specific\npoints, the server allows unauthenticated players to join:\n* By overriding the logic in `JWTValidator`, we can still parse relevant token information without validatin the player's certificate\n* A patch to `SessionServiceClient` allows us to avoid requests to Hytale's servers\n* Inserting a fake game session to `ServerAuthManager` avoid a set of other requests\n\nYou can find more in [AuthBypass.java](./plugin/src/main/java/rs/luiz/hytale/offline_mode/AuthBypass.java).\n\n### Player -\u003e Proxy\n\nThe proxy validates JWT tokens using EdDSA (Ed25519) signatures. Public keys are fetched from the session service's JWKS endpoint and cached. This is the same process handled by the server JAR.\n\n```mermaid\nsequenceDiagram\n    participant C as Client\n    participant P as Proxy\n    participant S as Session Service\n\n    C-\u003e\u003eP: Connect packet (identity_token, uuid, username)\n    P-\u003e\u003eP: Validate identity_token signature (EdDSA)\n    P-\u003e\u003eS: POST /server-join/auth-grant\n    S--\u003e\u003eP: authorization_grant\n    P-\u003e\u003eC: AuthGrant packet (authorization_grant, server_identity_token)\n    C-\u003e\u003eP: AuthToken packet (access_token, server_authorization_grant)\n    P-\u003e\u003eP: Validate access_token signature\n    P-\u003e\u003eS: POST /server-join/auth-token (exchange server_authorization_grant)\n    S--\u003e\u003eP: server_access_token\n    P-\u003e\u003eC: ServerAuthToken packet (server_access_token)\n```\n\n### Proxy -\u003e Server\n\nThe patched server ignores all validation and only extracts the necessary information from the client's token. After authentication is done, traffic can be relayed.\n\n```mermaid\nsequenceDiagram\n    participant P as Proxy\n    participant U as Upstream Server\n\n    P-\u003e\u003eU: Connect packet (original from client)\n    U-\u003e\u003eP: AuthGrant packet\n    P-\u003e\u003eU: AuthToken packet (client's access_token)\n    U-\u003e\u003eP: ServerAuthToken packet\n    Note over P,U: Bidirectional relay begins\n```\n\n## The auth.enc file\n\nCredentials are encrypted with AES-256-GCM. The key is derived from the machine's hardware UUID using PBKDF2-HMAC-SHA256 (100k iterations, salt: `HytaleAuthCredentialStore`).\n\n#### Encrypted file format\n\n| Offset | Size | Content |\n|--------|------|---------|\n| 0 | 12 | Nonce/IV |\n| 12 | rest | Ciphertext + GCM tag |\n\n#### Decrypted file format\n\n| Offset | Size | Content |\n|--------|------|---------|\n| 0 | 4 | Header (zeros) |\n| 4+ | var | Field entries (repeated) |\n\nEach entry:\n\n| Size | Content |\n|------|---------|\n| 1 | Separator (0x00) |\n| var | Key name (null-terminated) |\n| 4 | Value length (LE u32) |\n| var | Value bytes |\n\nAnd the fields: `AccessToken`, `RefreshToken`, `ExpiresAt`, `ProfileUuid`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaiintbrisson%2Farmadillo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaiintbrisson%2Farmadillo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaiintbrisson%2Farmadillo/lists"}