How to encrypt and decrypt an audio file in Android?

By | May 8, 2018

Here is a simple example to encrypt and decrypt a audio file in Android.

We will directly go to the implementation part.

Demo Video

You can check the demo video here.

Download Library

You can download the simple library from here.

Aim

  • Download an audio file from internet.
  • Encrypt and save the encrypted file in Disk, so that no one can open it.
  • Decrypt the same file.
  • Play the file.

Classes

For accomplishing the above tasks we have the below utility files.

  • EncryptDecryptUtils – The file which encrypt and decrypts a file.
  • FileUtils – This file is used for file operations.
  • PrefUtils – For saving the key.
  • Player – For playing the audio.

You would probably need the first three classes for encrypt and decrypting any type of files, not only the audio files.
Encryption and Decryption will return the file contents in terms of bytes.

Lets check how the EncryptDecryptUtils looks like

EncryptDecryptUtils


import android.content.Context;
import android.util.Base64;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.CIPHER_ALGORITHM;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.KEY_SPEC_ALGORITHM;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.OUTPUT_KEY_LENGTH;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.PROVIDER;

/**
 * Created by James From CoderzHeaven on 5/2/18.
 */

public class EncryptDecryptUtils {

    public static EncryptDecryptUtils instance = null;
    private static PrefUtils prefUtils;

    public static EncryptDecryptUtils getInstance(Context context) {

        if (null == instance)
            instance = new EncryptDecryptUtils();

        if (null == prefUtils)
            prefUtils = PrefUtils.getInstance(context);

        return instance;
    }

    public static byte[] encode(SecretKey yourKey, byte[] fileData)
            throws Exception {
        byte[] data = yourKey.getEncoded();
        SecretKeySpec skeySpec = new SecretKeySpec(data, 0, data.length, KEY_SPEC_ALGORITHM);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        return cipher.doFinal(fileData);
    }

    public static byte[] decode(SecretKey yourKey, byte[] fileData)
            throws Exception {
        byte[] decrypted;
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
        cipher.init(Cipher.DECRYPT_MODE, yourKey, new IvParameterSpec(new byte[cipher.getBlockSize()]));
        decrypted = cipher.doFinal(fileData);
        return decrypted;
    }

    public void saveSecretKey(SecretKey secretKey) {
        String encodedKey = Base64.encodeToString(secretKey.getEncoded(), Base64.NO_WRAP);
        prefUtils.saveSecretKey(encodedKey);
    }

    public SecretKey getSecretKey() {
        String encodedKey = prefUtils.getSecretKey();
        if (null == encodedKey || encodedKey.isEmpty()) {
            SecureRandom secureRandom = new SecureRandom();
            KeyGenerator keyGenerator = null;
            try {
                keyGenerator = KeyGenerator.getInstance(KEY_SPEC_ALGORITHM);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            keyGenerator.init(OUTPUT_KEY_LENGTH, secureRandom);
            SecretKey secretKey = keyGenerator.generateKey();
            saveSecretKey(secretKey);
            return secretKey;
        }

        byte[] decodedKey = Base64.decode(encodedKey, Base64.NO_WRAP);
        SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, KEY_SPEC_ALGORITHM);
        return originalKey;
    }

}

FileUtils

Helps in file related operations.


import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.DIR_NAME;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.FILE_EXT;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.FILE_NAME;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.TEMP_FILE_NAME;

/**
 * Created by James From CoderzHeaven on 5/6/18.
 */

public class FileUtils {

