android-sdd 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +143 -0
- package/package.json +27 -0
- package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
- package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
- package/skills/Android Platform/Configuration/SKILL.md +201 -0
- package/skills/Android Platform/Filesystem/SKILL.md +216 -0
- package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
- package/skills/Android Platform/Manifest/SKILL.md +226 -0
- package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
- package/skills/Android Platform/Resources/SKILL.md +234 -0
- package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
- package/skills/Android Platform/State Restoration/SKILL.md +210 -0
- package/skills/Architecture/Bounded Context/SKILL.md +207 -0
- package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
- package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
- package/skills/Architecture/Entity Design/SKILL.md +243 -0
- package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
- package/skills/Architecture/MVI/SKILL.md +224 -0
- package/skills/Architecture/MVVM/SKILL.md +198 -0
- package/skills/Architecture/Modularization/SKILL.md +194 -0
- package/skills/Architecture/Offline First/SKILL.md +249 -0
- package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
- package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
- package/skills/Architecture/State Management/SKILL.md +229 -0
- package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
- package/skills/Architecture/Use Case Design/SKILL.md +244 -0
- package/skills/Architecture/Value Object/SKILL.md +226 -0
- package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
- package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
- package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
- package/skills/Build System/Build Cache/SKILL.md +233 -0
- package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
- package/skills/Build System/Build Variant/SKILL.md +215 -0
- package/skills/Build System/Convention Plugin/SKILL.md +288 -0
- package/skills/Build System/Dependency Management/SKILL.md +261 -0
- package/skills/Build System/Gradle/SKILL.md +284 -0
- package/skills/Build System/Incremental Build/SKILL.md +199 -0
- package/skills/Build System/KAPT/SKILL.md +198 -0
- package/skills/Build System/KSP/SKILL.md +263 -0
- package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
- package/skills/Build System/Specialized/C++/SKILL.md +308 -0
- package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
- package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
- package/skills/Build System/Version Catalog/SKILL.md +304 -0
- package/skills/Concurrency/Background Processing/SKILL.md +185 -0
- package/skills/Concurrency/Channel/SKILL.md +207 -0
- package/skills/Concurrency/Coroutine/SKILL.md +200 -0
- package/skills/Concurrency/Flow/SKILL.md +179 -0
- package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
- package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
- package/skills/Concurrency/StateFlow/SKILL.md +175 -0
- package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
- package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
- package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
- package/skills/Core Language/DSL/SKILL.md +186 -0
- package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
- package/skills/Core Language/Immutability/SKILL.md +156 -0
- package/skills/Core Language/KMP/SKILL.md +182 -0
- package/skills/Core Language/Kotlin/SKILL.md +187 -0
- package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
- package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
- package/skills/Core Language/Serialization/SKILL.md +191 -0
- package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
- package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
- package/skills/Data Layer/DAO/SKILL.md +225 -0
- package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
- package/skills/Data Layer/DataStore/SKILL.md +264 -0
- package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
- package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
- package/skills/Data Layer/File Storage/SKILL.md +247 -0
- package/skills/Data Layer/Indexing/SKILL.md +184 -0
- package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
- package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
- package/skills/Data Layer/Migration/SKILL.md +243 -0
- package/skills/Data Layer/Paging/SKILL.md +264 -0
- package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
- package/skills/Data Layer/Room/SKILL.md +244 -0
- package/skills/Data Layer/SQLite/SKILL.md +255 -0
- package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
- package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
- package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
- package/skills/Dependency Injection/Koin/SKILL.md +282 -0
- package/skills/Developer Experience/Detekt/SKILL.md +272 -0
- package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
- package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
- package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
- package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
- package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
- package/skills/Media/Audio/SKILL.md +257 -0
- package/skills/Media/Camera/SKILL.md +229 -0
- package/skills/Media/CameraX/SKILL.md +295 -0
- package/skills/Media/ExoPlayer/SKILL.md +258 -0
- package/skills/Media/Video/SKILL.md +228 -0
- package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
- package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
- package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
- package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
- package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
- package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
- package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
- package/skills/Navigation/Navigation/SKILL.md +215 -0
- package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
- package/skills/Networking/API Contract/SKILL.md +220 -0
- package/skills/Networking/Authentication/SKILL.md +210 -0
- package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
- package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
- package/skills/Networking/Ktor/SKILL.md +219 -0
- package/skills/Networking/Multipart Upload/SKILL.md +213 -0
- package/skills/Networking/OkHttp/SKILL.md +193 -0
- package/skills/Networking/REST/SKILL.md +178 -0
- package/skills/Networking/Rate Limiting/SKILL.md +170 -0
- package/skills/Networking/Retrofit/SKILL.md +241 -0
- package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
- package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
- package/skills/Networking/WebSocket/SKILL.md +224 -0
- package/skills/Observability/Crash Reporting/SKILL.md +219 -0
- package/skills/Observability/Logging/SKILL.md +168 -0
- package/skills/Observability/Metrics/SKILL.md +227 -0
- package/skills/Observability/Structured Logging/SKILL.md +234 -0
- package/skills/Performance/ANR Prevention/SKILL.md +192 -0
- package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
- package/skills/Performance/App Startup/SKILL.md +183 -0
- package/skills/Performance/Baseline Profile/SKILL.md +205 -0
- package/skills/Performance/Battery Optimization/SKILL.md +192 -0
- package/skills/Performance/Benchmark/SKILL.md +182 -0
- package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
- package/skills/Performance/Compose Optimization/SKILL.md +187 -0
- package/skills/Performance/Heap Management/SKILL.md +184 -0
- package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
- package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
- package/skills/Performance/Rendering Performance/SKILL.md +205 -0
- package/skills/Performance/Startup Optimization/SKILL.md +219 -0
- package/skills/Security/Biometric/SKILL.md +224 -0
- package/skills/Security/Certificate Transparency/SKILL.md +158 -0
- package/skills/Security/Cryptography/SKILL.md +244 -0
- package/skills/Security/Encrypted Storage/SKILL.md +273 -0
- package/skills/Security/Frida Detection/SKILL.md +230 -0
- package/skills/Security/Hook Detection/SKILL.md +197 -0
- package/skills/Security/Keystore/SKILL.md +272 -0
- package/skills/Security/Network Security Config/SKILL.md +186 -0
- package/skills/Security/Obfuscation/SKILL.md +226 -0
- package/skills/Security/Proguard/SKILL.md +202 -0
- package/skills/Security/R8/SKILL.md +234 -0
- package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
- package/skills/Security/Root Detection/SKILL.md +220 -0
- package/skills/Security/Secure Networking/SKILL.md +220 -0
- package/skills/System Integration/AlarmManager/SKILL.md +182 -0
- package/skills/System Integration/App Widget/SKILL.md +182 -0
- package/skills/System Integration/Deep Link/SKILL.md +187 -0
- package/skills/System Integration/Foreground Service/SKILL.md +212 -0
- package/skills/System Integration/Notification/SKILL.md +237 -0
- package/skills/System Integration/WorkManager/SKILL.md +256 -0
- package/skills/System Integration/clipboard/SKILL.md +155 -0
- package/skills/System Integration/share-intent/SKILL.md +182 -0
- package/skills/Testing/Compose Testing/SKILL.md +296 -0
- package/skills/Testing/Espresso/SKILL.md +292 -0
- package/skills/Testing/Fake Data/SKILL.md +245 -0
- package/skills/Testing/Integration Testing/SKILL.md +288 -0
- package/skills/Testing/Mocking/SKILL.md +229 -0
- package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
- package/skills/Testing/UI Testing/SKILL.md +293 -0
- package/skills/Testing/Unit Testing/SKILL.md +309 -0
- package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
- package/skills/UI System/Compose/SKILL.md +296 -0
- package/skills/UI System/Compose Animation/SKILL.md +281 -0
- package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
- package/skills/UI System/Compose Navigation/SKILL.md +255 -0
- package/skills/UI System/Compose Performance/SKILL.md +274 -0
- package/skills/UI System/Design System/SKILL.md +217 -0
- package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
- package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
- package/skills/UI System/Loading Strategy/SKILL.md +254 -0
- package/skills/UI System/Material 3/SKILL.md +279 -0
- package/skills/UI System/RTL/SKILL.md +179 -0
- package/src/index.ts +182 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: keystore
|
|
3
|
+
description: >
|
|
4
|
+
Android Keystore System for cryptographic key management.
|
|
5
|
+
Load this skill when generating, storing, or using cryptographic keys,
|
|
6
|
+
implementing encrypt/decrypt operations backed by Keystore,
|
|
7
|
+
requiring user authentication before key use, or managing key lifecycle.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Keystore
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
The Android Keystore System lets you store cryptographic keys in a container that makes them harder to extract — keys can be bound to secure hardware (TEE/StrongBox) and never leave the device. Keystore is the foundation for all local encryption, biometric authentication, and signing operations.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
- Keys are **generated inside Keystore** — never imported from outside unless necessary
|
|
20
|
+
- Keys **never leave the secure enclave** — only the operations (encrypt/decrypt/sign) are performed
|
|
21
|
+
- Specify **purpose at key generation** — a key for encryption cannot be used for signing
|
|
22
|
+
- Use **StrongBox** when available for highest security (hardware security module)
|
|
23
|
+
- Keys can require **user authentication** (biometric/PIN) before use
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Generating a Symmetric Key (AES)
|
|
28
|
+
|
|
29
|
+
```kotlin
|
|
30
|
+
// ✅ Generate AES key for encryption/decryption
|
|
31
|
+
fun generateAesKey(alias: String) {
|
|
32
|
+
val keyGenerator = KeyGenerator.getInstance(
|
|
33
|
+
KeyProperties.KEY_ALGORITHM_AES,
|
|
34
|
+
"AndroidKeyStore"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
keyGenerator.init(
|
|
38
|
+
KeyGenParameterSpec.Builder(
|
|
39
|
+
alias,
|
|
40
|
+
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
|
41
|
+
)
|
|
42
|
+
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
|
43
|
+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
|
44
|
+
.setKeySize(256)
|
|
45
|
+
.setUserAuthenticationRequired(false) // set true to require biometric/PIN
|
|
46
|
+
.setInvalidatedByBiometricEnrollment(true)
|
|
47
|
+
.build()
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
keyGenerator.generateKey()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ✅ Generate key that requires biometric authentication
|
|
54
|
+
fun generateBiometricBoundKey(alias: String) {
|
|
55
|
+
val keyGenerator = KeyGenerator.getInstance(
|
|
56
|
+
KeyProperties.KEY_ALGORITHM_AES,
|
|
57
|
+
"AndroidKeyStore"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
keyGenerator.init(
|
|
61
|
+
KeyGenParameterSpec.Builder(
|
|
62
|
+
alias,
|
|
63
|
+
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
|
64
|
+
)
|
|
65
|
+
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
|
66
|
+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
|
67
|
+
.setKeySize(256)
|
|
68
|
+
.setUserAuthenticationRequired(true)
|
|
69
|
+
.setUserAuthenticationParameters(
|
|
70
|
+
0, // 0 = every use requires auth
|
|
71
|
+
KeyProperties.AUTH_BIOMETRIC_STRONG or KeyProperties.AUTH_DEVICE_CREDENTIAL
|
|
72
|
+
)
|
|
73
|
+
.setInvalidatedByBiometricEnrollment(true)
|
|
74
|
+
.build()
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
keyGenerator.generateKey()
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Generating an Asymmetric Key (RSA / EC)
|
|
84
|
+
|
|
85
|
+
```kotlin
|
|
86
|
+
// ✅ Generate EC key pair for signing
|
|
87
|
+
fun generateEcKeyPair(alias: String) {
|
|
88
|
+
val keyPairGenerator = KeyPairGenerator.getInstance(
|
|
89
|
+
KeyProperties.KEY_ALGORITHM_EC,
|
|
90
|
+
"AndroidKeyStore"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
keyPairGenerator.initialize(
|
|
94
|
+
KeyGenParameterSpec.Builder(
|
|
95
|
+
alias,
|
|
96
|
+
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
|
|
97
|
+
)
|
|
98
|
+
.setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
|
|
99
|
+
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
|
|
100
|
+
.build()
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
keyPairGenerator.generateKeyPair()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ✅ Generate RSA key pair for encryption
|
|
107
|
+
fun generateRsaKeyPair(alias: String) {
|
|
108
|
+
val keyPairGenerator = KeyPairGenerator.getInstance(
|
|
109
|
+
KeyProperties.KEY_ALGORITHM_RSA,
|
|
110
|
+
"AndroidKeyStore"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
keyPairGenerator.initialize(
|
|
114
|
+
KeyGenParameterSpec.Builder(
|
|
115
|
+
alias,
|
|
116
|
+
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
|
117
|
+
)
|
|
118
|
+
.setKeySize(2048)
|
|
119
|
+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
|
|
120
|
+
.setDigests(KeyProperties.DIGEST_SHA256)
|
|
121
|
+
.build()
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
keyPairGenerator.generateKeyPair()
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Encrypt / Decrypt with AES-GCM
|
|
131
|
+
|
|
132
|
+
```kotlin
|
|
133
|
+
class KeystoreCrypto @Inject constructor() {
|
|
134
|
+
private val keyStore = KeyStore.getInstance("AndroidKeyStore").also { it.load(null) }
|
|
135
|
+
|
|
136
|
+
// ✅ Encrypt — returns IV + ciphertext (IV needed for decryption)
|
|
137
|
+
fun encrypt(alias: String, plaintext: ByteArray): EncryptedData {
|
|
138
|
+
ensureKeyExists(alias)
|
|
139
|
+
val key = keyStore.getKey(alias, null) as SecretKey
|
|
140
|
+
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
|
141
|
+
cipher.init(Cipher.ENCRYPT_MODE, key)
|
|
142
|
+
|
|
143
|
+
val ciphertext = cipher.doFinal(plaintext)
|
|
144
|
+
return EncryptedData(iv = cipher.iv, ciphertext = ciphertext)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ✅ Decrypt — requires same IV used during encryption
|
|
148
|
+
fun decrypt(alias: String, data: EncryptedData): ByteArray {
|
|
149
|
+
val key = keyStore.getKey(alias, null) as SecretKey
|
|
150
|
+
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
|
151
|
+
val spec = GCMParameterSpec(128, data.iv)
|
|
152
|
+
cipher.init(Cipher.DECRYPT_MODE, key, spec)
|
|
153
|
+
return cipher.doFinal(data.ciphertext)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
fun deleteKey(alias: String) {
|
|
157
|
+
if (keyStore.containsAlias(alias)) {
|
|
158
|
+
keyStore.deleteEntry(alias)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fun hasKey(alias: String): Boolean = keyStore.containsAlias(alias)
|
|
163
|
+
|
|
164
|
+
private fun ensureKeyExists(alias: String) {
|
|
165
|
+
if (!keyStore.containsAlias(alias)) generateAesKey(alias)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
data class EncryptedData(
|
|
170
|
+
val iv: ByteArray,
|
|
171
|
+
val ciphertext: ByteArray
|
|
172
|
+
) {
|
|
173
|
+
// ✅ Serialize for storage — prepend IV to ciphertext
|
|
174
|
+
fun toByteArray(): ByteArray = iv + ciphertext
|
|
175
|
+
|
|
176
|
+
companion object {
|
|
177
|
+
private const val IV_SIZE = 12 // GCM IV is always 12 bytes
|
|
178
|
+
|
|
179
|
+
fun fromByteArray(data: ByteArray): EncryptedData = EncryptedData(
|
|
180
|
+
iv = data.copyOfRange(0, IV_SIZE),
|
|
181
|
+
ciphertext = data.copyOfRange(IV_SIZE, data.size)
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Sign / Verify with EC
|
|
190
|
+
|
|
191
|
+
```kotlin
|
|
192
|
+
class KeystoreSigner @Inject constructor() {
|
|
193
|
+
private val keyStore = KeyStore.getInstance("AndroidKeyStore").also { it.load(null) }
|
|
194
|
+
|
|
195
|
+
fun sign(alias: String, data: ByteArray): ByteArray {
|
|
196
|
+
val privateKey = keyStore.getKey(alias, null) as PrivateKey
|
|
197
|
+
return Signature.getInstance("SHA256withECDSA").run {
|
|
198
|
+
initSign(privateKey)
|
|
199
|
+
update(data)
|
|
200
|
+
sign()
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
fun verify(alias: String, data: ByteArray, signature: ByteArray): Boolean {
|
|
205
|
+
val publicKey = keyStore.getCertificate(alias).publicKey
|
|
206
|
+
return Signature.getInstance("SHA256withECDSA").run {
|
|
207
|
+
initVerify(publicKey)
|
|
208
|
+
update(data)
|
|
209
|
+
verify(signature)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## StrongBox (Hardware Security Module)
|
|
218
|
+
|
|
219
|
+
```kotlin
|
|
220
|
+
// ✅ Use StrongBox when available (Pixel 3+, Android 9+)
|
|
221
|
+
fun generateStrongBoxKey(context: Context, alias: String) {
|
|
222
|
+
val hasStrongBox = context.packageManager
|
|
223
|
+
.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
|
|
224
|
+
|
|
225
|
+
val spec = KeyGenParameterSpec.Builder(
|
|
226
|
+
alias,
|
|
227
|
+
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
|
228
|
+
)
|
|
229
|
+
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
|
230
|
+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
|
231
|
+
.setKeySize(256)
|
|
232
|
+
.apply {
|
|
233
|
+
if (hasStrongBox) setIsStrongBoxBacked(true)
|
|
234
|
+
}
|
|
235
|
+
.build()
|
|
236
|
+
|
|
237
|
+
KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
|
|
238
|
+
.apply { init(spec) }
|
|
239
|
+
.generateKey()
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Key Aliases (Convention)
|
|
246
|
+
|
|
247
|
+
```kotlin
|
|
248
|
+
object KeystoreAliases {
|
|
249
|
+
const val DATABASE_KEY = "app_database_key"
|
|
250
|
+
const val AUTH_TOKEN_KEY = "app_auth_token_key"
|
|
251
|
+
const val BIOMETRIC_KEY = "app_biometric_key"
|
|
252
|
+
const val SIGNING_KEY = "app_signing_key"
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Anti-Patterns
|
|
259
|
+
|
|
260
|
+
- Generating keys outside AndroidKeyStore — keys in memory can be extracted
|
|
261
|
+
- Reusing the same IV for multiple encryptions with the same key — breaks GCM security
|
|
262
|
+
- Storing the IV separately in an insecure location — IV must be stored with ciphertext
|
|
263
|
+
- Using ECB mode (`AES/ECB/PKCS5Padding`) — no IV, patterns visible in ciphertext
|
|
264
|
+
- Ignoring `KeyPermanentlyInvalidatedException` — thrown when biometrics change; handle gracefully
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Related Skills
|
|
269
|
+
- `encrypted-storage` — using Keystore-backed keys for storage encryption
|
|
270
|
+
- `biometric` — biometric authentication tied to Keystore keys
|
|
271
|
+
- `cryptography` — higher-level crypto operations
|
|
272
|
+
- `secure-networking` — certificate pinning and TLS
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: network-security-config
|
|
3
|
+
description: >
|
|
4
|
+
Android Network Security Config for controlling TLS and cleartext traffic.
|
|
5
|
+
Load this skill when configuring network security policy via XML,
|
|
6
|
+
blocking cleartext HTTP, trusting custom CAs, defining per-domain rules,
|
|
7
|
+
or allowing debug-only network policies.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Network Security Config
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
Network Security Config is an Android XML-based mechanism for defining a per-app network security policy without code changes. It controls which CAs are trusted, whether cleartext (HTTP) traffic is allowed, certificate pinning, and debug-only overrides. It applies to all HTTP(S) connections made through standard Android networking APIs.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
- **Declare in manifest** — `android:networkSecurityConfig` on `<application>`
|
|
20
|
+
- **Default behavior** (no config): cleartext allowed on API < 28, blocked on API 28+
|
|
21
|
+
- **Block cleartext explicitly** — don't rely on the default
|
|
22
|
+
- **Debug overrides** are only active in debug builds — safe to include user CAs there
|
|
23
|
+
- **Per-domain rules** override the base config for specific hosts
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Full Configuration Reference
|
|
28
|
+
|
|
29
|
+
```xml
|
|
30
|
+
<!-- res/xml/network_security_config.xml -->
|
|
31
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
32
|
+
<network-security-config>
|
|
33
|
+
|
|
34
|
+
<!-- ✅ Base config — applies to all connections not covered by domain-config -->
|
|
35
|
+
<base-config cleartextTrafficPermitted="false">
|
|
36
|
+
<trust-anchors>
|
|
37
|
+
<certificates src="system" /> <!-- trust system CAs only -->
|
|
38
|
+
</trust-anchors>
|
|
39
|
+
</base-config>
|
|
40
|
+
|
|
41
|
+
<!-- ✅ Per-domain config — overrides base-config for specific hosts -->
|
|
42
|
+
<domain-config cleartextTrafficPermitted="false">
|
|
43
|
+
<domain includeSubdomains="true">api.example.com</domain>
|
|
44
|
+
<trust-anchors>
|
|
45
|
+
<certificates src="system" />
|
|
46
|
+
</trust-anchors>
|
|
47
|
+
<!-- Certificate pinning (optional — prefer OkHttp pinning for flexibility) -->
|
|
48
|
+
<pin-set expiration="2026-01-01">
|
|
49
|
+
<pin digest="SHA-256">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</pin>
|
|
50
|
+
<pin digest="SHA-256">BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=</pin>
|
|
51
|
+
</pin-set>
|
|
52
|
+
</domain-config>
|
|
53
|
+
|
|
54
|
+
<!-- ✅ Allow cleartext for specific internal/local hosts only -->
|
|
55
|
+
<domain-config cleartextTrafficPermitted="true">
|
|
56
|
+
<domain includeSubdomains="false">10.0.2.2</domain> <!-- emulator localhost -->
|
|
57
|
+
<domain includeSubdomains="false">192.168.1.1</domain>
|
|
58
|
+
</domain-config>
|
|
59
|
+
|
|
60
|
+
<!-- ✅ Debug overrides — ONLY active in debug builds, ignored in release -->
|
|
61
|
+
<debug-overrides>
|
|
62
|
+
<trust-anchors>
|
|
63
|
+
<certificates src="system" />
|
|
64
|
+
<certificates src="user" /> <!-- allows Charles/Burp SSL proxy on debug -->
|
|
65
|
+
</trust-anchors>
|
|
66
|
+
</debug-overrides>
|
|
67
|
+
|
|
68
|
+
</network-security-config>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## AndroidManifest.xml
|
|
74
|
+
|
|
75
|
+
```xml
|
|
76
|
+
<application
|
|
77
|
+
android:networkSecurityConfig="@xml/network_security_config"
|
|
78
|
+
android:usesCleartextTraffic="false" <!-- ✅ belt-and-suspenders for API < 24 -->
|
|
79
|
+
...>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Common Configurations
|
|
85
|
+
|
|
86
|
+
```xml
|
|
87
|
+
<!-- ✅ Minimal production config — block all cleartext, system CAs only -->
|
|
88
|
+
<network-security-config>
|
|
89
|
+
<base-config cleartextTrafficPermitted="false">
|
|
90
|
+
<trust-anchors>
|
|
91
|
+
<certificates src="system" />
|
|
92
|
+
</trust-anchors>
|
|
93
|
+
</base-config>
|
|
94
|
+
<debug-overrides>
|
|
95
|
+
<trust-anchors>
|
|
96
|
+
<certificates src="system" />
|
|
97
|
+
<certificates src="user" />
|
|
98
|
+
</trust-anchors>
|
|
99
|
+
</debug-overrides>
|
|
100
|
+
</network-security-config>
|
|
101
|
+
|
|
102
|
+
<!-- ✅ Trust a custom/private CA (e.g. internal enterprise API) -->
|
|
103
|
+
<network-security-config>
|
|
104
|
+
<base-config cleartextTrafficPermitted="false">
|
|
105
|
+
<trust-anchors>
|
|
106
|
+
<certificates src="system" />
|
|
107
|
+
<certificates src="@raw/my_ca_cert" /> <!-- place CA cert in res/raw/ -->
|
|
108
|
+
</trust-anchors>
|
|
109
|
+
</base-config>
|
|
110
|
+
</network-security-config>
|
|
111
|
+
|
|
112
|
+
<!-- ✅ Override for one domain with stricter rules -->
|
|
113
|
+
<network-security-config>
|
|
114
|
+
<base-config cleartextTrafficPermitted="false">
|
|
115
|
+
<trust-anchors>
|
|
116
|
+
<certificates src="system" />
|
|
117
|
+
</trust-anchors>
|
|
118
|
+
</base-config>
|
|
119
|
+
<domain-config>
|
|
120
|
+
<domain includeSubdomains="true">payments.example.com</domain>
|
|
121
|
+
<pin-set expiration="2026-06-01">
|
|
122
|
+
<pin digest="SHA-256">primaryPinBase64==</pin>
|
|
123
|
+
<pin digest="SHA-256">backupPinBase64==</pin>
|
|
124
|
+
</pin-set>
|
|
125
|
+
</domain-config>
|
|
126
|
+
</network-security-config>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Certificate Sources
|
|
132
|
+
|
|
133
|
+
| `src` value | Meaning |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `system` | Android system CA store |
|
|
136
|
+
| `user` | User-installed CAs (avoid in production) |
|
|
137
|
+
| `@raw/cert_file` | Bundled CA certificate in `res/raw/` |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Pin Expiration
|
|
142
|
+
|
|
143
|
+
```xml
|
|
144
|
+
<!-- ✅ Always set pin expiration — prevents permanent lockout if pin rotation fails -->
|
|
145
|
+
<pin-set expiration="2026-06-01">
|
|
146
|
+
<pin digest="SHA-256">primaryPinBase64==</pin>
|
|
147
|
+
<pin digest="SHA-256">backupPinBase64==</pin>
|
|
148
|
+
</pin-set>
|
|
149
|
+
|
|
150
|
+
<!-- After expiration date, pinning is disabled — connections proceed without pinning -->
|
|
151
|
+
<!-- ✅ Better to use OkHttp certificate pinning for runtime flexibility -->
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Verifying Config is Applied
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# ✅ Test that cleartext is blocked
|
|
160
|
+
adb shell am start -a android.intent.action.VIEW \
|
|
161
|
+
-d http://example.com com.example.app
|
|
162
|
+
|
|
163
|
+
# Expected: NetworkSecurityPolicy blocks the connection
|
|
164
|
+
# Logcat: CLEARTEXT communication to example.com not permitted by network security policy
|
|
165
|
+
|
|
166
|
+
# ✅ Verify config with Network Inspector in Android Studio
|
|
167
|
+
# View > Tool Windows > App Inspection > Network Inspector
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Anti-Patterns
|
|
173
|
+
|
|
174
|
+
- `cleartextTrafficPermitted="true"` in base-config for production — allows HTTP interception
|
|
175
|
+
- `<certificates src="user" />` in base-config (not debug-overrides) — allows proxy attacks
|
|
176
|
+
- No `debug-overrides` block — forces developers to modify production config for local testing
|
|
177
|
+
- Embedding private keys in `res/raw/` — only embed **CA certificates**, never private keys
|
|
178
|
+
- Relying solely on XML pinning — prefer OkHttp pinning which supports easier rotation
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Related Skills
|
|
183
|
+
- `secure-networking` — overall network security setup
|
|
184
|
+
- `certificate-pinning` — OkHttp-based certificate pinning
|
|
185
|
+
- `certificate-transparency` — CT enforcement
|
|
186
|
+
- `okhttp` — OkHttp configuration
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: obfuscation
|
|
3
|
+
description: >
|
|
4
|
+
Code obfuscation for Android apps using R8 and ProGuard.
|
|
5
|
+
Load this skill when configuring obfuscation rules, protecting sensitive
|
|
6
|
+
logic from reverse engineering, keeping required classes unobfuscated,
|
|
7
|
+
or troubleshooting crashes caused by obfuscation.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Obfuscation
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
Obfuscation renames classes, methods, and fields to meaningless names, making reverse-engineered code harder to understand. In Android, R8 (the successor to ProGuard) handles shrinking, obfuscation, and optimization in a single pass. Obfuscation is enabled by default in release builds.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
- **Obfuscation ≠ security** — it raises the bar, not a complete defense
|
|
20
|
+
- R8 is the default since Android Gradle Plugin 3.4 — prefer R8 over ProGuard
|
|
21
|
+
- **Keep rules are critical** — wrong keeps = broken app; missing keeps = crashes
|
|
22
|
+
- Always **test release builds** — obfuscation bugs only appear in release
|
|
23
|
+
- **Mapping file** must be saved — needed to decode crash stack traces
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Enable in build.gradle.kts
|
|
28
|
+
|
|
29
|
+
```kotlin
|
|
30
|
+
// ✅ Release build config
|
|
31
|
+
android {
|
|
32
|
+
buildTypes {
|
|
33
|
+
release {
|
|
34
|
+
isMinifyEnabled = true // enables R8 obfuscation + shrinking
|
|
35
|
+
isShrinkResources = true // removes unused resources
|
|
36
|
+
proguardFiles(
|
|
37
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
38
|
+
"proguard-rules.pro"
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ✅ Optional: test obfuscation in debug
|
|
43
|
+
debug {
|
|
44
|
+
isMinifyEnabled = false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## proguard-rules.pro
|
|
53
|
+
|
|
54
|
+
```proguard
|
|
55
|
+
# ============================================================
|
|
56
|
+
# Data classes used with serialization (Gson, kotlinx.serialization, Moshi)
|
|
57
|
+
# ============================================================
|
|
58
|
+
-keepclassmembers class com.example.app.data.remote.dto.** {
|
|
59
|
+
<fields>;
|
|
60
|
+
}
|
|
61
|
+
-keep class com.example.app.data.remote.dto.** { *; }
|
|
62
|
+
|
|
63
|
+
# ============================================================
|
|
64
|
+
# Room entities and DAOs
|
|
65
|
+
# ============================================================
|
|
66
|
+
-keep class * extends androidx.room.RoomDatabase
|
|
67
|
+
-keep @androidx.room.Entity class *
|
|
68
|
+
-keepclassmembers @androidx.room.Entity class * { <fields>; }
|
|
69
|
+
|
|
70
|
+
# ============================================================
|
|
71
|
+
# Retrofit interfaces
|
|
72
|
+
# ============================================================
|
|
73
|
+
-keep interface com.example.app.data.remote.api.** { *; }
|
|
74
|
+
-keepclassmembernames interface * {
|
|
75
|
+
@retrofit2.http.* <methods>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# ============================================================
|
|
79
|
+
# Hilt — generated components must not be obfuscated
|
|
80
|
+
# ============================================================
|
|
81
|
+
-keep class dagger.hilt.** { *; }
|
|
82
|
+
-keep class javax.inject.** { *; }
|
|
83
|
+
-keep @dagger.hilt.android.HiltAndroidApp class *
|
|
84
|
+
-keep @dagger.hilt.InstallIn class *
|
|
85
|
+
-keep @dagger.hilt.android.AndroidEntryPoint class *
|
|
86
|
+
|
|
87
|
+
# ============================================================
|
|
88
|
+
# Parcelable
|
|
89
|
+
# ============================================================
|
|
90
|
+
-keep class * implements android.os.Parcelable {
|
|
91
|
+
public static final android.os.Parcelable$Creator *;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# ============================================================
|
|
95
|
+
# Enums
|
|
96
|
+
# ============================================================
|
|
97
|
+
-keepclassmembers enum * {
|
|
98
|
+
public static **[] values();
|
|
99
|
+
public static ** valueOf(java.lang.String);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# ============================================================
|
|
103
|
+
# Serialization — kotlinx.serialization
|
|
104
|
+
# ============================================================
|
|
105
|
+
-keepattributes *Annotation*, InnerClasses
|
|
106
|
+
-dontnote kotlinx.serialization.AnnotationsKt
|
|
107
|
+
-keepclassmembers class kotlinx.serialization.json.** {
|
|
108
|
+
*** Companion;
|
|
109
|
+
}
|
|
110
|
+
-keepclasseswithmembers class **$$serializer {
|
|
111
|
+
static **$$serializer INSTANCE;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# ============================================================
|
|
115
|
+
# Crash reporting — keep line numbers for stack traces
|
|
116
|
+
# ============================================================
|
|
117
|
+
-keepattributes SourceFile,LineNumberTable
|
|
118
|
+
-renamesourcefileattribute SourceFile
|
|
119
|
+
|
|
120
|
+
# ============================================================
|
|
121
|
+
# Firebase
|
|
122
|
+
# ============================================================
|
|
123
|
+
-keep class com.google.firebase.** { *; }
|
|
124
|
+
-keep class com.google.android.gms.** { *; }
|
|
125
|
+
|
|
126
|
+
# ============================================================
|
|
127
|
+
# OkHttp / Retrofit
|
|
128
|
+
# ============================================================
|
|
129
|
+
-dontwarn okhttp3.**
|
|
130
|
+
-dontwarn retrofit2.**
|
|
131
|
+
-keep class okhttp3.** { *; }
|
|
132
|
+
-keep interface okhttp3.** { *; }
|
|
133
|
+
|
|
134
|
+
# ============================================================
|
|
135
|
+
# WebView JS interface
|
|
136
|
+
# ============================================================
|
|
137
|
+
-keepclassmembers class * {
|
|
138
|
+
@android.webkit.JavascriptInterface <methods>;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Saving the Mapping File
|
|
145
|
+
|
|
146
|
+
```kotlin
|
|
147
|
+
// ✅ Store mapping file for crash deobfuscation
|
|
148
|
+
// The mapping.txt is generated at:
|
|
149
|
+
// app/build/outputs/mapping/release/mapping.txt
|
|
150
|
+
|
|
151
|
+
// ✅ Upload to Firebase Crashlytics automatically
|
|
152
|
+
android {
|
|
153
|
+
buildTypes {
|
|
154
|
+
release {
|
|
155
|
+
// Crashlytics uploads mapping.txt automatically when minifyEnabled = true
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ✅ Or upload to Play Console manually
|
|
161
|
+
// Google Play Console > App Bundle Explorer > Download mapping.txt
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Decoding Obfuscated Stack Traces
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# ✅ Use retrace to decode a stack trace
|
|
170
|
+
# Located at: $ANDROID_SDK/tools/proguard/bin/retrace.sh
|
|
171
|
+
|
|
172
|
+
retrace.sh mapping.txt obfuscated_stacktrace.txt
|
|
173
|
+
|
|
174
|
+
# ✅ Or use bundletool / R8's retrace
|
|
175
|
+
java -jar r8.jar retrace --map mapping.txt stacktrace.txt
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Testing Obfuscation
|
|
181
|
+
|
|
182
|
+
```kotlin
|
|
183
|
+
// ✅ Create a release variant that's debuggable for testing obfuscation
|
|
184
|
+
android {
|
|
185
|
+
buildTypes {
|
|
186
|
+
create("releaseDebug") {
|
|
187
|
+
initWith(getByName("release"))
|
|
188
|
+
isDebuggable = true
|
|
189
|
+
signingConfig = signingConfigs.getByName("debug")
|
|
190
|
+
applicationIdSuffix = ".releasedebug"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Common Crash Causes After Obfuscation
|
|
199
|
+
|
|
200
|
+
| Crash | Cause | Fix |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| `ClassNotFoundException` | Class renamed by R8 | Add `-keep class com.example.MyClass` |
|
|
203
|
+
| `NoSuchMethodException` | Method renamed | Add `-keepclassmembers` rule |
|
|
204
|
+
| Gson deserialization returns null | DTO fields renamed | Keep DTO fields |
|
|
205
|
+
| Room `IllegalStateException` | Entity/DAO renamed | Keep Room annotated classes |
|
|
206
|
+
| Hilt `ComponentNotFound` | Hilt generated class renamed | Keep Hilt annotations |
|
|
207
|
+
| `NullPointerException` in Retrofit | Interface methods renamed | Keep Retrofit interfaces |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Anti-Patterns
|
|
212
|
+
|
|
213
|
+
- `isMinifyEnabled = false` in release builds — ships unobfuscated code
|
|
214
|
+
- `-keep class com.example.** { *; }` — keeps everything, defeats obfuscation
|
|
215
|
+
- Discarding the mapping file — crash stack traces become unreadable
|
|
216
|
+
- Never testing release builds — obfuscation breaks discovered only in production
|
|
217
|
+
- Obfuscation as the only security measure — combine with encryption, root detection, pinning
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Related Skills
|
|
222
|
+
- `r8` — R8-specific optimization and shrinking beyond obfuscation
|
|
223
|
+
- `proguard` — legacy ProGuard rules reference
|
|
224
|
+
- `reverse-engineering-resistance` — broader anti-tampering strategy
|
|
225
|
+
- `gradle` — build configuration for release variants
|
|
226
|
+
- `build-variant` — managing debug/release/staging variants
|