将数据发送到Firebase数据库之前如何加密?

时间:2018-10-10 06:12:14

标签: java android firebase encryption firebase-realtime-database

我正在使用Firebase实时数据库制作聊天应用程序。我知道Firebase十分安全(只要您的规则正确),但是我自己可以使用我的应用程序阅读人们的所有聊天记录。

我想停止此操作,为此,我需要一种解密和加密方法。我尝试使用Caesar的解密,但是在此过程中失败了。

String encrypt(String talk, int key){

  for(int i=0;i<talk.length;i++)
  //can't think of how to procceed from here

我想知道是否有一种方法可以在这里实现凯撒的加密,否则,我应该使用哪种其他加密?

3 个答案:

答案 0 :(得分:0)

您可以在客户端上生成一些加密密钥(例如,基于用户的凭据),然后将其安全地存储在客户端(例如,在KeyStore中或根据其他最低SDK版本使用其他方法)。然后使用加密密钥和AES(或任何其他标准)在发送/接收时对消息进行加密/解密。

答案 1 :(得分:0)

在使用此词时,凯撒密码实际上不是“密码”或加密方法。它实际上是25种不同编码的集合。根据定义,编码不是加密的,也不安全。如果您正在寻找用于生产的解决方案,那么Caesar Cipher绝对不是。破坏微不足道,完全不提供安全性。

应该应该做的是清楚地定义自己要保护的威胁模型和攻击媒介。从这里开始,您应该咨询具有实际加密经验的人,以设计出解决所发现问题的方法。

尽管您可能不会这样做,但没人会这样做,因为他们认为他们更了解。如果您决定不这样做,则至少要花一些时间来学习一些基本的密码学概念。

这是我的own repository here中的一些Java代码,展示了一种使用给定密码加密和解密字符串的安全方法:

public class SecureCompatibleEncryptionExamples {

private final static String ALGORITHM_NAME = "AES/GCM/NoPadding";
private final static int ALGORITHM_NONCE_SIZE = 12;
private final static int ALGORITHM_TAG_SIZE = 128;
private final static int ALGORITHM_KEY_SIZE = 128;
private final static String PBKDF2_NAME = "PBKDF2WithHmacSHA256";
private final static int PBKDF2_SALT_SIZE = 16;
private final static int PBKDF2_ITERATIONS = 32767;

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

    // Create an instance of PBKDF2 and derive a key.
    PBEKeySpec pwSpec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE);
    SecretKeyFactory keyFactory = 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 = new byte[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);
}

public static 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 = new byte[PBKDF2_SALT_SIZE];
    byte[] ciphertextAndNonce = new byte[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.
    PBEKeySpec pwSpec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(PBKDF2_NAME);
    byte[] key = keyFactory.generateSecret(pwSpec).getEncoded();

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

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

    // Create the cipher instance and initialize.
    Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(ALGORITHM_TAG_SIZE, nonce));

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

    return ciphertextAndNonce;
}

public static byte[] decrypt(byte[] ciphertextAndNonce, byte[] key) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
    // Retrieve the nonce and ciphertext.
    byte[] nonce = new byte[ALGORITHM_NONCE_SIZE];
    byte[] ciphertext = new byte[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.
    Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(ALGORITHM_TAG_SIZE, nonce));

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

}

答案 2 :(得分:-1)

您可以使用Caesar的加密,但是要在接收方解密消息,还必须将key存储在Firebase中。

但是您可以使用rand()来获取key,并在存储它之前对它进行任何数学运算,这对您来说是不容易理解的,这也是随机的。

这看起来确实很难,但事实并非如此。凯撒的加密和解密代码如下所示:

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

        k = k % 26 + 26;
        StringBuilder encoded = new StringBuilder();
        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 device

       return encryptMessage(m,26-key);
    }