Unsafe cryptographic encryption on Android almost always means your app uses AES in ECB mode, which Google Play's security scan flags because ECB leaks patterns in the data. The fix is to stop using ECB and switch to an authenticated mode: AES/GCM with a random, unique nonce for every encryption is the modern recommendation, giving both confidentiality and integrity. Generate keys and nonces with SecureRandom, store keys in the Android Keystore rather than hardcoding them, and consider using Google's Tink library so you do not have to assemble the pieces yourself. After fixing the flagged code, rebuild and the Play Console warning clears on the next scan.
Short answer
The warning means your app encrypts with a weak mode, almost always AES/ECB, and the fix is an authenticated cipher. Per Google's remediation guidance, ECB produces weak ciphertext because identical plaintext blocks become identical ciphertext blocks, so replace it. Per Android's cryptography guide, use AES/GCM with a fresh random nonce per message, generate keys and nonces with SecureRandom, and keep keys in the Android Keystore. Google's Play Console notice lists the exact locations, and a location ending in dynamically loaded code means it is in a library. Fix each flagged spot, or adopt Tink for safe defaults, then rebuild.
What unsafe cryptographic encryption means
Unsafe cryptographic encryption is Google Play's label for using a cipher configuration that is known to be insecure, and in practice it almost always points to AES in ECB mode. Google's App Security Improvement program scans uploaded apps and warns when it detects the pattern, because encrypting with ECB can produce weak ciphertext that puts user data at risk. The warning is not about whether you encrypt, but about how, and ECB is the how it objects to.
The reason is specific to how ECB works, not a general distrust of AES. AES itself is a strong algorithm; the problem is the mode you run it in. ECB encrypts each block independently, which means the same input block always yields the same output block, so structure in your data survives into the ciphertext. Google's scan flags this because it is a well-understood weakness with a clear fix, and the fix is to change the mode rather than to abandon AES. The rest of resolving the warning is choosing a safe mode and handling keys and nonces correctly.
AES/GCM versus ECB
The difference between AES/GCM and AES/ECB is the difference between a mode that is safe by design and one that leaks. ECB, the electronic codebook mode, encrypts each block of data on its own with no chaining, so two identical plaintext blocks produce two identical ciphertext blocks. That lets an observer see repetition and structure in the encrypted data, and ECB provides no integrity, so tampering is not detected. This is exactly what Google Play flags.
AES/GCM, the Galois Counter Mode, is an authenticated encryption mode that fixes both problems. It uses a nonce, a number used once, so identical plaintext encrypts to different ciphertext each time, hiding the patterns ECB exposes. It also produces an authentication tag that lets you detect any tampering with the ciphertext, giving integrity alongside confidentiality. The one rule you must follow is never to reuse a nonce with the same key, because nonce reuse in GCM is catastrophic. Used correctly, with a fresh random nonce per message, GCM is the recommended replacement for ECB and resolves the underlying weakness rather than just quieting the warning.
The Google Play warning and where to find it
When Google Play flags unsafe encryption, the Play Console notification for your app lists the exact locations of the insecure encryption calls, which is where you start. Each entry points to a place in your code or a dependency where the ECB pattern was detected, so you fix those specific spots rather than guessing. Reading the notification carefully saves time, because it tells you precisely what to change.
Pay attention to how each location is described. If a location ends with a note that it is in dynamically loaded code, the pattern is inside code loaded at runtime by your app or by a library it uses, which means the offending call may not be in your own source at all. In that case you address it by updating or replacing the third-party library that contains the weak cipher, since you cannot edit the library's code directly. Distinguishing your own code from a bundled library is the key to fixing the right thing, and the notification gives you that distinction.
How to fix it: the safe pattern
The safe pattern is to replace the ECB cipher with an authenticated mode and handle the inputs correctly. Move from an AES/ECB cipher to AES/GCM, requesting the cipher as AES/GCM/NoPadding, and supply a fresh random nonce for every encryption operation. Store or transmit that nonce alongside the ciphertext, since you need it to decrypt, and never reuse a nonce with the same key. This single change addresses the weakness Google flags and gives you integrity as a bonus.
If GCM is not available in your context, Google's remediation also accepts AES in CBC mode with a randomly generated key and a random initialization vector retrieved from the cipher, requested as AES/CBC/PKCS5Padding. Be aware that CBC alone does not provide integrity, so pair it with a separate message authentication code such as HMAC in an encrypt-then-authenticate design if tampering is a concern. Between the two, GCM is the simpler and safer default because integrity is built in, while CBC plus HMAC is a valid but more error-prone alternative.
Keys, initialization vectors, and randomness
Fixing the mode is only part of the job; the key, the nonce, and the randomness behind them matter just as much. Generate keys and nonces using SecureRandom, the cryptographically strong random source, rather than java.util.Random, which is predictable and unsuitable for security. A strong cipher mode with a predictable key or a predictable nonce is not secure, so the source of randomness is part of the fix, not an afterthought.
Store your keys in the Android Keystore rather than hardcoding them or keeping them in shared preferences, since a hardcoded key can be extracted from the app and a key is only as protected as where it lives. The Keystore keeps key material out of your app's process and, on supported devices, in hardware-backed storage. And never use a static or reused initialization vector; each encryption needs its own fresh nonce. Getting the mode right while reusing an IV or hardcoding a key simply moves the weakness rather than removing it.
Use Tink to avoid the footguns
Because assembling cipher, mode, nonce, key storage, and randomness correctly has many places to slip, using a higher-level library is often the safer path. Google's Tink library provides authenticated encryption through a simple interface, choosing secure algorithms and handling nonces and key management for you, so you make fewer low-level decisions and hit fewer footguns. For many apps, adopting Tink is faster and safer than hand-rolling AES/GCM.
The advantage is that Tink is designed so the easy path is the secure path. It steers you toward authenticated encryption, manages keys through keysets you can back with the Android Keystore, and removes the temptation to reuse a nonce or pick a weak mode. If your flagged code is your own, replacing it with Tink resolves the warning and reduces the chance of a future crypto mistake. If the flagged code is in a dependency, updating that dependency to a version that uses safe crypto is the equivalent move. Either way, the goal is to let well-built code make the hard choices.
Safe versus unsafe crypto
Sorting the common choices into safe and unsafe makes the fixes concrete. The table below compares them.
| Practice | Unsafe | Safe replacement |
|---|---|---|
| Cipher mode | AES/ECB | AES/GCM authenticated mode |
| Integrity | None with ECB or bare CBC | GCM tag, or encrypt-then-HMAC |
| Nonce or IV | Static or reused | Fresh random value per message |
| Randomness | java.util.Random | SecureRandom |
| Key storage | Hardcoded or plain preferences | Android Keystore |
| Algorithm or hash | DES, 3DES, RC4, MD5, SHA-1 | AES-256, SHA-256 or stronger |
Read the table row by row against your code: each unsafe entry has a direct, safe replacement, and moving every row to the right column is what clears the warning and actually protects the data.
Remediation checklist
Working through the steps in order fixes the flagged code and confirms it. The checklist below covers them.
| Step | Action | Done? |
|---|---|---|
| Find the flag | Read the exact locations in the Play Console notice | [ ] |
| Replace ECB | Move to AES/GCM, or CBC with HMAC | [ ] |
| Use a fresh nonce | Random, unique per encryption, never reused | [ ] |
| Use SecureRandom | For all keys and nonces | [ ] |
| Store keys in Keystore | Remove hardcoded or plaintext keys | [ ] |
| Rebuild and re-scan | Confirm the warning clears, update flagged libraries | [ ] |
The step people miss is the last part of the second row: if the flag is in dynamically loaded code, update the library rather than searching your own source, because the weak cipher is not in code you wrote.
Scan your build for weak crypto
Because weak crypto can hide in your own code or in a bundled library, and because the Play Console flags only what its scan detects, checking your build directly gives you a fuller picture before you submit. Knowing where ciphers, keys, and hashes live in your app is the input to fixing them once rather than in repeated review rounds.
A scanner like PTKD.com analyzes your build and reports issues such as weak or broken cryptography, hardcoded keys, and insecure data storage by severity, mapped to OWASP MASVS, whose cryptography category covers exactly these patterns. To be clear about the boundary: PTKD does not rewrite your cipher code or clear the Google Play warning for you. It finds the weak crypto, including in dependencies, so you know what to replace before the scan flags it.
What to take away
- Unsafe cryptographic encryption on Android almost always means AES/ECB, which Google Play flags because identical plaintext blocks become identical ciphertext, leaking patterns.
- Replace ECB with AES/GCM, an authenticated mode that hides patterns and detects tampering, using a fresh random nonce for every message and never reusing one with the same key.
- Generate keys and nonces with SecureRandom, store keys in the Android Keystore, and never use a static IV or a hardcoded key.
- Read the Play Console notice for exact locations; a location in dynamically loaded code means the weak cipher is in a library you should update, not your own source.
- Consider Google's Tink for safe defaults, and scan your build with a tool like PTKD.com to catch weak crypto before the Play scan does.




