CASE_04 · 2014–2018 · VISA_VTS
Visa Inc. · NFC/HCE · NDK · OpenSSL · ARXAN
I led the Android SDK for the Visa Token Service (VTS), enabling card issuers to ship NFC/HCE mobile payments inside their banking apps. Built the JNI-Bridge — hardened Java↔C with encrypted channels — managed OpenSSL inside the NDK for RSA key generation in C, and shipped ARXAN obfuscation with a custom stack-trace system that kept the SDK supportable with zero symbol exposure.
// case_study
The Visa Token Service SDK gave card issuers a path to ship NFC/HCE mobile payments inside their own banking apps. As the lead engineer I owned the Android SDK end-to-end: the build configuration, the security hardening, and the JNI-Bridge that was the spine of the security model.
This is the work that calibrated my view of what mobile security
means at the production end — not the abstract threat model, the
actual on-device adversary trying to pull keys out of a
.so file.
The core of the SDK's security posture was the
JNI-Bridge — a hardened Java↔C
integration layer with encrypted channels between the Java caller code
and the native .so binaries. Sensitive
data never crosses the boundary in plaintext; the C side holds the key
material; the Java side never sees what it doesn't need to see. The
"tight bond" between Java and C was the design constraint and the
implementation discipline.
I managed OpenSSL builds (1.0.2c / g / h, depending on the issuer's release timeline) inside the Android NDK for RSA key generation in C — that's where the key material had to be born and stay. Everything was built from source, so we knew exactly what shipped.
The native code shipped with ARXAN-based
obfuscation. Once obfuscation is on and symbols are stripped,
the standard problem hits: when a card issuer's app crashes in
production, you can't get a useful stack trace from the binary
anymore. "We made it secure but unsupportable" isn't an acceptable
answer for an SDK that issuers integrate. So I built a custom
stack-trace system — enough internal markers for our support engineers
to triangulate a crash, with zero symbol exposure to anyone reading
the .so.
A security-first product has to expose as little information as possible during any error, exception, or crash — but never so little that supportability dies. Holding both ends required a deliberate error-handling discipline: every error path inventoried, classified, and shaped to give support engineering enough to act without giving an adversary enough to map.
Full Gradle flavor implementation for build configurations, testing, versioning, and artifact packaging — multiple issuers, multiple targets, multiple validation profiles. Customized shell scripts to build the NDK project, so that turning on logs / debugs / environment toggles was a one-line change instead of a 30-minute reconfiguration.
The architectural challenges I solved here became the foundational principles for the work I'm doing now at TikTok. The threat model flipped — Visa was a semi-trusted environment built around HCE / TEE, where the device cooperates with us; TikTok assumes the client is actively hostile — but the same hardened JNI patterns and white-box encryption instincts now sit underneath the Zero-Trust infrastructure I lead today.
The custom stack-trace system and the ARXAN integration here were my first deep dive into the on-device-adversary mindset. That instinct evolved into the anti-automation and device-farm fingerprinting at TikTok — same posture, different scale, custom assembly-level hardening from the ground up instead of riding a commercial product.
What this taught me is that security has to be invisible to the end user but invincible to the attacker. Whether it's enabling NFC payments for a few million cardholders or anti-automation at 1.9B DAU, the design constraint is the same: zero felt overhead, zero exposed surface.
android stack
Java · Android SDK 4.4+ · SQLite · Retrofit · OkHttp · Gson · Gradle flavors · IntelliJ
native & security
NDK · C · OpenSSL 1.0.2 (c / g / h) · ARXAN · WhiteBox encryption · JNI-Bridge