"Your app contains unsafe cryptographic encryption patterns" - How I can get rid of this warning?

 

 

Asked 2 years, 2 months ago
Active 2 years ago
Viewed 5k times
 
7

Few days ago, In "Pre-launch report for APK" in Google Play Console, it start to flag me

Unsafe encryption

Detected in APK ???

Your app contains unsafe cryptographic encryption patterns. Please see this Google Help Centre article for details.

Vulnerable classes:

c.j.a.s.J.b

enter image description here


However, since the early day of APK, I do not change anything in encryption code/ description code. Hence, I'm not sure why Google starts to warn me on recent APK?

Any idea how to resolve? As, the information for vulnerable classes c.j.a.s.J.b is not helpful.

I try to use Proguard + mapping.txt to retrace c.j.a.s.J.b but able to figure what class is that.

Any idea how I can get rid of Google security warning?

  •  
    Did you find any solution.?   Sep 20 '19 at 6:40
  •  
    Not really. I did not find any solution.   Sep 20 '19 at 17:25
  •  
    Is there a class in the resources with each part of the fully qualifying name starting with letters c then j then a and so on? For example: com.java.android.sample.Java...
    – Boris
     Sep 24 '19 at 11:39 
  •  
    Try to find the class that uses crypto like this question https://stackoverflow.com/questions/58026804/unsafe-cryptographic-encryption-patterns-how-to-solve-it, you will see that the KEY is unsafe cryptographic encryption. I resolved it by use Android NDK Native.   Oct 3 '19 at 3:23 
  • 1
    I had the same issue and I didn't used any static key for encryption but the method was static and I changed it to normal class level method and it solved the issue   Nov 27 '19 at 5:42

2 Answers

2

The google play suggests with vulnerable classes with the function name, you can see in the dialog.

Review your app for statically computed keys, initialization vectors, and/or salts that are used in cryptographic encryption operations and ensure that these values are constructed safely

For example :

public byte[] encryptionUtil(String key, String iv, byte[] plainText) {
    Cipher cipher = Cipher.getInstance(“AES/GCM/NoPadding”);
    SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), “AES”);
    GCMParameterSpec paramSpec = new GCMParameterSpec(256, iv.getBytes());
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, paramSpec);
    return cipher.doFinal(plainText);
  }

And you are calling a function as:

byte[] cipherText = encryptionUtil(“abcdef...”, “010203040506”, plainText);

Here your encryption key “abcdef...” is provides as a static string. A statically computed value is a value that is the same on every execution of your app. Statically computed cryptographic values can be extracted from your app and used to attack your app’s encrypted data.

So you can use EncryptedSharedPreferences to store locally data

Reference link https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences

OR

Jetpack Security

For more details: Remediation for Unsafe Cryptographic Encryption

  •  
    security-crypto library forcing to update min-sdk-version 26. Any solution for the lower version?   Nov 6 '19 at 7:03
 
-1

