String Encryption
Protection ID: stringEncryption
String Encryption replaces plaintext string literals in your bytecode with encrypted versions that are decrypted at runtime. This prevents attackers from extracting API keys, URLs, credentials, and other sensitive data by simply decompiling the APK.
Configuration
shield {
protections {
stringEncryption = true
}
}shield {
protections {
stringEncryption = true
}
}How It Works
String encryption transforms literal string values in your code (API keys, URLs, database connection strings, error messages, and other constants) into encrypted values that are only resolved at runtime. This prevents attackers from easily identifying important values during static analysis of the decompiled APK.
The protection replaces direct string references with calls to optimized decoding methods, effectively hiding the actual values in the decompiled code. Each string uses a unique combination of parameters, making it impractical to write a generic decoder.
Before Shield
public class ApiClient {
private static final String API_KEY = "sk_live_abc123def456";
private static final String BASE_URL = "https://api.example.com/v2";
private static final String AUTH_HEADER = "Authorization";
}public class ApiClient {
private static final String API_KEY = "sk_live_abc123def456";
private static final String BASE_URL = "https://api.example.com/v2";
private static final String AUTH_HEADER = "Authorization";
}After Shield
public class ApiClient {
private static final String API_KEY = htys("\u0012\u0045\u0078...", "xK", 42, true);
private static final String BASE_URL = htys("\u0033\u0067\u0021...", "mQ", 17, false);
private static final String AUTH_HEADER = htys("\u0055\u0012\u0039...", "rT", 8, true);
}public class ApiClient {
private static final String API_KEY = htys("\u0012\u0045\u0078...", "xK", 42, true);
private static final String BASE_URL = htys("\u0033\u0067\u0021...", "mQ", 17, false);
private static final String AUTH_HEADER = htys("\u0055\u0012\u0039...", "rT", 8, true);
}Each encrypted string uses a different combination of key parameters, making pattern-based decryption impractical.
Excluding Strings
If specific strings should not be encrypted (for example, strings used in reflection or JNI), use the @Exclude annotation:
import com.bytehide.shield.annotations.Exclude;
@Exclude(protections = {"StringEncryption"})
public class ReflectionHelper {
// Strings in this class will not be encrypted
public static final String CLASS_NAME = "com.example.MyService";
}import com.bytehide.shield.annotations.Exclude;
@Exclude(protections = {"StringEncryption"})
public class ReflectionHelper {
// Strings in this class will not be encrypted
public static final String CLASS_NAME = "com.example.MyService";
}Or use @Keep to exclude from all protections:
@Keep
public native void nativeMethod();@Keep
public native void nativeMethod();Performance Impact
String decryption adds a small overhead per string access. In practice, this is negligible because decryption is performed at runtime in an optimized way, most strings are accessed infrequently (initialization, error messages), and the runtime cost is microseconds per decryption.
For performance-critical hot paths with repeated string access, consider using @Exclude(protections = {"StringEncryption"}) on the relevant methods.
When to Use
String encryption is recommended for all production builds. It is particularly important for applications that contain API keys or service credentials, authentication tokens or secrets, backend URLs and endpoint paths, database connection strings, license validation logic, or any hardcoded sensitive values.
Related
- Constant Mutation - Protect numeric constants
- Annotations - Exclude specific elements from encryption
- Protections Overview - All available protections