From 0270dd5739480acced62e045b5890ec0ebde2631 Mon Sep 17 00:00:00 2001
From: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Date: Fri, 9 Oct 2026 17:15:07 +0800
Subject: [PATCH] feat(website): add an Aegis APK code-generation showcase
---
website/README.md | 18 +-
website/evidence/aegis-login-code.md | 139 ++++
website/figures.md | 12 +
website/public/assets/aegis-demo.js | 84 +++
website/public/assets/aegis-otp.js | 36 +
website/public/assets/styles.css | 63 +-
website/public/index.html | 10 +-
website/public/showcase/aegis/index.html | 682 ++++++++++++++++++
.../public/showcase/aegis/test-vectors.json | 14 +
website/public/showcase/index.html | 24 +-
website/style-guide.md | 17 +-
11 files changed, 1084 insertions(+), 15 deletions(-)
create mode 100644 website/evidence/aegis-login-code.md
create mode 100644 website/public/assets/aegis-demo.js
create mode 100644 website/public/assets/aegis-otp.js
create mode 100644 website/public/showcase/aegis/index.html
create mode 100644 website/public/showcase/aegis/test-vectors.json
diff --git a/website/README.md b/website/README.md
index 6f9af6887e..1b4d0806b0 100644
--- a/website/README.md
+++ b/website/README.md
@@ -4,7 +4,7 @@
>
> — N0zoM1z0
-An English static website with explanatory figures, worked guides and DX-Ball, Notion, TH04 and CTF investigations.
+An English static website with explanatory figures, worked guides and Aegis, DX-Ball, Notion, TH04 and CTF investigations.
The public files are in `website/public/`. The site uses HTML, CSS and small
scripts for copying code, following code comparisons and playing the dinosaur
speed reconstruction. Python
@@ -30,6 +30,7 @@ Open . Refresh the browser after editing a file.
- `public/examples/dino-lab/index.html`: adjustable-speed mini-game, recovered rule, original-game check and browser analysis steps.
- `public/first-investigation/index.html`: a guided Notes export investigation, from setup to a checked CSV prediction.
- `public/showcase/index.html`: the case-study index.
+- `public/showcase/aegis/index.html`: Aegis's Android login-code calculation, with an adjustable clock and reference checks.
- `public/showcase/dx-ball/index.html`: sound-pan investigation and project status.
- `public/showcase/notion/index.html`: Notion's Electron clipboard bridge and rich clipboard format.
- `public/showcase/th04/index.html`: TH04's 16-bit DOS bullet-angle calculation and compiler checks.
@@ -158,6 +159,21 @@ the website.
[evidence/notion-clipboard.md](evidence/notion-clipboard.md) records the REA
package version, selected findings, source anchors and module-probe scope.
+## Aegis Android case study
+
+The Aegis case inspects the official 3.4.3 APK through REA 6.1.0. It follows
+the default login-code calculation from class search and display references to
+the time block, keyed hash and six-digit output. Selected decompiled Java is
+paired with a readable summary; the original app and excerpts are credited to
+Aegis under its GPL-3.0 license.
+
+`public/assets/aegis-otp.js` is a new teaching reconstruction using the fixed,
+public RFC 6238 test key. `aegis-demo.js` connects it to the clock slider and
+reference-check button. The diagram remains readable and controls stay disabled
+without JavaScript. Keep the demo, selected code and
+[evidence/aegis-login-code.md](evidence/aegis-login-code.md) aligned. The APK and
+analysis-provider JAR remain official external downloads.
+
## TH04 case study
The TH04 case inspects the original PC-98 DOS angle helper through REA 4.1.0.
diff --git a/website/evidence/aegis-login-code.md b/website/evidence/aegis-login-code.md
new file mode 100644
index 0000000000..9567fba88a
--- /dev/null
+++ b/website/evidence/aegis-login-code.md
@@ -0,0 +1,139 @@
+# Aegis Android login-code evidence
+
+Inspection on 9 October 2026, using the published REA 6.1.0 CLI with the
+caller-supplied `jadx-headless-mcp` 0.7.1 provider and OpenJDK 21.0.12.1 on
+Linux x64. The case follows the default time-based code in
+[Aegis Authenticator](https://github.com/beemdevelopment/Aegis).
+
+## Target
+
+- [Official release](https://github.com/beemdevelopment/Aegis/releases/tag/v3.4.3): v3.4.3, published 6 September 2026.
+- Artifact: `aegis-v3.4.3.apk`, 6,881,897 bytes.
+- SHA-256: `fa091c91912c0d56ec3553394fac4158f9a9d178e93bcbb35419601d788cb528`.
+- Package: `com.beemdevelopment.aegis`, version code 82.
+- Reported inventory: 3,077 classes and 1,106 resources.
+- Matching source commit: `d6f4e5925a97e4e91593f1542085eae03432a759`.
+- Android provider JAR SHA-256: `6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75`.
+- Provider source revision: `5844800a486d2248fa949b74c9896285f5b54de2`.
+
+The artifact's SHA-256 matches the official GitHub release asset digest and every
+saved REA record. The APK and provider JAR were downloaded into temporary storage.
+They are linked from their official releases; neither file is a website asset.
+
+The CLI used `REA_JADX_MCP_JAR` for its own process. The connected MCP server's
+Android provider was initially unavailable; it was not reconfigured. The page
+expresses the inspected selections as REA tool requests, using the same operation
+parameters as the successful CLI calls. Input paths and result package prefixes
+are shortened for display, as noted beside those blocks.
+
+## REA findings
+
+Twenty REA operations completed successfully against this artifact. These are the
+records used for the page's main findings:
+
+| Operation | Finding | Evidence ID |
+| -------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------- |
+| `inspect_android_method` | Display calls the timestamp overload for TotpInfo. | `ev_c4b51611c987a398359f526dc64866d97a99b146d0ec9177bc1d583a55d64bdc` |
+| `trace_android_references` | TotpInfo is one of the three incoming generator callers. | `ev_6b5457705a67bd4952f7e17630bcf948538424fae5bc2951c08e921af7448d58` |
+| `inspect_android_method` | Eight-byte big-endian counter, account key and HMAC. | `ev_cad4c03faf5b07347cba699d4f8f643c69e5a8f0c85f622fc8cbebe3f834f228` |
+| `inspect_android_method` | Hash-byte selection produces a 31-bit integer. | `ev_5797488db16e72a4e9ad559a8f07e355adc1f73b9eb50566cfb46d47d1b6a883` |
+| `inspect_android_method` | Algorithm name is prefixed with Hmac. | `ev_bffbfa3924c79823168df7daa01e8a3f62c4914d3fb4b54e5d4e60d21e75110f` |
+| `trace_android_references` | Display and copy callers of the base method. | `ev_d90e3ed81b0bb6815826e4edf312eadec91b9d20ff06aaff61d38a191403676b` |
+| `inspect_android_method` | Default SHA1 algorithm and six digits. | `ev_64294487704fa2a9877938017c95163e41c399ba958ea43c5b365118403ae0fe` |
+| `inspect_android_method` | Decimal remainder and leading-zero padding. | `ev_5d0906d19ea9281fed36309794fd5697b54cac3abfbd17e2f78665e758e0eb60` |
+| `inspect_android_method` | Class discriminator 0 selects the OTP formatting branch. | `ev_f0a82295bf6124055b7a12a21533950644267e8e8340038bca9c32db57d8d71f` |
+| `inspect_android_package` | Package identity; 3,077 classes. | `ev_de07111c281cd76c4f2304f42448b06ef3199268815515d59caa02ea2480eb67` |
+| `inspect_android_class` | Both getOtp overloads and their selection indices. | `ev_870577d702741f3023494c1bcb6567381a672a7132a60fd35ea2dd21ab9804c8` |
+| `search_android_classes` | Three matches for the case-sensitive query Totp. | `ev_deeb75a09990e253881d0dc1932097abe00f94447d29a64c782fb48c42e9f492` |
+| `inspect_android_method` | Current clock in milliseconds is converted to seconds. | `ev_ff4d8be5b4797e6f118d37ed55a2f65c9ceb8df39e8058d2cf36cd5561dc4bfd` |
+| `inspect_android_method` | Default period: 30 seconds. | `ev_67af69cd39faceec616a9b1b48b03a5ea71b9c94ff2d1263a0a0063029cc1104` |
+| `inspect_android_method` | Time is floored into a block before generation. | `ev_f282f536e5690e3e2253903bd979687687cfa5a9a4480758b4cd261da145caaf` |
+
+All selected methods returned complete Java representations without a fallback.
+Signatures are provider display signatures; exact DEX descriptors, source-line
+locations and instruction offsets are not available from these results.
+Reference lists are static incoming references, with complete coverage of the
+engine's reported set; reflection and dynamic loading remain unverified.
+
+## Interpretation
+
+`TotpInfo.getOtp()` obtains Unix time in seconds. Its timestamp overload uses
+`floor(seconds / period)` as the generator's counter. The default constructor
+sets the period to 30; the base constructor sets SHA1 and six digits.
+These are defaults, not settings imposed on every imported account.
+
+`getAlgorithm()` constructs `HmacSHA1` for that default. The generator encodes the
+counter as eight big-endian bytes, calculates the keyed hash, uses the low four
+bits of the final hash byte as an offset, and selects a positive 31-bit integer.
+The `OTP.toString()` branch for discriminator 0 reduces it modulo the requested
+power of ten and prepends zeroes. The inspected generator passes discriminator 0
+into the constructor, connecting that branch to the generated code.
+
+The release exposes `generateOTP` and `getHash` under `kotlin.ExceptionsKt`.
+Original-source naming alone would not identify that class in this APK.
+The call returned from `TotpInfo.getOtp(long)` supplies the helper name; REA's
+method inspection and reference tracing establish its calculation and callers.
+
+The base `OtpInfo.getOtp` reference list includes `EntryHolder.getOtp` and
+`MainActivity.copyEntryCode`. Inspecting `EntryHolder.getOtp(int)` then shows that
+the display calls the timestamp overload for a `TotpInfo` account, with an
+optional period offset. The page uses the unshifted code calculation.
+
+## Reconstruction checks
+
+A temporary JVM harness assembled six method bodies directly from saved REA
+results: the timestamp method, algorithm getter, hash method, generator, output
+constructor and output formatter. Imports, enclosing classes, fields, exception
+type and test driver were supplied for the harness. The original APK was not run.
+
+An independently authored Python calculation agreed with those Java methods on
+133 inputs. The website's separately authored WebCrypto implementation then
+agreed with all 133 recorded Java outputs.
+
+The cases include:
+
+- All six [RFC 6238 SHA-1 reference vectors](https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B) at eight digits, plus the corresponding six-digit remainders.
+- Every integer second from 0 through 120, checking four complete 30-second blocks and four boundary samples.
+- A leading-zero result at Unix time 1,111,111,109: `081804`.
+
+The fixed key is the public ASCII test string `12345678901234567890`.
+At 30 and 59 seconds the result is `287082`; at 60 seconds it is `359152`.
+The diagram labels these as example clock inputs. A code is recomputed for each
+block; the checked examples change at their boundaries. Adjacent codes need not
+be universally distinct.
+
+The page's “Run reference checks” button tests the browser calculation against
+all six reference inputs at both digit lengths. Slider updates use a revision
+number so an earlier asynchronous calculation cannot overwrite a later input.
+The reference JSON contains public test data, not a captured account key.
+
+## Source comparison and attribution
+
+After obtaining the calculation through REA, selected files from the matching
+release source were read for corroboration:
+
+- [HOTP.java](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/HOTP.java): counter encoding, HMAC and byte selection.
+- [TOTP.java](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/TOTP.java): time-to-counter transformation.
+- [OTP.java](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/OTP.java): decimal output and zero padding.
+
+These files confirm the interpretation. The public page's selected decompiled
+Java comes from the APK evidence. It includes fragments from several methods and
+line wrapping for display; the paired readable summary is an explanation.
+The expanded generator panel retains its complete returned body, with formatting
+changes. Aegis excerpts are credited under the upstream
+[GPL-3.0 license](https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/LICENSE).
+The diagram, explanatory summary, demo and its WebCrypto implementation are new
+teaching material; the demo is not recovered original application source.
+
+## Scope and maintenance
+
+The claim is a static APK investigation and a checked reconstruction of its
+default code calculation. It covers neither Android UI execution nor APK
+signature verification, split APK handling, native libraries or vault storage.
+The shell walkthrough was executed on Linux. The PowerShell recipe uses the
+same CLI/environment inputs but was not executed on a Windows host.
+
+Raw REA results, provider scratch paths, Java harness classes and the downloaded
+binaries remain outside the public website. The public page uses generic filenames
+and the public test key. Update the release identity, selected excerpts, demo,
+reference data and these notes together when moving to another Aegis version.
diff --git a/website/figures.md b/website/figures.md
index c0ab93d609..5cf50ce29f 100644
--- a/website/figures.md
+++ b/website/figures.md
@@ -73,6 +73,18 @@ are new teaching code. Check that the fallback is visible with JavaScript
disabled and hidden when the playable canvas loads. Keep the speed settings,
source excerpt, reconstruction and original-result table consistent.
+## Aegis login-code figure
+
+The Aegis overview and adjustable-clock figure are semantic HTML. The clock
+diagram shows seconds, the 30-second block and the resulting six-digit code,
+using the public RFC 6238 test key. It retains a static 59-second example when
+JavaScript is disabled. The three code selections connect each operation to the
+APK's selected Java and an explanatory summary.
+
+[evidence/aegis-login-code.md](evidence/aegis-login-code.md) records the inspected
+APK, methods, source attribution and reconstruction checks. Keep the block
+formula, default settings, slider outputs and reference cases consistent.
+
## Original image generation prompts
## Prompt 1
diff --git a/website/public/assets/aegis-demo.js b/website/public/assets/aegis-demo.js
new file mode 100644
index 0000000000..74afa79b30
--- /dev/null
+++ b/website/public/assets/aegis-demo.js
@@ -0,0 +1,84 @@
+import { generateExampleCode } from "./aegis-otp.js";
+
+async function initializeAegisDemo() {
+ const demo = document.querySelector("[data-aegis-demo]");
+ if (demo === null) return;
+ const clock = demo.querySelector("input[type=range]");
+ const controls = demo.querySelectorAll("input, button");
+ const status = demo.querySelector("[data-aegis-status]");
+ let revision = 0;
+
+ const updateTime = async (seconds) => {
+ const currentRevision = ++revision;
+ try {
+ const code = await generateExampleCode(seconds);
+ if (currentRevision !== revision) return false;
+ const block = Math.floor(seconds / 30);
+ demo.querySelector("[data-aegis-seconds]").textContent = String(seconds);
+ demo.querySelector("[data-aegis-block]").textContent = String(block);
+ demo.querySelector("[data-aegis-division]").textContent =
+ `floor(${seconds} / 30)`;
+ demo.querySelector("[data-aegis-window]").textContent =
+ `${block * 30}–${block * 30 + 29} seconds`;
+ demo.querySelector("[data-aegis-code]").textContent = code;
+ clock.setAttribute(
+ "aria-valuetext",
+ `${seconds} seconds, time block ${block}`,
+ );
+ status.textContent = "";
+ return true;
+ } catch {
+ if (currentRevision === revision) {
+ status.textContent =
+ "Interactive calculation is unavailable in this browser. The example shows the code at 59 seconds.";
+ }
+ return false;
+ }
+ };
+
+ if (!(await updateTime(Number(clock.value)))) return;
+ controls.forEach((control) => {
+ control.disabled = false;
+ });
+ clock.addEventListener("input", async () => {
+ await updateTime(Number(clock.value));
+ });
+ demo.querySelectorAll("[data-aegis-time]").forEach((button) => {
+ button.addEventListener("click", async () => {
+ clock.value = button.getAttribute("data-aegis-time");
+ await updateTime(Number(clock.value));
+ });
+ });
+
+ const checkButton = document.querySelector("[data-aegis-check]");
+ const checkResult = document.querySelector("[data-aegis-check-result]");
+ checkButton.disabled = false;
+ checkButton.addEventListener("click", async () => {
+ checkButton.disabled = true;
+ checkResult.textContent = "Checking…";
+ try {
+ const response = await fetch(
+ new URL("../showcase/aegis/test-vectors.json", import.meta.url),
+ );
+ if (!response.ok) throw new Error("Reference data unavailable");
+ const { vectors } = await response.json();
+ let passed = 0;
+ for (const vector of vectors) {
+ for (const digits of [6, 8]) {
+ const code = await generateExampleCode(vector.seconds, digits);
+ if (code === vector.sha1.slice(-digits)) passed += 1;
+ }
+ }
+ checkResult.textContent =
+ `${passed} / ${vectors.length * 2} checks passed ` +
+ "(six reference cases, at six and eight digits).";
+ } catch {
+ checkResult.textContent =
+ "Could not run the reference checks. Try again.";
+ } finally {
+ checkButton.disabled = false;
+ }
+ });
+}
+
+await initializeAegisDemo();
diff --git a/website/public/assets/aegis-otp.js b/website/public/assets/aegis-otp.js
new file mode 100644
index 0000000000..0952a6070c
--- /dev/null
+++ b/website/public/assets/aegis-otp.js
@@ -0,0 +1,36 @@
+// Teaching reconstruction of the calculation inspected in Aegis v3.4.3.
+// The key is public RFC 6238 test data, not an account credential.
+const testKey = new TextEncoder().encode("12345678901234567890");
+let importedKey;
+
+/** Generate a code with the public test key and a 30-second time step. */
+export async function generateExampleCode(seconds, digits = 6) {
+ if (
+ !Number.isSafeInteger(seconds) ||
+ seconds < 0 ||
+ ![6, 8].includes(digits)
+ ) {
+ throw new RangeError(
+ "Use a nonnegative integer time and six or eight digits.",
+ );
+ }
+ importedKey ??= crypto.subtle.importKey(
+ "raw",
+ testKey,
+ { name: "HMAC", hash: "SHA-1" },
+ false,
+ ["sign"],
+ );
+ const key = await importedKey;
+ const block = Math.floor(seconds / 30);
+ const counter = new ArrayBuffer(8);
+ new DataView(counter).setBigUint64(0, BigInt(block), false);
+ const hash = new Uint8Array(await crypto.subtle.sign("HMAC", key, counter));
+ const offset = hash[hash.length - 1] & 15;
+ const number =
+ ((hash[offset] & 127) << 24) |
+ ((hash[offset + 1] & 255) << 16) |
+ ((hash[offset + 2] & 255) << 8) |
+ (hash[offset + 3] & 255);
+ return String(number % 10 ** digits).padStart(digits, "0");
+}
diff --git a/website/public/assets/styles.css b/website/public/assets/styles.css
index adf44815bf..ee2a3772dc 100644
--- a/website/public/assets/styles.css
+++ b/website/public/assets/styles.css
@@ -261,6 +261,14 @@ section[id] {
background: #38424e;
text-decoration: none;
}
+.button.secondary {
+ border-color: var(--line);
+ background: var(--page);
+ color: var(--ink);
+}
+.button.secondary:hover {
+ background: var(--soft);
+}
.text-link {
font-size: 0.95rem;
font-weight: 500;
@@ -689,6 +697,59 @@ pre code {
.case-figure {
margin-bottom: 3.2rem;
}
+.aegis-step-selector {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+.aegis-step-selector button {
+ min-height: 44px;
+}
+.aegis-calculation .flow-node {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.35rem;
+ min-height: 3.5rem;
+ font-variant-numeric: tabular-nums;
+}
+.aegis-calculation .aegis-code {
+ font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
+ font-size: 1.5rem;
+ letter-spacing: 0.06em;
+}
+.aegis-clock-controls {
+ margin-top: 1.7rem;
+}
+.aegis-clock-controls label {
+ display: block;
+ font-size: 0.875rem;
+ font-weight: 500;
+}
+.aegis-clock-controls input {
+ display: block;
+ width: 100%;
+ min-height: 44px;
+ margin: 0;
+ accent-color: var(--accent);
+}
+.aegis-clock-scale {
+ display: flex;
+ justify-content: space-between;
+ color: var(--muted);
+ font-size: 0.75rem;
+ font-variant-numeric: tabular-nums;
+}
+.aegis-clock-controls .actions {
+ gap: 0.7rem;
+ margin-top: 1.2rem;
+}
+.aegis-clock-controls .caption {
+ margin-bottom: 0;
+}
+.aegis-demo .button:disabled,
+[data-aegis-check]:disabled {
+ opacity: 0.6;
+ cursor: default;
+}
.step-selector {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
@@ -1456,7 +1517,7 @@ pre code {
.comparison-label {
padding-bottom: 0.8rem;
border-bottom: 1px solid var(--line);
- font-size: 0.875rem;
+ font-size: 1.125rem;
font-weight: 600;
}
.agent-investigation > .comparison-label {
diff --git a/website/public/index.html b/website/public/index.html
index c8c3649add..492d595b41 100644
--- a/website/public/index.html
+++ b/website/public/index.html
@@ -167,7 +167,10 @@
class="manual-investigation step-comparison"
data-step-comparison
>
-
Before REA · You investigate
+
+ Before REA · You
+ investigate
+
-
With REA · You ask your agent
+
+ With REA · You ask
+ your agent
+
One prompt.
Ask your agent in plain English.
diff --git a/website/public/showcase/aegis/index.html b/website/public/showcase/aegis/index.html
new file mode 100644
index 0000000000..d9bde85ac0
--- /dev/null
+++ b/website/public/showcase/aegis/index.html
@@ -0,0 +1,682 @@
+
+
+
+
+
+ How an authenticator generates a login code — REA
+
+
+
+
+
+
+
+
+ Skip to content
+
+
+ 01 · Locate the feature3,077 classes → generating methodsREA searches the package and traces the code used by the display
+ and copy actions.
+
+
+ 02 · Read the calculationTime + account key → six digitsREA returns the methods and defaults. The agent explains how they
+ fit together.
+
+
+ 03 · Rebuild and checkChange the clock. Watch the code.A new browser demo reproduces the rule and checks it against
+ public reference cases.
+
+
+
+
+
+
+
+
+
Ask your agent
+
+ The app shows a changing login code. We want to find
+ what makes it change and reproduce that behavior.
+
+
+
+ Your coding agent
+
+
+ ›Use REA to inspect aegis-v3.4.3.apk. Find how it generates
+ the six-digit login code, explain why it changes every 30
+ seconds, and rebuild a small demo where I can change the
+ time.
+
+ The app groups time into
+ 30-second blocks. It combines
+ the block number with the account key to generate a code. The same
+ key and block produce the same code.
+
+ TotpInfo is the calculation candidate; the other
+ two concern the progress bar and imported accounts. TOTP means
+ a time-based one-time password.
+
+ REA identifies the timestamp overload and finds the base
+ method's callers. Inspecting
+ EntryHolder.getOtp then shows the display calling
+ TotpInfo.getOtp(timestamp).
+
+
+
+
+ Requests show a shortened input path. Result class names omit the
+ common com.beemdevelopment.aegis prefix.
+
+
+
+
+
Read the calculation
+
+ REA returns
+ the clock conversion, default settings and generating
+ methods.
+ The constructors set a 30-second interval and six digits; the
+ timestamp method turns seconds into a block number.
+
// Group time into 30-second blocks
+seconds = current_time_ms / 1000
+block = floor(seconds / 30)
+
+// Generate a number from the key and block
+hash = HMAC_SHA1(account_key,
+ big_endian_8_bytes(block))
+number = select_31_bits(hash)
+
+// Format the default six-digit code
+code = number % 1_000_000
+code = pad_with_zeroes(code, 6)
+
+
+
+
+ Time chooses the block. Seconds 30 through 59
+ all give block 1. At 60 seconds, the block becomes 2.
+
+
+
+
+ The key matters too. The generator combines
+ the account key with the block. An account with a different
+ key can show a different code at the same time.
+
+
+
+
+ Keep six digits. The remainder after division
+ by 1,000,000 is padded with zeroes when needed, so a code can
+ begin with 0.
+
+
+
+
+ Excerpts from several inspected methods, with line wrapping for
+ display. The right panel is an explanatory summary.
+ Aegis code is GPL-3.0.
+
+
+ Inside the generator
+
+ The released APK puts generateOTP in
+ kotlin.ExceptionsKt. REA follows the call from
+ TotpInfo and returns this body; the original source
+ calls the helper HOTP.
+
+ The last hash byte selects a position. Four bytes at that
+ position provide a positive 31-bit number; formatting reduces it
+ to the requested number of digits. The constructor's last
+ argument selects the code-formatting branch introduced by
+ compilation.
+
+ We assembled the selected REA-returned Java methods in a small
+ test program. Their output matched an independent reconstruction
+ on 133 test cases, including time-block
+ boundaries and codes beginning with zero.
+
+
+
+
+
+
Example time
+
Block
+
Six-digit code
+
+
+
+
+
30 seconds
+
1
+
287082
+
+
+
59 seconds
+
1
+
287082
+
+
+
60 seconds
+
2
+
359152
+
+
+
1,111,111,109 seconds
+
37,037,036
+
081804
+
+
+
+
+
+ The generator also matches the six published SHA-1 reference cases
+ in
+ RFC 6238. Check the browser implementation against them:
+
+ Your agent can continue through REA's CLI using the prompt above.
+ For MCP, add REA_JADX_MCP_JAR to the REA server's
+ environment and reconnect it.
+
+
+ A next question:
+ what happens when an account uses eight digits or a different
+ time interval?
+
+ Inspected with REA 6.1.0 on 9 October 2026. Decompiled excerpts
+ are credited to Aegis; the diagram, readable summary and browser
+ reconstruction are new teaching material.
+
- Game reconstruction, Electron analysis and a CTF challenge, with code,
- figures and checked results.
+ Android, games, Electron and a CTF challenge, with code, figures and
+ checked results.
+
+
Android · APK analysis
+
+
How an authenticator generates a login code
+
+ Find Aegis's six-digit code calculation in its released APK. Trace
+ the generating methods with REA, then move a demo clock to see why
+ the code changes every 30 seconds.
+
diff --git a/website/style-guide.md b/website/style-guide.md
index 285ba39ae6..a696837957 100644
--- a/website/style-guide.md
+++ b/website/style-guide.md
@@ -142,14 +142,15 @@ purposes, and immutable commit links for checkpoint-dependent facts.
Each figure should answer a question that a reader can name. Choose the visual
form that fits it:
-| Relationship | Existing example | Useful form |
-| ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------- |
-| Analysis and verification steps | DX-Ball sound pan | Flow with separate verification branches |
-| Code across process boundaries | Electron CSV export and Notion clipboard | HTML flow with APIs and channel names |
-| A mathematical transformation | TH04's fixed and aimed rings | SVG drawn from the angle formula |
-| Original instructions and readable source | DX-Ball and TH04 | Selectable HTML code with matching step highlights |
-| A request caused by an action | Notes browser export | Flow, observed result table and script excerpt |
-| Recovered behavior and a new experiment | Dinosaur speed reconstruction | Inspected code, playable demo and original-result check |
+| Relationship | Existing example | Useful form |
+| ----------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------- |
+| Analysis and verification steps | DX-Ball sound pan | Flow with separate verification branches |
+| Code across process boundaries | Electron CSV export and Notion clipboard | HTML flow with APIs and channel names |
+| A mathematical transformation | TH04's fixed and aimed rings | SVG drawn from the angle formula |
+| Original instructions and readable source | DX-Ball and TH04 | Selectable HTML code with matching step highlights |
+| A request caused by an action | Notes browser export | Flow, observed result table and script excerpt |
+| Recovered behavior and a new experiment | Dinosaur speed reconstruction | Inspected code, playable demo and original-result check |
+| Time blocks and changing output | Aegis login-code reconstruction | Adjustable clock, block number and code beside recovered methods |
Use SVG or semantic HTML for diagrams with exact text, numbers and arrows.
Generated illustrations can help explore a layout, but the published labels,