I think you are using some encryption/decryption code with statically stored key. A statically computed value is a value that is the same on every execution of your app. Statically computed cryptographic values can be extracted from your app and used to attack your app’s encrypted data. So Google give this warning to change that stored key with dynamically generated key. For that you can generate different key on every launch. To solve this problem generate dynamic encryption/decryption key on every launch. For that you can find more info here https://developer.android.com/jetpack/androidx/releases/security

  • 1
    What if you need to decrypt some data that was previously encrypted with a former key?   Sep 19 '19 at 5:36
  •  
    For that you can use asymmetric cryptography. which encrypt data with different private key and on other end decrypt data with public key. This link may help you. 
    – Mahesh
     Sep 19 '19 at 6:49 
  • 2
    How is it possible to have a single public key that can decrypt a message encrypted with a different private key? Aren't the keys generated as a standalone pair?   Sep 19 '19 at 11:20 
  •  
    I think, it's not related to original asked questions. Plz ask separate question. but you can get your questions answer from here
    – Mahesh
     Sep 23 '19 at 7:39
     
    https://stackoverflow.com/questions/58002913/your-app-contains-unsafe-cryptographic-encryption-patterns-how-i-can-get-rid
     
     
    #########################################################################################################################################################
     
     
     
    Asked 2 years, 2 months ago
    Viewed 2k times
     
    3
    This question already has answers here:
    Closed 2 years ago.

    I'm encrypting the password for firebase sign in, it's working well but I received a warning in google play console that your app contains unsafe cryptographic encryption patterns how can I get rid of it ??

    I'm trying it on android studio.

    public static class AESCrypt
    {
        private static final String ALGORITHM = "AES";
        private static final String KEY = "1Hbfh667adfDEJ78";
    
        public static String encrypt(String value) throws Exception
        {
            Key key = generateKey();
            Cipher cipher = Cipher.getInstance(AESCrypt.ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte [] encryptedByteValue = cipher.doFinal(value.getBytes("utf-8"));
            String encryptedValue64 = Base64.encodeToString(encryptedByteValue, Base64.DEFAULT);
            return encryptedValue64;
    
        }
    
        public static String decrypt(String value) throws Exception
        {
            Key key = generateKey();
            Cipher cipher = Cipher.getInstance(AESCrypt.ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptedValue64 = Base64.decode(value, Base64.DEFAULT);
            byte [] decryptedByteValue = cipher.doFinal(decryptedValue64);
            String decryptedValue = new String(decryptedByteValue,"utf-8");
            return decryptedValue;
    
        }
    
        private static Key generateKey() throws Exception
        {
            Key key = new SecretKeySpec(AESCrypt.KEY.getBytes(),AESCrypt.ALGORITHM);
            return key;
        }
    
    •  
      What password? The user's password???   Sep 20 '19 at 11:41
    •  
      its email+salt   Sep 21 '19 at 11:32
    3
     
     

    The main issues are that you use a cipher with no integrity and a hard coded cryptographic key. If you analyse your source with Find Security Bugs you get CIPHER_INTEGRITY and HARD_CODE_KEY warning:

    The cipher does not provide data integrity [com.lloyds.keystorage.AESCrypt] At AESCrypt.java:[line 25] CIPHER_INTEGRITY
    The cipher does not provide data integrity [com.lloyds.keystorage.AESCrypt] At AESCrypt.java:[line 15] CIPHER_INTEGRITY
    Hard coded cryptographic key found [com.lloyds.keystorage.AESCrypt] At AESCrypt.java:[line 35] HARD_CODE_KEY
    

    The solution is to use a cipher that includes a Hash based Message Authentication Code (HMAC) to sign the data:

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    

    And to store the secret key in separate configuration files or keystores.

    Below is the whole class after a full refactoring:

    import android.util.Base64
    import static java.nio.charset.StandardCharsets.UTF_8;
    import java.security.Key;
    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    
    public class AESCrypt {
      private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    
      public static String encrypt(String value) throws Exception {
        Key key = generateKey();
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encryptedByteValue = cipher.doFinal(value.getBytes(UTF_8));
        return Base64.encodeToString(encryptedByteValue, Base64.DEFAULT);
      }
    
      public static String decrypt(String value) throws Exception {
        Key key = generateKey();
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedValue64 = Base64.decode(value, Base64.DEFAULT);
        byte[] decryptedByteValue = cipher.doFinal(decryptedValue64);
        return new String(decryptedByteValue, UTF_8);
      }
    
      private static Key generateKey() {
        return new SecretKeySpec(Configuration.getKey().getBytes(UTF_8), TRANSFORMATION);
      }
    }
    
    •  
      But, java.util.Base64 requires API level 26. What's the reason of using java.util.Base64 or android.util.Base64  Sep 22 '19 at 22:32
    •  
      Also, what is the implementation of Configuration.getKey()? If it is always returning the same value for different devices, will Google flag warning again?   Sep 22 '19 at 22:37
    •  
      @CheokYanCheng, can you share a link to the resource showing that you need the level 26 for a Java 8 class java.util.Base64
      – Boris
       Sep 23 '19 at 10:51
    • 1
      See developer.android.com/reference/java/util/Base64.Encoder (Added in API level 26)   Sep 23 '19 at 10:58
    • 1
      @Boris i remove hard code key now the warning gone thanks. :-)   Oct 10 '19 at 6:24
     

    Not the answer you're looking for? Browse other questions tagged    or ask your own question.

     

     

    https://stackoverflow.com/questions/58026804/unsafe-cryptographic-encryption-patterns-how-to-solve-it

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章