Skip to content

MASTG-DEMO-0023: Uses of Insecure Encryption Modes in Cipher with semgrep

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

Sample

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

  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
121
122
123
124
125
126
127
128
129
130
131
132
133
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

class MastgTest(private val context: Context) {

    // Vulnerable AES encryption
    fun vulnerableAesEncryption(data: String): String {
        try {
            val key = "1234567890123456".toByteArray() // 16 bytes key for AES
            val secretKeySpec = SecretKeySpec(key, "AES")

            // Default mode for AES (ECB)
            val cipher = Cipher.getInstance("AES")
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec)

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

    // Vulnerable AES with ECB and NoPadding (manual padding applied)
    fun vulnerableAesEcbNoPadding(data: String): String {
        try {
            val key = "1234567890123456".toByteArray()
            val secretKeySpec = SecretKeySpec(key, "AES")

            val cipher = Cipher.getInstance("AES/ECB/NoPadding")
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec)

            // Ensure the data is padded to match the block size
            val blockSize = 16
            val paddingLength = blockSize - (data.length % blockSize)
            val paddedData = data + "\u0000".repeat(paddingLength) // Null padding

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

    // Vulnerable AES with ECB and PKCS5Padding
    fun vulnerableAesEcbPkcs5Padding(data: String): String {
        try {
            val key = "1234567890123456".toByteArray()
            val secretKeySpec = SecretKeySpec(key, "AES")

            val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec)

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

    // Vulnerable AES with ECB and ISO10126Padding
    fun vulnerableAesEcbIso10126Padding(data: String): String {
        try {
            val key = "1234567890123456".toByteArray()
            val secretKeySpec = SecretKeySpec(key, "AES")

            val cipher = Cipher.getInstance("AES/ECB/ISO10126Padding")
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec)

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

    // Vulnerable DES with ECB and PKCS5Padding
    fun vulnerableDesEcbPkcs5Padding(data: String): String {
        try {
            val keySpec = DESKeySpec("12345678".toByteArray())
            val keyFactory = SecretKeyFactory.getInstance("DES")
            val secretKey: Key = keyFactory.generateSecret(keySpec)

            val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding")
            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 3DES with ECB and PKCS5Padding
    fun vulnerable3DesEcbPkcs5Padding(data: String): String {
        try {
            val keySpec = DESedeKeySpec("123456789012345678901234".toByteArray())
            val keyFactory = SecretKeyFactory.getInstance("DESede")
            val secretKey: Key = keyFactory.generateSecret(keySpec)

            val cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding")
            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}"
        }
    }

    // Test and return results
    fun mastgTest(): String {
        val sensitiveString = "Hello from OWASP MASTG!"

        val results = listOf(
            "AES Default: ${vulnerableAesEncryption(sensitiveString)}",
            "AES ECB NoPadding: ${vulnerableAesEcbNoPadding(sensitiveString)}",
            "AES ECB PKCS5Padding: ${vulnerableAesEcbPkcs5Padding(sensitiveString)}",
            "AES ECB ISO10126Padding: ${vulnerableAesEcbIso10126Padding(sensitiveString)}",
            "DES ECB PKCS5Padding: ${vulnerableDesEcbPkcs5Padding(sensitiveString)}",
            "3DES ECB PKCS5Padding: ${vulnerable3DesEcbPkcs5Padding(sensitiveString)}"
        )

        return results.joinToString("\n")
    }
}
  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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package org.owasp.mastestapp;

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

/* 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\b\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\u0006J\u000e\u0010\f\u001a\u00020\u00062\u0006\u0010\b\u001a\u00020\u0006J\u000e\u0010\r\u001a\u00020\u00062\u0006\u0010\b\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u000e"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "(Landroid/content/Context;)V", "mastgTest", "", "vulnerable3DesEcbPkcs5Padding", "data", "vulnerableAesEcbIso10126Padding", "vulnerableAesEcbNoPadding", "vulnerableAesEcbPkcs5Padding", "vulnerableAesEncryption", "vulnerableDesEcbPkcs5Padding", "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 vulnerableAesEncryption(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] key = "1234567890123456".getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(key, "this as java.lang.String).getBytes(charset)");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(1, secretKeySpec);
            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 vulnerableAesEcbNoPadding(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] key = "1234567890123456".getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(key, "this as java.lang.String).getBytes(charset)");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
            cipher.init(1, secretKeySpec);
            int paddingLength = 16 - (data.length() % 16);
            String paddedData = data + StringsKt.repeat("\u0000", paddingLength);
            byte[] bytes = paddedData.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 StringsKt.trim((CharSequence) encodeToString).toString();
        } catch (Exception e) {
            return "Encryption error: " + e.getMessage();
        }
    }

    public final String vulnerableAesEcbPkcs5Padding(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] key = "1234567890123456".getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(key, "this as java.lang.String).getBytes(charset)");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(1, secretKeySpec);
            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 vulnerableAesEcbIso10126Padding(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] key = "1234567890123456".getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(key, "this as java.lang.String).getBytes(charset)");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/ISO10126Padding");
            cipher.init(1, secretKeySpec);
            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 vulnerableDesEcbPkcs5Padding(String data) {
        Intrinsics.checkNotNullParameter(data, "data");
        try {
            byte[] bytes = "12345678".getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
            DESKeySpec keySpec = new DESKeySpec(bytes);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key generateSecret = keyFactory.generateSecret(keySpec);
            Intrinsics.checkNotNullExpressionValue(generateSecret, "generateSecret(...)");
            Key secretKey = generateSecret;
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(1, secretKey);
            byte[] bytes2 = data.getBytes(Charsets.UTF_8);
            Intrinsics.checkNotNullExpressionValue(bytes2, "this as java.lang.String).getBytes(charset)");
            byte[] encryptedData = cipher.doFinal(bytes2);
            String encodeToString = Base64.encodeToString(encryptedData, 0);
            Intrinsics.checkNotNullExpressionValue(encodeToString, "encodeToString(...)");
            return encodeToString;
        } catch (Exception e) {
            return "Encryption error: " + e.getMessage();
        }
    }

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

    public final String mastgTest() {
        List results = CollectionsKt.listOf((Object[]) new String[]{"AES Default: " + vulnerableAesEncryption("Hello from OWASP MASTG!"), "AES ECB NoPadding: " + vulnerableAesEcbNoPadding("Hello from OWASP MASTG!"), "AES ECB PKCS5Padding: " + vulnerableAesEcbPkcs5Padding("Hello from OWASP MASTG!"), "AES ECB ISO10126Padding: " + vulnerableAesEcbIso10126Padding("Hello from OWASP MASTG!"), "DES ECB PKCS5Padding: " + vulnerableDesEcbPkcs5Padding("Hello from OWASP MASTG!"), "3DES ECB PKCS5Padding: " + vulnerable3DesEcbPkcs5Padding("Hello from OWASP MASTG!")});
        return CollectionsKt.joinToString$default(results, "\n", null, null, 0, null, null, 62, null);
    }
}

Steps

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

../../../../rules/mastg-android-weak-encryption-modes.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
rules:
  - id: weak-encryption-modes
    languages:
      - java
    severity: WARNING
    metadata:
      summary: This rule looks for weak encryption modes.
    message: "[MASVS-CRYPTO-1] Weak encryption modes found in use."
    pattern-either:
      - pattern: Cipher.getInstance("AES")
      - pattern-regex: Cipher\.getInstance\("?[A-Za-z0-9]+/ECB(/[A-Za-z0-9]+)?"?\)
run.sh
1
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-weak-encryption-modes.yaml ./MastgTest_reversed.java --text > output.txt

Observation

The rule has identified six instances in the code file where insecure encryption modes 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
16
17
18
19
┌─────────────────┐
 6 Code Findings 
└─────────────────┘

    MastgTest_reversed.java
    ❯❱ rules.weak-encryption-modes
          [MASVS-CRYPTO-1] Weak encryption modes found in use.

           36 Cipher cipher = Cipher.getInstance("AES");
            ⋮┆----------------------------------------
           55 Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
            ⋮┆----------------------------------------
           76 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            ⋮┆----------------------------------------
           95 Cipher cipher = Cipher.getInstance("AES/ECB/ISO10126Padding");
            ⋮┆----------------------------------------
          118 Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            ⋮┆----------------------------------------
          141 Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");

Evaluation

The test fails since the output contains several instances of the ECB mode of AES in different transformations explicitly or implicitly (ECB is the default mode for AES if not specified).

See Weak Symmetric Encryption Modes for more information.