Skip to content

Added sharedprefs monitor for Android #622

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

CDuPlooy
Copy link
Contributor

This adds in functionality to monitor usage of the Android shared preferences (includes Jetpack encrypted shared preferences)

To use, issue the command android sharedprefs monitor, you can specify that only encrypted shared prefs should be monitored using the flag --encrypted-only

I'm just doing one or two last test cases and will open a complete PR after.

@leonjza
Copy link
Member

leonjza commented May 23, 2024

Just checking on this one, is this the complete PR in the end? :) Got a test app to play with maybe?

@CDuPlooy
Copy link
Contributor Author

Geez, sorry for the non-response. Seeing if I can get an example of this up and running and catching up to master quick

@CDuPlooy
Copy link
Contributor Author

CDuPlooy commented Apr 27, 2025

I created an android app with a basic activity, then replaced main with:

package com.example.encryptedsharedprefsdemojava;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;

import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;

import android.view.View;

import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKey;

import com.example.encryptedsharedprefsdemojava.databinding.ActivityMainBinding;

import android.view.Menu;
import android.view.MenuItem;

import java.io.IOException;
import java.security.GeneralSecurityException;

public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setSupportActionBar(binding.toolbar);

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        Context c  = this;
        binding.fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MasterKey masterKey = null;
                try {
                    masterKey = new MasterKey.Builder(c)
                            .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                            .build();
                } catch (GeneralSecurityException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                SharedPreferences sharedPreferences = null;
                try {
                    sharedPreferences = EncryptedSharedPreferences.create(
                            c,
                            "secret_shared_prefs",
                            masterKey,
                            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
                    );
                } catch (GeneralSecurityException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                // use the shared preferences and editor as you normally would
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("eMsg", "Hello from ZA");
                editor.commit();
                sharedPreferences.getString("eMsg", "");

                SharedPreferences cleartextSP = c.getSharedPreferences("dont_care", MODE_PRIVATE);
                SharedPreferences.Editor ed = cleartextSP.edit();
                ed.putString("cleartextMessage", "Bye from ZA");
                ed.commit();
                cleartextSP.getString("cleartextMessage", "dont_care");
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }
}

Gradle build:

plugins {
    alias(libs.plugins.android.application)
}

android {
    namespace = "com.example.encryptedsharedprefsdemojava"
    compileSdk = 35

    defaultConfig {
        applicationId = "com.example.encryptedsharedprefsdemojava"
        minSdk = 24
        targetSdk = 35
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    buildFeatures {
        viewBinding = true
    }
}

dependencies {
    implementation("androidx.security:security-crypto:1.1.0-alpha03")
    implementation(libs.appcompat)
    implementation(libs.material)
    implementation(libs.constraintlayout)
    implementation(libs.navigation.fragment)
    implementation(libs.navigation.ui)
    testImplementation(libs.junit)
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

When you hit the only button on the app, it should create a cleartext and encrypted shared preferences entry.

Apparently tink has been deprecated, so now, so is this interface, with the documentation pointing people to standard shared preferences which is a real shame. You would think somebody looking up encrypted shared preferences is doing so for a reason :/

I guess we'll still be seeing it around for a while though.

Screenshot 2025-04-27 at 18 51 01

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants