Skip to content Skip to sidebar Skip to footer

How To Encrypt Data Before Sending It To Firebase Database?

I am making a chat application using Firebase realtime database. I know that Firebase is very secure(provided your rules are correct), but I myself can read all the chats of the pe

Solution 1:

The Caesar Cipher is not actually a "cipher" nor encryption in any use of the word. It is actually a set of 25 different encodings. An encoding, by definition, is not encryption and is not secure. If you're searching for a solution to use in production, the Caesar Cipher is definitely not it. It is trivial to break and provides no security at all.

What you should do is clearly define the threat model and attack vectors that you are protecting yourself from. From here, you should consult with someone who has actual cryptography experience to design a solution to the problems you've found.

You probably won't do that though, no one ever does, they think they know better. In the case that you decide to not do that, at the very least, take the time to learn some basic cryptography concepts.

Here is some Java code, from my own repository here, that demonstrates a secure method of encrypting and decrypting strings with a given password:

publicclassSecureCompatibleEncryptionExamples {

privatefinalstaticStringALGORITHM_NAME="AES/GCM/NoPadding";
privatefinalstaticintALGORITHM_NONCE_SIZE=12;
privatefinalstaticintALGORITHM_TAG_SIZE=128;
privatefinalstaticintALGORITHM_KEY_SIZE=128;
privatefinalstaticStringPBKDF2_NAME="PBKDF2WithHmacSHA256";
privatefinalstaticintPBKDF2_SALT_SIZE=16;
privatefinalstaticintPBKDF2_ITERATIONS=32767;

publicstatic String encryptString(String plaintext, String password)throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
    // Generate a 128-bit salt using a CSPRNG.SecureRandomrand=newSecureRandom();
    byte[] salt = newbyte[PBKDF2_SALT_SIZE];
    rand.nextBytes(salt);

    // Create an instance of PBKDF2 and derive a key.PBEKeySpecpwSpec=newPBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE);
    SecretKeyFactorykeyFactory= SecretKeyFactory.getInstance(PBKDF2_NAME);
    byte[] key = keyFactory.generateSecret(pwSpec).getEncoded();

    // Encrypt and prepend salt.byte[] ciphertextAndNonce = encrypt(plaintext.getBytes(StandardCharsets.UTF_8), key);
    byte[] ciphertextAndNonceAndSalt = newbyte[salt.length + ciphertextAndNonce.length];
    System.arraycopy(salt, 0, ciphertextAndNonceAndSalt, 0, salt.length);
    System.arraycopy(ciphertextAndNonce, 0, ciphertextAndNonceAndSalt, salt.length, ciphertextAndNonce.length);

    // Return as base64 string.return Base64.getEncoder().encodeToString(ciphertextAndNonceAndSalt);
}

publicstatic String decryptString(String base64CiphertextAndNonceAndSalt, String password)throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException {
    // Decode the base64.byte[] ciphertextAndNonceAndSalt = Base64.getDecoder().decode(base64CiphertextAndNonceAndSalt);

    // Retrieve the salt and ciphertextAndNonce.byte[] salt = newbyte[PBKDF2_SALT_SIZE];
    byte[] ciphertextAndNonce = newbyte[ciphertextAndNonceAndSalt.length - PBKDF2_SALT_SIZE];
    System.arraycopy(ciphertextAndNonceAndSalt, 0, salt, 0, salt.length);
    System.arraycopy(ciphertextAndNonceAndSalt, salt.length, ciphertextAndNonce, 0, ciphertextAndNonce.length);

    // Create an instance of PBKDF2 and derive the key.PBEKeySpecpwSpec=newPBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE);
    SecretKeyFactorykeyFactory= SecretKeyFactory.getInstance(PBKDF2_NAME);
    byte[] key = keyFactory.generateSecret(pwSpec).getEncoded();

    // Decrypt and return result.returnnewString(decrypt(ciphertextAndNonce, key), StandardCharsets.UTF_8);
}

publicstaticbyte[] encrypt(byte[] plaintext, byte[] key) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
    // Generate a 96-bit nonce using a CSPRNG.SecureRandomrand=newSecureRandom();
    byte[] nonce = newbyte[ALGORITHM_NONCE_SIZE];
    rand.nextBytes(nonce);

    // Create the cipher instance and initialize.Ciphercipher= Cipher.getInstance(ALGORITHM_NAME);
    cipher.init(Cipher.ENCRYPT_MODE, newSecretKeySpec(key, "AES"), newGCMParameterSpec(ALGORITHM_TAG_SIZE, nonce));

    // Encrypt and prepend nonce.byte[] ciphertext = cipher.doFinal(plaintext);
    byte[] ciphertextAndNonce = newbyte[nonce.length + ciphertext.length];
    System.arraycopy(nonce, 0, ciphertextAndNonce, 0, nonce.length);
    System.arraycopy(ciphertext, 0, ciphertextAndNonce, nonce.length, ciphertext.length);

    return ciphertextAndNonce;
}

publicstaticbyte[] decrypt(byte[] ciphertextAndNonce, byte[] key) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
    // Retrieve the nonce and ciphertext.byte[] nonce = newbyte[ALGORITHM_NONCE_SIZE];
    byte[] ciphertext = newbyte[ciphertextAndNonce.length - ALGORITHM_NONCE_SIZE];
    System.arraycopy(ciphertextAndNonce, 0, nonce, 0, nonce.length);
    System.arraycopy(ciphertextAndNonce, nonce.length, ciphertext, 0, ciphertext.length);

    // Create the cipher instance and initialize.Ciphercipher= Cipher.getInstance(ALGORITHM_NAME);
    cipher.init(Cipher.DECRYPT_MODE, newSecretKeySpec(key, "AES"), newGCMParameterSpec(ALGORITHM_TAG_SIZE, nonce));

    // Decrypt and return result.return cipher.doFinal(ciphertext);
}

}

Solution 2:

You can generate some encryption key on the client, for example based on user's credentials, and store it there securely (i.e. in the KeyStore or using other approaches depending on what is your min SDK version). Then using the encryption key and AES (or any other standard) encrypt/decrypt messages on send/receive.

Solution 3:

You can use Caesar's encryption but to decrypt the message on the receiver's side you've to also store the key in Firebase.

But you can make it not understandable to yourself, using rand() for getting key and before storing it, do any mathematical operation on it, that's also random.

This does look hard, but it is not. The code of Caesar's encryption and decryption looks something like this:

private String encryptMessage(String talk, int k){
        // make the string encrypted before sending to the database

        k = k % 26 + 26;
        StringBuilderencoded=newStringBuilder();
        for (char i : talk.toCharArray()) {
            if (Character.isLetter(i)) {
                if (Character.isUpperCase(i)) {
                    encoded.append((char) ('A' + (i - 'A' + k) % 26 ));
                }
                else {
                    encoded.append((char) ('a' + (i - 'a' + k) % 26 ));
                }
            }
            else {
                encoded.append(i);
            }
        }
        return encoded.toString();
    }

    private String decryptMessage(String m, int key){
       // make string readable on the receiver's devicereturn encryptMessage(m,26-key);
    }

Post a Comment for "How To Encrypt Data Before Sending It To Firebase Database?"