Add encryption in firebase group chat

 Brief summary of this post:

1. The user enters a passphrase which is unique to the group chat and has to be shared to the user for granting him access.

2. The passphrase is saved in SharedPreferences.

3. A master key is generated using the passphrase.

4. While sending message, a secret key is generated using the master key and message ID. The message is encrypted using this secret key.

5. On retrieving message, it is decrypted using a secret key generated using master key and message ID.


Steps:

1. In Button to enter the group chat page, add a dialog box (dialog2) with EditText (dialog_text1) where user can enter the passphrase. On entering the passphrase it is saved in SharedPreferences (sp:sp) and user moves to group chat activity using intent component.



Code to add an EditText to Dialog component:

final EditText dialog_text1 = new EditText(AdminpageActivity.this);

dialog_text1.setLayoutParams(linear2.getLayoutParams());

dialog2.setView(dialog_text1);

Code to get text from EditText:

dialog_text1.getText().toString()

2. Add another button which can be used to reenter passphrase, in case user has entered the wrong passphrase.



3. In local library manager, add the following library and select it:

androidx.security:security-crypto:1.1.0-alpha06

4. In Java/Kotlin manager, add a new Java class file EncryptionHelper.java and put following codes in it. Make sure to keep your own package name at the top.


package com.my.dmchat;

import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;
import java.util.Arrays;

import android.content.SharedPreferences;
import android.content.Context;
import androidx.security.crypto.MasterKey;
import androidx.security.crypto.EncryptedFile;
import androidx.security.crypto.EncryptedSharedPreferences;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyStore;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.Mac;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.spec.KeySpec;
import javax.crypto.spec.SecretKeySpec;

public class EncryptionHelper {

    /**
     * Derives a Master Key from a given passphrase using PBKDF2.
     * @param passphrase The user's passphrase.
     * @return SecretKey The derived master key.
     * @throws Exception if key derivation fails.
     */
    public static SecretKey deriveMasterKey(String passphrase) throws Exception {
        byte[] salt = "SomeFixedSaltValue".getBytes(StandardCharsets.UTF_8); // Can be static or unique per chat
        int iterations = 100000;
        int keyLength = 256;

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), salt, iterations, keyLength);
        SecretKey tmpKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");

        return tmpKey;
    }

    /**
     * Derives a unique chat-specific encryption key from the master key using HMAC.
     * @param masterKey The master key.
     * @param chatID The chat identifier.
     * @return SecretKey The derived chat key.
     * @throws Exception if key derivation fails.
     */
    public static SecretKey deriveChatKey(SecretKey masterKey, String chatID) throws Exception {
        Mac hmac = Mac.getInstance("HmacSHA256");
        hmac.init(masterKey);
        byte[] secretKeyBytes = hmac.doFinal(chatID.getBytes(StandardCharsets.UTF_8));
        
        return new SecretKeySpec(Arrays.copyOf(secretKeyBytes, 16), "AES"); // 128-bit AES key
    }

    /**
     * Encrypts a message using AES-GCM encryption.
     * @param chatKey The AES key used for encryption.
     * @param plaintext The message to be encrypted.
     * @return Encrypted message as a Base64 string.
     * @throws Exception if encryption fails.
     */
    public static String encryptMessage(SecretKey chatKey, String plaintext) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, chatKey);
        byte[] iv = cipher.getIV();
        byte[] encryptedData = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
    
        byte[] combined = new byte[iv.length + encryptedData.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encryptedData, 0, combined, iv.length, encryptedData.length);
    
        return Base64.encodeToString(combined, Base64.DEFAULT);
    }

    /**
     * Decrypts an AES-GCM encrypted message.
     * @param chatKey The AES key used for decryption.
     * @param encryptedData The Base64 encoded encrypted message.
     * @return Decrypted plaintext message.
     * @throws Exception if decryption fails.
     */
    public static String decryptMessage(SecretKey chatKey, String encryptedData) throws Exception {
        byte[] decodedData = Base64.decode(encryptedData, Base64.DEFAULT);
        byte[] iv = new byte[12]; // GCM IV length is 12 bytes
        System.arraycopy(decodedData, 0, iv, 0, iv.length);
    
        byte[] encryptedBytes = new byte[decodedData.length - iv.length];
        System.arraycopy(decodedData, iv.length, encryptedBytes, 0, encryptedBytes.length);
    
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.DECRYPT_MODE, chatKey, spec);
    
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}

5. In groupchat.xml add a ListView listview1, an EditText edittext1 and a Button send.



6. Create a Custom View groupchat_item.xml and add items as shown in image below. Select it as Custom View of listview1.



7. In GroupchatActivity, add following components:

FirebaseDb component group_chat:groupchat, Calendar component cal, Dialog components dialog and dialog2, SharedPreferences component sp:sp, and FirebaseAuth component fauth.

8. Add following variables:

- String variables message_idmessageencrypted_messagedatepassphraseuid and username.

- Map variable map.

- List Map variable maplist.

9. Add import event and put following imports:

import javax.crypto.SecretKey;

10. Create a more block Declared and put codes to declare masterkey in it:

}
SecretKey masterkey;
{

11. In onCreate, get passphrase from shared preferences and use it to generate masterkey as shown in image below:


The code to generate masterkey is:

try {
masterkey = EncryptionHelper.deriveMasterKey(passphrase);

} catch (Exception e){
showMessage(e.toString());
}

12. Create a more block addUsername(username) fromMap(Map:map) toList (List Map:maplist) and put blocks as shown below.


13. In group_chat onChildAdded event put blocks as shown in image below.

Here the code to get username from uid is

DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("users").child(uid);
 usersRef.addListenerForSingleValueEvent(new ValueEventListener() {

@Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.exists()) {
username= snapshot.child("username").getValue(String.class);

// Put more block to add Username to maplist and refresh ListView.

}
}

@Override
public void onCancelled(DatabaseError error) {
username = uid;

// Put more block to add Username to maplist and refresh ListView.

}

});

14. In send button onClick event, put following blocks:

Here the code to derive Secret key from message_id and encrypt the message is:
try {
SecretKey messageKey = EncryptionHelper.deriveChatKey(masterkey, message_id);

encrypted_message = EncryptionHelper.encryptMessage(messageKey, message);

} catch (Exception e){
showMessage(e.toString());
}


15. In listview1 onBindCustomView, use following blocks to display the message and username.


The code to decrypt message using secret key derived from master key and message ID is following:
try {
SecretKey messageKey = EncryptionHelper.deriveChatKey(masterkey, message_id);
 
message = EncryptionHelper.decryptMessage(messageKey, encrypted_message);

} catch (Exception e){
showMessage(e.toString());
}

Use following blocks to display the date and time.


16. In listview1 itemLongClicked event show a dialog to delete item and delete item from firebase.



17. In group_chat onChildRemoved event put codes as shown in image below:






teg

Sketchware Hub, Sketchware Pro, Sketchware Mod APK, Sketchware Tutorials, Sketchware Projects, Sketchware Source Code, Sketchware Blocks, Sketchware Android App Development, Sketchware AIA Files, Sketchware SWB Projects, Sketchware Coding, Sketchware Tips and Tricks, Sketchware Beginners Guide, Sketchware Advanced Projects, Android App Builder, No Coding App Development, Mobile App Development, SketchwareHub Download, Sketchware Tools, Sketchware Extensions, Sketchware Update, Sketchware Free Projects, Sketchware UI Design, Sketchware Programming, Best Sketchware Projects, Sketchware App Making, Sketchware Hindi Tutorial, Sketchware Nepali Tutorial, App Development Without Coding, Android App Maker, SketchwareHub Project Download, SketchwareHub Latest Version, SketchwareHub Official Website

Post a Comment

0 Comments