Skip to content

MASTG-DEMO-0022: Uses of Broken Symmetric Encryption Algorithms in Cipher with semgrep

Download MASTG-DEMO-0022 APK Open MASTG-DEMO-0022 Folder Build MASTG-DEMO-0022 APK

Sample

The code snippet below shows sample code contains use of insecure encryption algorithms.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package org.owasp.mastestapp

import android.content.Context
import java.security.Key
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
import javax.crypto.spec.DESedeKeySpec
import javax.crypto.spec.SecretKeySpec
import android.util.Base64
import java.security.SecureRandom
import javax.crypto.SecretKey

class MastgTest(private val context: Context) {

    // Vulnerable encryption using DES (broken algorithm)
    fun vulnerableDesEncryption(data: String): String {
        try {
            // Insufficient key length for DES
            val keyBytes = ByteArray(8)
            SecureRandom().nextBytes(keyBytes)
            val keySpec = DESKeySpec(keyBytes)
            val keyFactory = SecretKeyFactory.getInstance("DES")
            val secretKey: Key = keyFactory.generateSecret(keySpec)

            // Broken encryption algorithm (DES)
            val cipher = Cipher.getInstance("DES")
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)

            val encryptedData = cipher.doFinal(data.toByteArray())
            return Base64.encodeToString(encryptedData, Base64.DEFAULT)
        } catch (e: Exception) {
            return "Encryption error: ${e.message}"
        }
    }


    // Vulnerable encryption using 3DES (Triple DES)
    fun vulnerable3DesEncryption(data: String): String {
        try {
            val keyBytes = ByteArray(24)
            SecureRandom().nextBytes(keyBytes)
            val keySpec = DESedeKeySpec(keyBytes)
            val keyFactory = SecretKeyFactory.getInstance("DESede")
            val secretKey: Key = keyFactory.generateSecret(keySpec)

            // Broken encryption algorithm (3DES)
            val cipher = Cipher.getInstance("DESede")
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)

            val encryptedData = cipher.doFinal(data.toByteArray())
            return Base64.encodeToString(encryptedData, Base64.DEFAULT)
        } catch (e: Exception) {
            return "Encryption error: ${e.message}"
        }
    }

    // Insecure encryption using RC4 (ARCFOUR) (Deprecated)
    fun vulnerableRc4Encryption(data: String): String {
        return try {
            val keyBytes = ByteArray(16)
            SecureRandom().nextBytes(keyBytes)
            val secretKey = SecretKeySpec(keyBytes, "RC4")

            val cipher = Cipher.getInstance("RC4")
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)

            val encryptedData = cipher.doFinal(data.toByteArray())
            Base64.encodeToString(encryptedData, Base64.DEFAULT)
        } catch (e: Exception) {
            "Encryption error: ${e.message}"
        }
    }

    // Encryption using Blowfish (broken algorithm)
    fun vulnerableBlowfishEncryption(data: String): String {
        return try {
            // Insufficient key length for Blowfish
            val keyBytes = ByteArray(8) // Only 8 bytes (64-bit key) - not secure
            SecureRandom().nextBytes(keyBytes)
            val secretKey: SecretKey = SecretKeySpec(keyBytes, "Blowfish")

            // Broken encryption algorithm (Blowfish)
            val cipher = Cipher.getInstance("Blowfish")
            cipher.init(Cipher.ENCRYPT_MODE, secretKey)

            val encryptedData = cipher.doFinal(data.toByteArray())
            Base64.encodeToString(encryptedData, Base64.DEFAULT)
        } catch (e: Exception) {
            "Encryption error: ${e.message}"
        }
    }


    fun mastgTest(): String {
        val sensitiveString = "Hello from the OWASP MASTG Test app."

        // Encrypt with broken DES
        val desEncryptedString = vulnerableDesEncryption(sensitiveString)

        // Broken with risky 3DES
        val tripleDesEncryptedString = vulnerable3DesEncryption(sensitiveString)

        // Encrypt with broken RC4
        val rc4EncryptedString = vulnerableRc4Encryption(sensitiveString)

        // Encrypt with broken Blowfish
        val blowfishEncryptedString = vulnerableBlowfishEncryption(sensitiveString)

        // Returning the encrypted results
        return "DES Encrypted: $desEncryptedString\n3DES Encrypted: $tripleDesEncryptedString\nRC4 Encrypted: $rc4EncryptedString\nBlowfish Encrypted: $blowfishEncryptedString"
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package org.owasp.mastestapp;

import android.content.Context;
import android.util.Base64;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import kotlin.text.Charsets;

/* compiled from: MastgTest.kt */
@Metadata(d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0006\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\u0006\u0010\u0005\u001a\u00020\u0006J\u000e\u0010\u0007\u001a\u00020\u00062\u0006\u0010\b\u001a\u00020\u0006J\u000e\u0010\t\u001a\u00020\u00062\u0006\u0010\b\u001a\u00020\u0006J\u000e\u0010\n\u001a\u00020\u00062\u0006\u0010\b\u001a\u00020\u0006J\u000e\u0010\u000b\u001a\u00020\u00062\u0006\u0010\b\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\f"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "(Landroid/content/Context;)V", "mastgTest", "", "vulnerable3DesEncryption", "data", "vulnerableBlowfishEncryption", "vulnerableDesEncryption", "vulnerableRc4Encryption", "app_debug"}, k = 1, mv = {1, 9, 0}, xi = 48)
/* loaded from: classes4.dex */
public final class MastgTest {
    public static final int $stable = 8;
    private final Context context;

    public MastgTest(Context context) {
        Intrinsics.checkNotNullParameter(context, "context");
        this.context = context;
    }

    public final String vulnerableDesEncryption(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] keyBytes = new byte[8];
            new SecureRandom().nextBytes(keyBytes);
            DESKeySpec keySpec = new DESKeySpec(keyBytes);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key generateSecret = keyFactory.generateSecret(keySpec);
            Intrinsics.checkNotNullExpressionValue(generateSecret, "generateSecret(...)");
            Key secretKey = generateSecret;
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(1, secretKey);
            byte[] bytes = data.getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
            byte[] encryptedData = cipher.doFinal(bytes);
            String encodeToString = Base64.encodeToString(encryptedData, 0);
            Intrinsics.checkNotNullExpressionValue(encodeToString, "encodeToString(...)");
            return encodeToString;
        } catch (Exception e) {
            return "Encryption error: " + e.getMessage();
        }
    }

    public final String vulnerable3DesEncryption(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] keyBytes = new byte[24];
            new SecureRandom().nextBytes(keyBytes);
            DESedeKeySpec keySpec = new DESedeKeySpec(keyBytes);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
            Key generateSecret = keyFactory.generateSecret(keySpec);
            Intrinsics.checkNotNullExpressionValue(generateSecret, "generateSecret(...)");
            Key secretKey = generateSecret;
            Cipher cipher = Cipher.getInstance("DESede");
            cipher.init(1, secretKey);
            byte[] bytes = data.getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
            byte[] encryptedData = cipher.doFinal(bytes);
            String encodeToString = Base64.encodeToString(encryptedData, 0);
            Intrinsics.checkNotNullExpressionValue(encodeToString, "encodeToString(...)");
            return encodeToString;
        } catch (Exception e) {
            return "Encryption error: " + e.getMessage();
        }
    }

    public final String vulnerableRc4Encryption(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] keyBytes = new byte[16];
            new SecureRandom().nextBytes(keyBytes);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "RC4");
            Cipher cipher = Cipher.getInstance("RC4");
            cipher.init(1, secretKey);
            byte[] bytes = data.getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
            byte[] encryptedData = cipher.doFinal(bytes);
            String encodeToString = Base64.encodeToString(encryptedData, 0);
            Intrinsics.checkNotNull(encodeToString);
            return encodeToString;
        } catch (Exception e) {
            return "Encryption error: " + e.getMessage();
        }
    }

    public final String vulnerableBlowfishEncryption(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] keyBytes = new byte[8];
            new SecureRandom().nextBytes(keyBytes);
            SecretKey secretKey = new SecretKeySpec(keyBytes, "Blowfish");
            Cipher cipher = Cipher.getInstance("Blowfish");
            cipher.init(1, secretKey);
            byte[] bytes = data.getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
            byte[] encryptedData = cipher.doFinal(bytes);
            String encodeToString = Base64.encodeToString(encryptedData, 0);
            Intrinsics.checkNotNull(encodeToString);
            return encodeToString;
        } catch (Exception e) {
            return "Encryption error: " + e.getMessage();
        }
    }

    public final String mastgTest() {
        String desEncryptedString = vulnerableDesEncryption("Hello from the OWASP MASTG Test app.");
        String tripleDesEncryptedString = vulnerable3DesEncryption("Hello from the OWASP MASTG Test app.");
        String rc4EncryptedString = vulnerableRc4Encryption("Hello from the OWASP MASTG Test app.");
        String blowfishEncryptedString = vulnerableBlowfishEncryption("Hello from the OWASP MASTG Test app.");
        return "DES Encrypted: " + desEncryptedString + "\n3DES Encrypted: " + tripleDesEncryptedString + "\nRC4 Encrypted: " + rc4EncryptedString + "\nBlowfish Encrypted: " + blowfishEncryptedString;
    }
}

Steps

Let's run our semgrep rule against the sample code.

../../../../rules/mastg-android-broken-encryption-algorithms.yaml
1
2
3
4
5
6
7
8
9
rules:
  - id: mastg-android-broken-encryption-algorithms
    languages:
      - java
    severity: WARNING
    metadata:
      summary: This rule looks for broken encryption algorithms.
    message: "[MASVS-CRYPTO-1] Broken encryption algorithms found in use."
    pattern-regex: Cipher\.getInstance\("?(DES|DESede|RC4|Blowfish)(/[A-Za-z0-9]+(/[A-Za-z0-9]+)?)?"?\)
run.sh
1
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-broken-encryption-algorithms.yaml ./MastgTest_reversed.java --text > output.txt

Observation

The rule has identified several instances in the code file where broken encryption algorithms are used. The specified line numbers can be located in the reverse-engineered code for further investigation and remediation.

output.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
┌─────────────────┐
 4 Code Findings 
└─────────────────┘

    MastgTest_reversed.java
    ❯❱ rules.mastg-android-broken-encryption-algorithms
          [MASVS-CRYPTO-1] Broken encryption algorithms found in use.

           39 Cipher cipher = Cipher.getInstance("DES");
            ⋮┆----------------------------------------
           62 Cipher cipher = Cipher.getInstance("DESede");
            ⋮┆----------------------------------------
           81 Cipher cipher = Cipher.getInstance("RC4");
            ⋮┆----------------------------------------
          100 Cipher cipher = Cipher.getInstance("Blowfish");

Evaluation

The test fails due to the use of broken encryption algorithms, specifically DES, 3DES, RC4 and Blowfish.

See Broken Symmetric Encryption Algorithms for more information.