    public static void saveFile(byte[] encodedBytes, String path) {
        try {
            File file = new File(path);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bos.write(encodedBytes);
            bos.flush();
            bos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static byte[] readFile(String filePath) {
        byte[] contents;
        File file = new File(filePath);
        int size = (int) file.length();
        contents = new byte[size];
        try {
            BufferedInputStream buf = new BufferedInputStream(
                    new FileInputStream(file));
            try {
                buf.read(contents);
                buf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return contents;
    }

    @NonNull
    public static File createTempFile(Context context, byte[] decrypted) throws IOException {
        File tempFile = File.createTempFile(TEMP_FILE_NAME, FILE_EXT, context.getCacheDir());
        tempFile.deleteOnExit();
        FileOutputStream fos = new FileOutputStream(tempFile);
        fos.write(decrypted);
        fos.close();
        return tempFile;
    }

    public static FileDescriptor getTempFileDescriptor(Context context, byte[] decrypted) throws IOException {
        File tempFile = FileUtils.createTempFile(context, decrypted);
        FileInputStream fis = new FileInputStream(tempFile);
        return fis.getFD();
    }

    public static final String getDirPath(Context context) {
        return context.getDir(DIR_NAME, Context.MODE_PRIVATE).getAbsolutePath();
    }

    public static final String getFilePath(Context context) {
        return getDirPath(context) + File.separator + FILE_NAME;
    }

    public static final void deleteDownloadedFile(Context context) {
        File file = new File(getFilePath(context));
        if (null != file && file.exists()) {
            if (file.delete()) Log.i("FileUtils", "File Deleted.");
        }
    }

}

PrefUtils

Helps in saving the values in preferences.


import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.SECRET_KEY;

public class PrefUtils {

    public static final PrefUtils prefUtils = new PrefUtils();
    public static SharedPreferences myPrefs = null;

    public static PrefUtils getInstance(Context context) {
        if (null == myPrefs)
            myPrefs = PreferenceManager.getDefaultSharedPreferences(context);
        return prefUtils;
    }

    public void saveSecretKey(String value) {
        SharedPreferences.Editor editor = myPrefs.edit();
        editor.putString(SECRET_KEY, value);
        editor.commit();
    }

    public String getSecretKey() {
        return myPrefs.getString(SECRET_KEY, null);
    }
}

Player

Helps in MediaPlayer related operations.


import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Message;

import java.io.FileDescriptor;

/**
 * Created by James from CoderzHeaven on 5/7/18.
 */

public class Player implements MediaPlayer.OnCompletionListener {

    private MediaPlayer mediaPlayer;
    private Handler handler;

    public Player(Handler handler) {
        this.handler = handler;
    }

    private void initPlayer() {
        if (null == mediaPlayer) {
            mediaPlayer = new MediaPlayer();
        }
    }

    public void play(FileDescriptor fileDescriptor) {
        initPlayer();
        stopAudio();
        playAudio(fileDescriptor);
    }

    public void playAudio(FileDescriptor fileDescriptor) {
        mediaPlayer.reset();
        try {
            mediaPlayer.setOnCompletionListener(this);
            mediaPlayer.setDataSource(fileDescriptor);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (Exception e) {
        }
    }

    private void stopAudio() {
        if (null != mediaPlayer && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
        }
    }

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        Message message = new Message();
        message.obj = "Audio play completed.";
        handler.dispatchMessage(message);
    }

    private void releasePlayer() {
        if (null != mediaPlayer) {
            mediaPlayer.release();
        }
    }

    public void destroyPlayer() {
        stopAudio();
        releasePlayer();
        mediaPlayer = null;
    }
}

MainActivity

Finally the main activity that does the implementation.
The layout for the activity is pasted below.

package encrypt_decrypt.coderzheaven.com.encryptdecryptandroid;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.downloader.Error;
import com.downloader.OnDownloadListener;
import com.downloader.PRDownloader;

import java.io.FileDescriptor;
import java.io.IOException;

import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.DOWNLOAD_AUDIO_URL;
import static encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.Constants.FILE_NAME;

public class MainActivity extends AppCompatActivity implements OnDownloadListener, Handler.Callback {

    private Player player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        player = new Player(new Handler(this));
    }

    public final void updateUI(String msg) {
        ((TextView) findViewById(R.id.statusTv)).setText(msg);
    }

    public void onClick(View view) {
        int id = view.getId();
        switch (id) {
            case R.id.download:
                downloadAudio();
                break;
            case R.id.encrypt:
                if (encrypt()) updateUI("File encrypted successfully.");
                break;
            case R.id.decrypt:
                if (null != decrypt()) updateUI("File decrypted successfully.");
                break;
            case R.id.play:
                playClicked();
                break;
            default:
                updateUI("Unknown Click");
        }
    }

    private void playClicked() {
        try {
            playAudio(FileUtils.getTempFileDescriptor(this, decrypt()));
        } catch (IOException e) {
            updateUI("Error Playing Audio.\nException: " + e.getMessage());
            return;
        }
    }

    private void downloadAudio() {
        // Delete the old file //
        FileUtils.deleteDownloadedFile(this);
        updateUI("Downloading audio file...");
        PRDownloader.download(DOWNLOAD_AUDIO_URL, FileUtils.getDirPath(this), FILE_NAME).build().start(this);
    }

    /**
     * Encrypt and save to disk
     *
     * @return
     */
    private boolean encrypt() {
        updateUI("Encrypting file...");
        try {
            byte[] fileData = FileUtils.readFile(FileUtils.getFilePath(this));
            byte[] encodedBytes = EncryptDecryptUtils.encode(EncryptDecryptUtils.getInstance(this).getSecretKey(), fileData);
            FileUtils.saveFile(encodedBytes, FileUtils.getFilePath(this));
            return true;
        } catch (Exception e) {
            updateUI("File Encryption failed.\nException: " + e.getMessage());
        }
        return false;
    }

    /**
     * Decrypt and return the decoded bytes
     *
     * @return
     */
    private byte[] decrypt() {
        updateUI("Decrypting file...");
        try {
            byte[] fileData = FileUtils.readFile(FileUtils.getFilePath(this));
            byte[] decryptedBytes = EncryptDecryptUtils.decode(EncryptDecryptUtils.getInstance(this).getSecretKey(), fileData);
            return decryptedBytes;
        } catch (Exception e) {
            updateUI("File Decryption failed.\nException: " + e.getMessage());
        }
        return null;
    }

    private void playAudio(FileDescriptor fileDescriptor) {
        if (null == fileDescriptor) {
            return;
        }
        updateUI("Playing audio...");
        player.play(fileDescriptor);
    }

    @Override
    public void onDownloadComplete() {
        updateUI("File Download complete");
    }

    @Override
    public void onError(Error error) {
        updateUI("File Download Error");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        player.destroyPlayer();
    }

    @Override
    public boolean handleMessage(Message message) {
        if (null != message) {
            updateUI(message.obj.toString());
        }
        return false;
    }
}

Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:animateLayoutChanges="true" android:orientation="vertical" android:padding="20dp" tools:context="encrypt_decrypt.coderzheaven.com.encryptdecryptandroid.MainActivity">

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="20dp" android:gravity="center" android:text="[ Tap the buttons in order for the demo ]" android:textColor="@android:color/holo_red_dark" />

    <Button android:id="@+id/download" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" android:gravity="left|center" android:onClick="onClick" android:text="1. Download Audio" />

    <Button android:id="@+id/encrypt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" android:gravity="left|center" android:onClick="onClick" android:text="2. Encrypt Audio" />

    <Button android:id="@+id/decrypt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" android:gravity="left|center" android:onClick="onClick" android:text="3. Decrypt Audio" />

    <Button android:id="@+id/play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" android:gravity="left|center" android:onClick="onClick" android:text="4. Play" />

    <TextView android:id="@+id/statusTv" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" android:layout_weight="0.7" android:gravity="center" android:textColor="@android:color/holo_green_dark" android:textSize="20sp" />

    <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="bottom" android:layout_marginBottom="20dp" android:layout_weight="1" android:gravity="center" android:text="coderzheaven.com" />

</LinearLayout>

Source Code

You can download the complete source code from here.

4 thoughts on “How to encrypt and decrypt an audio file in Android?

  1. arsalan

    thank you for the nice tutorial, please guide me how to play encrypted video in android? I want to encrypt a video file and copy to sd card, then in my app decrypt this video in the air and play in the video view.

    Reply
  2. Monir

    Thanks a lot for your codes.
    I’m new in android, so I need help.
    Are they correct?
    public class Constants {
    static String SECRET_KEY = “ASDFGHJKLASDFGHJ”;
    static String DIR_NAME = “com….”; //My package name
    static String FILE_EXT = “mp3”;
    static String FILE_NAME = “1.mp3”;
    static String TEMP_FILE_NAME = “tset”;
    static String CIPHER_ALGORITHM = “AES”;
    static String KEY_SPEC_ALGORITHM = “AES”;
    static int OUTPUT_KEY_LENGTH = 128;
    static String PROVIDER = “BC”;
    }
    My problem is about DIR_NAME.
    Thanks in advance

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *