Files
rea/website/public/showcase/aegis/index.html
T
12ee785e5e feat(website): follow the system dark mode and fix small-screen text (#1894)
* fix(website): keep text inside small screens and tidy small type and spacing

From a layout audit of the built pages:

- Long terminal prompts and code-header buttons wrap instead of being cut
  off at 320px (WCAG 1.4.10).
- Headings and table cells break long words, so the 1.4.12 text-spacing
  test no longer widens pages past 320px.
- Header and footer links get a 24px minimum height (2.5.8).
- Labels that rendered under 12px now render at 12px or more, and inline
  code never drops under 0.75rem.
- The home page's hero and definition rows share one column gap and align
  on the first baseline, and stacked boxes share one corner size.
- Highlight chips get room around the text, and the active run in a step
  listing is one band instead of a box per line.

Colors are unchanged.

🤖 Generated with Claude Code (Sonnet 5.5) 🦊

* feat(website): follow the system dark mode

The site was light only, so a reader with a dark system still got a white
page. Add one prefers-color-scheme: dark block to the stylesheet that swaps
the six color variables to Catppuccin Mocha (MIT) and overrides the fixed
colors that would break on a dark page: selection, buttons, tinted
highlights, flow nodes and arrows, and a visible border on the agent
terminal.

Add a dark theme-color tag beside the light one in the page template and
the 17 pages, and a Dark column to the style guide's color table.

Light colors are unchanged. The SVG figures follow in the next commit; the
blog page's inline strokes, the dinosaur game and the social card are left
as they are.

🤖 Generated with Claude Code (Sonnet 5.5) 🦊

* feat(website): give the five SVG figures a dark scheme

Pages load the figures with <img>, so page CSS cannot reach inside them.
Each figure now carries its own @media (prefers-color-scheme: dark) block
of attribute-selector overrides that map every light color to a Catppuccin
Mocha color, with one shared map across all five. No markup, labels,
shapes or positions change, and nothing uses !important.

Four figures also paint a mantle canvas so "Open figure" works on its own;
analyst-thinking.svg stays transparent, since it sits on the page rather
than in a figure box.

🤖 Generated with Claude Code (Sonnet 5.5) 🦊

* chore(website): refresh translation source references

The theme-color tags move the page lines that the catalogs cite, so
python3 scripts/website.py translations extract rewrites the source
references in messages.pot and the 18 PO files. No message text changes.
The same run moves the "Main navigation" entry to its new position in each
catalog.

🤖 Generated with Claude Code (Sonnet 5.5) 🦊

* fix(website): keep inline step highlights inline

The full-width band for the active step now applies only to code-step
blocks. The inline parameter highlights in the dx-ball and th04
signatures stay inline again.

🤖 Generated with Claude Code (Opus 5.5) 🦊

* test(website): check every page offers light and dark theme colors

Each authored reading page, and its built copy in every language,
must carry one theme-color tag for light and one for dark. The
stylesheet must keep its dark color scheme block. On the commit before
dark mode, this test fails on every page.

🤖 Generated with Claude Code (Opus 5.5) 🦊

* fix(website): draw the dinosaur game in the page colors

In dark mode the game box turned dark, but the game still drew with
its light colors, so the dinosaur, cacti and text fell to about 2:1
contrast. The canvas now reads five colors from CSS variables on
.dino-stage. Light values are the old ones, so light mode draws the
same pixels. Dark values are Catppuccin Mocha: 8.3:1 for the
dinosaur, 7.9:1 for cacti and text, 7.6:1 for the crash color.

The moved lines in dino-demo.js shift the translation catalog
references, so the catalogs are refreshed too (reference comments
only).

🤖 Generated with Claude Code (Opus 5.5) 🦊

* fix(website): recolor the Touhou flywheel arrows in dark mode

The inline flywheel SVG on the Touhou article hard-codes its stroke
colors, so on the dark page its connectors fell to about 2:1. Two
dark-only rules map those strokes to the page accent and muted colors
(7.8:1 and 7.4:1). Light mode is unchanged.

🤖 Generated with Claude Code (Opus 5.5) 🦊

* fix(website): redraw the dinosaur game when the system theme changes

The canvas reads its colors only when it draws, so an idle, paused or
crashed game kept the old palette after a theme switch. Each demo now
redraws on a prefers-color-scheme change.

The added lines shift the translation catalog references, so the
catalogs are refreshed too (reference comments only).

🤖 Generated with Claude Code (Opus 5.5) 🦊

---------

Co-authored-by: Claude Sonnet 5.5 <sonnet@cassie-pc>
Co-authored-by: Claude Opus 5.5 <opus@cassie-pc>
2026-10-12 03:17:49 +08:00

810 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Aegis APK Reverse Engineering: Login Codes — REA</title>
<meta
name="description"
content="Inspect the Aegis Android APK with REA, recover its six-digit login-code calculation and try a reconstruction with an adjustable clock."
/>
<!-- website:sharing:start -->
<!-- prettier-ignore -->
<link rel="canonical" href="https://rea.tools/showcase/aegis/" />
<!-- website:languages:start -->
<!-- prettier-ignore -->
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/aegis/" />
<!-- prettier-ignore -->
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/aegis/" />
<!-- website:languages:end -->
<!-- prettier-ignore -->
<meta property="og:type" content="website" />
<!-- prettier-ignore -->
<meta property="og:site_name" content="REA" />
<!-- prettier-ignore -->
<meta property="og:title" content="Aegis APK Reverse Engineering: Login Codes — REA" />
<!-- prettier-ignore -->
<meta property="og:description" content="Inspect the Aegis Android APK with REA, recover its six-digit login-code calculation and try a reconstruction with an adjustable clock." />
<!-- prettier-ignore -->
<meta property="og:url" content="https://rea.tools/showcase/aegis/" />
<!-- prettier-ignore -->
<meta property="og:image" content="https://rea.tools/assets/social-card.png" />
<!-- prettier-ignore -->
<meta property="og:image:type" content="image/png" />
<!-- prettier-ignore -->
<meta property="og:image:width" content="1200" />
<!-- prettier-ignore -->
<meta property="og:image:height" content="630" />
<!-- prettier-ignore -->
<meta
property="og:image:alt"
content="REA — Find out how software works. Reverse engineering with your coding agent."
/>
<!-- prettier-ignore -->
<meta name="twitter:card" content="summary_large_image" />
<!-- prettier-ignore -->
<meta name="twitter:title" content="Aegis APK Reverse Engineering: Login Codes — REA" />
<!-- prettier-ignore -->
<meta name="twitter:description" content="Inspect the Aegis Android APK with REA, recover its six-digit login-code calculation and try a reconstruction with an adjustable clock." />
<!-- prettier-ignore -->
<meta name="twitter:image" content="https://rea.tools/assets/social-card.png" />
<!-- prettier-ignore -->
<meta
name="twitter:image:alt"
content="REA — Find out how software works. Reverse engineering with your coding agent."
/>
<!-- website:sharing:end -->
<meta
name="theme-color"
content="#ffffff"
media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#1e1e2e"
media="(prefers-color-scheme: dark)"
/>
<link rel="icon" href="../../assets/favicon.svg" type="image/svg+xml" />
<link rel="stylesheet" href="../../assets/styles.css" />
<script src="../../assets/main.js" defer></script>
<script type="module" src="../../assets/aegis-demo.js"></script>
</head>
<body id="top">
<a class="skip-link" href="#main">Skip to content</a>
<!-- website:header:start -->
<!-- prettier-ignore -->
<header class="site-header">
<div class="container header-inner">
<a class="brand" href="../../" aria-label="REA home"
><span class="brand-name">REA</span
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
>
<nav class="navigation" aria-label="Main navigation">
<a href="../../showcase/" aria-current="page">Showcases</a>
<a href="../../blog/">Blog</a>
<a href="../../get-started/" class="nav-start">Get started</a>
<a href="../../guides/">Guides</a>
<a href="../../faq/">FAQ</a>
</nav>
<div class="header-social">
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../showcase/aegis/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/showcase/aegis/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/showcase/aegis/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/showcase/aegis/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/showcase/aegis/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/showcase/aegis/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/showcase/aegis/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/showcase/aegis/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/showcase/aegis/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/showcase/aegis/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/showcase/aegis/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/showcase/aegis/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/showcase/aegis/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/showcase/aegis/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/showcase/aegis/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/showcase/aegis/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/showcase/aegis/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/showcase/aegis/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/showcase/aegis/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
<a
class="nav-github"
href="https://github.com/morluto/rea"
aria-label="REA on GitHub"
title="REA on GitHub"
>
<svg
width="22"
height="22"
viewBox="0 0 16 16"
aria-hidden="true"
focusable="false"
>
<path
fill="currentColor"
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.65 7.65 0 0 1 2-.27c.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"
/>
</svg>
<span class="nav-github-count" hidden aria-hidden="true"></span>
</a>
<a
class="nav-discord"
href="https://discord.gg/GkcryMnJDM"
aria-label="Join REA on Discord"
title="Join REA on Discord"
>
<svg
width="22"
height="22"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
>
<path
fill="currentColor"
d="M20.317 4.3698a19.7913 19.7913 0 0 0-4.8851-1.5152.0741.0741 0 0 0-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 0 0-.0785-.037 19.7363 19.7363 0 0 0-4.8852 1.515.0699.0699 0 0 0-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 0 0 .0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 0 0 .0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 0 0-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 0 1-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 0 1 .0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 0 1 .0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 0 1-.0066.1276 12.2986 12.2986 0 0 1-1.873.8914.0766.0766 0 0 0-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 0 0 .0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 0 0 .0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 0 0-.0312-.0286ZM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189Zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"
/>
</svg>
</a>
<a
class="nav-x"
href="https://x.com/reatools"
aria-label="Follow REA on X"
title="Follow REA on X"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
aria-hidden="true"
focusable="false"
>
<path
fill="currentColor"
d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"
/>
</svg>
</a>
</div>
</div>
</header>
<!-- website:header:end -->
<main id="main" class="container">
<div class="page-heading">
<p class="breadcrumb">
<a href="../../">Home</a> / <a href="../">Showcases</a> / Android
</p>
<p class="eyebrow">Case study · Aegis Authenticator</p>
<h1>How does an authenticator<br />generate a login code?</h1>
<p class="lede">
A six-digit code changes every 30 seconds. Use REA to find the
calculation in an Android APK, then rebuild it with a clock you can
control.
</p>
<p class="page-meta">
Aegis 3.4.3 · Android · Official release APK · 6.9 MB
</p>
<a class="text-link" href="https://github.com/beemdevelopment/Aegis"
>View Aegis on GitHub</a
>
</div>
<figure class="workflow-figure case-figure">
<p class="figure-title">From an APK to a code you can reproduce</p>
<ol class="flow-steps">
<li>
<span class="flow-label">01 · Locate the feature</span
><strong class="flow-node"
>3,077 classes → generating methods</strong
><span class="flow-note"
>REA searches the package and traces the code used by the display
and copy actions.</span
>
</li>
<li>
<span class="flow-label">02 · Read the calculation</span
><strong class="flow-node">Time + account key → six digits</strong
><span class="flow-note"
>REA returns the methods and defaults. The agent explains how they
fit together.</span
>
</li>
<li>
<span class="flow-label">03 · Rebuild and check</span
><strong class="flow-node">Change the clock. Watch the code.</strong
><span class="flow-note"
>A new browser demo reproduces the rule and checks it against
public reference cases.</span
>
</li>
</ol>
</figure>
<div class="article-layout">
<nav class="contents" aria-label="On this page">
<p>In this case study</p>
<ul>
<li><a href="#ask">Ask your agent</a></li>
<li><a href="#demo">Try the code generator</a></li>
<li><a href="#find">Find the code with REA</a></li>
<li><a href="#calculation">Read the calculation</a></li>
<li><a href="#verify">Check the reconstruction</a></li>
<li><a href="#try">Inspect the APK yourself</a></li>
</ul>
</nav>
<article class="article" aria-label="Aegis APK case study">
<section class="article-section" id="ask">
<h2>Ask your agent</h2>
<p>
The app shows a changing login code. We want to find
<strong>what makes it change</strong> and reproduce that behavior.
</p>
<div class="agent-terminal">
<div class="terminal-header">
<span class="terminal-title"
><span class="terminal-dots" aria-hidden="true"
><i></i><i></i><i></i></span
>Your coding agent</span
><button
class="copy-button"
type="button"
data-copy="aegis-prompt"
aria-label="Copy Aegis example prompt"
>
Copy
</button>
</div>
<p class="terminal-prompt">
<span class="prompt-symbol" aria-hidden="true">›</span
><span id="aegis-prompt"
>Use REA to inspect
<span translate="no">aegis-v3.4.3.apk</span>. 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.</span
><span class="terminal-cursor" aria-hidden="true"></span>
</p>
</div>
<p class="caption">
An example prompt for the downloaded APK, with REA's Android
analysis configured.
<a href="#try">Get the APK and analysis setup ↓</a>
</p>
</section>
<section class="article-section" id="demo">
<h2>Try the code generator</h2>
<p>
The app groups time into
<mark class="prose-highlight">30-second blocks.</mark> It combines
the block number with the account key to generate a code. The same
key and block produce the same code.
</p>
<figure class="workflow-figure aegis-demo" data-aegis-demo>
<p class="figure-title">Move the clock across 60 seconds</p>
<ol class="flow-steps aegis-calculation">
<li>
<span class="flow-label">Time</span
><strong class="flow-node"
><output data-aegis-seconds>59</output> seconds</strong
><span class="flow-note">Our adjustable example clock</span>
</li>
<li>
<span class="flow-label">30-second block</span
><strong class="flow-node"
>Block <output data-aegis-block>1</output></strong
><span class="flow-note"
><code data-aegis-division>floor(59 / 30)</code><br /><span
data-aegis-window
>30–59 seconds</span
></span
>
</li>
<li>
<span class="flow-label">Generated code</span
><strong class="flow-node aegis-code"
><output
data-aegis-code
aria-live="polite"
aria-atomic="true"
>287082</output
></strong
><span class="flow-note"
>Account key + block → six digits</span
>
</li>
</ol>
<div class="aegis-clock-controls">
<label for="aegis-clock">Example time, in seconds</label>
<input
id="aegis-clock"
type="range"
min="0"
max="120"
step="1"
value="59"
disabled
/>
<div class="aegis-clock-scale" aria-hidden="true">
<span>0</span><span>30</span><span>60</span><span>90</span
><span>120</span>
</div>
<div class="actions">
<button
class="button secondary"
type="button"
data-aegis-time="59"
disabled
>
59 seconds</button
><button
class="button secondary"
type="button"
data-aegis-time="60"
disabled
>
60 seconds
</button>
</div>
<p class="caption">
At 59 seconds: <strong>287082.</strong> At 60 seconds:
<strong>359152.</strong> Moving within one block leaves the
code unchanged.
</p>
<p class="caption" data-aegis-status role="status"></p>
</div>
<figcaption>
The key is fixed, public
<a href="https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B"
>RFC 6238 test data</a
>. The demo implements the calculation recovered from the APK.
</figcaption>
<noscript
><p class="caption">
The diagram shows the result at 59 seconds. Enable JavaScript
to change the clock.
</p></noscript
>
</figure>
</section>
<section class="article-section" id="find">
<h2>Find the code with REA</h2>
<ol class="rea-queries">
<li>
<h4>Narrow the APK to three classes</h4>
<div class="rea-query-pair">
<div class="code-block">
<div class="code-header"><span>Agent → REA</span></div>
<pre><code>inspect_android_package
{"path": "aegis-v3.4.3.apk"}
search_android_classes
{"path": "aegis-v3.4.3.apk",
"query": "Totp"}</code></pre>
</div>
<div class="code-block">
<div class="code-header">
<span>REA → agent · selected results</span>
</div>
<pre><code>Package: com.beemdevelopment.aegis
Version: 3.4.3
Classes: 3,077
Three matches:
otp.TotpInfo
ui.views.TotpProgressBar
importers.TotpAuthenticatorImporter</code></pre>
</div>
</div>
<p>
<code>TotpInfo</code> is the calculation candidate; the other
two concern the progress bar and imported accounts. TOTP means
a time-based one-time password.
</p>
</li>
<li>
<h4>Connect the generator to the app's display</h4>
<div class="rea-query-pair">
<div class="code-block">
<div class="code-header"><span>Agent → REA</span></div>
<pre><code>inspect_android_class
{"path": "aegis-v3.4.3.apk",
"class_name":
"com.beemdevelopment.aegis.otp.TotpInfo"}
trace_android_references
{"path": "aegis-v3.4.3.apk",
"class_name":
"com.beemdevelopment.aegis.otp.OtpInfo",
"method_name": "getOtp"}</code></pre>
</div>
<div class="code-block">
<div class="code-header">
<span>REA → agent · methods and callers</span>
</div>
<pre><code>TotpInfo methods:
getOtp() · overload 0
getOtp(long) · overload 1
OtpInfo.getOtp callers:
ui.views.EntryHolder.getOtp
ui.MainActivity.copyEntryCode</code></pre>
</div>
</div>
<p>
REA identifies the timestamp overload and finds the base
method's callers. Inspecting
<code>EntryHolder.getOtp</code> then shows the display calling
<code>TotpInfo.getOtp(timestamp)</code>.
</p>
</li>
</ol>
<p class="caption">
Requests show a shortened input path. Result class names omit the
common <code>com.beemdevelopment.aegis</code> prefix.
</p>
</section>
<section class="article-section" id="calculation">
<h2>Read the calculation</h2>
<p>
REA returns
<strong
>the clock conversion, default settings and generating
methods.</strong
>
The constructors set a 30-second interval and six digits; the
timestamp method turns seconds into a block number.
</p>
<div class="step-comparison" data-step-comparison>
<div
class="step-selector aegis-step-selector"
role="group"
aria-label="Follow the login-code calculation"
>
<button
type="button"
data-select-step="1"
aria-pressed="true"
aria-controls="aegis-java aegis-summary"
>
<span>01</span> Time block
</button>
<button
type="button"
data-select-step="2"
aria-pressed="false"
aria-controls="aegis-java aegis-summary"
>
<span>02</span> Key + block
</button>
<button
type="button"
data-select-step="3"
aria-pressed="false"
aria-controls="aegis-java aegis-summary"
>
<span>03</span> Six digits
</button>
</div>
<div class="code-comparison">
<div class="code-block">
<div class="code-header">
<span>REA · selected decompiled Java</span>
</div>
<pre><code id="aegis-java"><span class="code-step is-active" data-step="1">// TotpInfo defaults and clock
setPeriod(30);
getOtp(System.currentTimeMillis() / 1000);
// OtpInfo default algorithm and digits
this(bArr, "SHA1", 6);
// Block passed to the generator
(long) Math.floor(j / ((double) this._period))</span>
<span class="code-step" data-step="2">// generateOTP → getHash
byte[] hash = getHash(bArr, str, j);
// getHash: account key + encoded block
Mac mac = Mac.getInstance(str);
mac.init(secretKeySpec);
return mac.doFinal(bArrArray);</span>
<span class="code-step" data-step="3">// OTP.toString, case 0
this._code % ((int) Math.pow(10.0d, i))
// Keep leading zeroes
while (sb.length() &lt; i) {
sb.insert(0, "0");
}</span></code></pre>
</div>
<div class="code-block">
<div class="code-header">
<span>Readable summary · agent's interpretation</span>
</div>
<pre><code id="aegis-summary"><span class="code-step is-active" data-step="1">// Group time into 30-second blocks
seconds = current_time_ms / 1000
block = floor(seconds / 30)</span>
<span class="code-step" data-step="2">// Generate a number from the key and block
hash = HMAC_SHA1(account_key,
big_endian_8_bytes(block))
number = select_31_bits(hash)</span>
<span class="code-step" data-step="3">// Format the default six-digit code
code = number % 1_000_000
code = pad_with_zeroes(code, 6)</span></code></pre>
</div>
</div>
<div class="step-detail" data-step-note="1">
<p>
<strong>Time chooses the block.</strong> Seconds 30 through 59
all give block 1. At 60 seconds, the block becomes 2.
</p>
</div>
<div class="step-detail" data-step-note="2">
<p>
<strong>The key matters too.</strong> The generator combines
the account key with the block. An account with a different
key can show a different code at the same time.
</p>
</div>
<div class="step-detail" data-step-note="3">
<p>
<strong>Keep six digits.</strong> The remainder after division
by 1,000,000 is padded with zeroes when needed, so a code can
begin with 0.
</p>
</div>
</div>
<p class="caption">
Excerpts from several inspected methods, with line wrapping for
display. The right panel is an explanatory summary.
<a
href="https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/LICENSE"
>Aegis code is GPL-3.0.</a
>
</p>
<details class="evidence-details">
<summary>Inside the generator</summary>
<p>
The released APK puts <code>generateOTP</code> in
<code>kotlin.ExceptionsKt</code>. REA follows the call from
<code>TotpInfo</code> and returns this body; the original source
calls the helper <code>HOTP</code>.
</p>
<div class="code-block">
<div class="code-header">
<span>REA · generateOTP, complete body</span>
</div>
<pre><code>public static OTP generateOTP(byte[] bArr, String str,
int i, long j)
throws NoSuchAlgorithmException, InvalidKeyException {
byte[] hash = getHash(bArr, str, j);
int i2 = hash[hash.length - 1] &amp; 15;
return new OTP(
(hash[i2 + 3] &amp; 255)
| ((hash[i2] &amp; 127) &lt;&lt; 24)
| ((hash[i2 + 1] &amp; 255) &lt;&lt; 16)
| ((hash[i2 + 2] &amp; 255) &lt;&lt; 8), i, 0);
}</code></pre>
</div>
<p>
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.
</p>
<p>
<a
href="https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/HOTP.java"
>Compare with the matching release source</a
>.
</p>
</details>
</section>
<section class="article-section" id="verify">
<h2>Check the reconstruction</h2>
<p>
We assembled the selected REA-returned Java methods in a small
test program. Their output matched an independent reconstruction
on <strong>133 test cases</strong>, including time-block
boundaries and codes beginning with zero.
</p>
<div class="evidence-table-wrap">
<table class="evidence-table">
<thead>
<tr>
<th>Example time</th>
<th>Block</th>
<th>Six-digit code</th>
</tr>
</thead>
<tbody>
<tr>
<td>30 seconds</td>
<td>1</td>
<td><code>287082</code></td>
</tr>
<tr>
<td>59 seconds</td>
<td>1</td>
<td><code>287082</code></td>
</tr>
<tr>
<td>60 seconds</td>
<td>2</td>
<td><code>359152</code></td>
</tr>
<tr>
<td>1,111,111,109 seconds</td>
<td>37,037,036</td>
<td><code>081804</code></td>
</tr>
</tbody>
</table>
</div>
<p>
The generator also matches the six published SHA-1 reference cases
in
<a href="https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B"
>RFC 6238</a
>. Check the browser implementation against them:
</p>
<div class="actions">
<button
class="button secondary"
type="button"
data-aegis-check
disabled
>
Run reference checks</button
><a class="text-link" href="../../assets/aegis-otp.js"
>Read the demo's calculation</a
>
</div>
<p
class="caption"
data-aegis-check-result
role="status"
aria-live="polite"
>
The reference cases use eight digits. The check also verifies
their six-digit results.
</p>
<p class="caption">
Verification runs extracted Java methods and the new demo. The
Android APK was inspected statically.
</p>
</section>
<section class="article-section" id="try">
<h2>Inspect the APK yourself</h2>
<p>
<a href="../../get-started/">Set up REA</a> on macOS or Linux,
then download these two files into the same folder. On Windows,
use a Linux environment such as WSL.
</p>
<p>
Android analysis needs a full JDK 17 or later. Select it with
<code>JAVA_HOME</code> or <code>PATH</code>. This case used JDK
21.
</p>
<div class="actions">
<a
class="button"
href="https://github.com/beemdevelopment/Aegis/releases/download/v3.4.3/aegis-v3.4.3.apk"
>Download Aegis APK</a
><a
class="text-link"
href="https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp-0.7.1-all.jar"
>Download Android analysis provider</a
>
</div>
<p>Point REA at the provider file and inspect the APK:</p>
<div class="code-block">
<div class="code-header">
<span>macOS / Linux</span
><button
class="copy-button"
type="button"
data-copy="aegis-inspect-command"
aria-label="Copy APK inspection command"
>
Copy
</button>
</div>
<pre><code id="aegis-inspect-command">REA_JADX_MCP_JAR="$PWD/jadx-headless-mcp-0.7.1-all.jar" \
npx rea-agents@latest inspect-android-package \
./aegis-v3.4.3.apk --format json --full-output</code></pre>
</div>
<p>
Your agent can continue through REA's CLI using the prompt above.
For MCP, add <code>REA_JADX_MCP_JAR</code> to the REA server's
environment and reconnect it.
</p>
<p>
A next question:
<strong
>what happens when an account uses eight digits or a different
time interval?</strong
>
</p>
</section>
<section class="article-section" id="sources">
<h2>Sources</h2>
<ul class="compact-list">
<li>
<a
href="https://github.com/beemdevelopment/Aegis/releases/tag/v3.4.3"
>Official Aegis 3.4.3 release</a
>
·
<a
href="https://github.com/beemdevelopment/Aegis/tree/d6f4e5925a97e4e91593f1542085eae03432a759"
>Matching source commit</a
>
·
<a
href="https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/LICENSE"
>GPL-3.0 license</a
>
</li>
<li>
<a href="https://www.rfc-editor.org/rfc/rfc6238.html#appendix-B"
>RFC 6238 reference cases</a
>
· <a href="test-vectors.json">Demo test data</a>
</li>
</ul>
<p class="caption">
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.
</p>
</section>
</article>
</div>
</main>
<!-- website:footer:start -->
<!-- prettier-ignore -->
<footer class="site-footer">
<div class="container footer-inner">
<p>REA · Reverse Engineer Anything</p>
<div class="footer-links">
<a href="https://github.com/morluto/rea">Source</a
><a href="https://github.com/morluto/rea/blob/main/LICENSE">MIT license</a
><a href="https://discord.gg/GkcryMnJDM">Join the community</a
><a href="https://x.com/reatools">Follow us on X</a>
</div>
</div>
</footer>
<p class="sr-only" id="copy-status" role="status" aria-live="polite"></p>
<a class="back-to-top" href="#top" aria-label="Back to top">
<span aria-hidden="true">↑</span> Top
</a>
<!-- website:footer:end -->
</body>
</html>