Move cipher logic out of backup and restore components

This commit is contained in:
Steve Soltys 2019-02-21 21:51:46 -05:00
parent b182e743e8
commit 9b979b3693
4 changed files with 68 additions and 21 deletions

View file

@ -0,0 +1,57 @@
package com.stevesoltys.backup.security;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
/**
* A utility class for encrypting and decrypting data using a {@link Cipher}.
*
* @author Steve Soltys
*/
public class CipherUtil {
/**
* The cipher algorithm.
*/
public static final String CIPHER_ALGORITHM = "AES/CFB/PKCS5Padding";
/**
* Encrypts the given payload using a key generated from the provided password and salt.
*
* @param payload The payload.
* @param password The password.
* @param salt The salt.
*/
public static byte[] encrypt(byte[] payload, String password, byte[] salt) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException,
InvalidAlgorithmParameterException, InvalidKeyException {
SecretKey secretKey = KeyGenerator.generate(password, salt);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(salt));
return cipher.doFinal(payload);
}
/**
* Decrypts the given payload using a key generated from the provided password and salt.
*
* @param payload The payload.
* @param password The password.
* @param salt The salt.
*/
public static byte[] decrypt(byte[] payload, String password, byte[] salt) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException,
InvalidAlgorithmParameterException, InvalidKeyException {
SecretKey secretKey = KeyGenerator.generate(password, salt);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(salt));
return cipher.doFinal(payload);
}
}

View file

@ -6,19 +6,15 @@ import android.content.pm.PackageInfo;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import com.stevesoltys.backup.security.KeyGenerator; import com.stevesoltys.backup.security.CipherUtil;
import com.stevesoltys.backup.transport.component.BackupComponent; import com.stevesoltys.backup.transport.component.BackupComponent;
import libcore.io.IoUtils; import libcore.io.IoUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -262,14 +258,12 @@ public class ContentProviderBackupComponent implements BackupComponent {
try { try {
if (configuration.getPassword() != null && !configuration.getPassword().isEmpty()) { if (configuration.getPassword() != null && !configuration.getPassword().isEmpty()) {
SecretKey secretKey = KeyGenerator.generate(configuration.getPassword(), backupState.getSalt());
Cipher cipher = Cipher.getInstance(ContentProviderBackupConstants.CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(backupState.getSalt()));
byte[] payload = Arrays.copyOfRange(buffer, 0, dataSize); byte[] payload = Arrays.copyOfRange(buffer, 0, dataSize);
byte[] encryptedBuffer = cipher.doFinal(payload); String password = configuration.getPassword();
outputStream.write(encryptedBuffer); byte[] salt = backupState.getSalt();
outputStream.write(CipherUtil.encrypt(payload, password, salt));
} else { } else {
outputStream.write(buffer, 0, dataSize); outputStream.write(buffer, 0, dataSize);

View file

@ -3,9 +3,7 @@ package com.stevesoltys.backup.transport.component.provider;
/** /**
* @author Steve Soltys * @author Steve Soltys
*/ */
public class ContentProviderBackupConstants { class ContentProviderBackupConstants {
static final String CIPHER_ALGORITHM = "AES/CFB/PKCS5Padding";
static final String SALT_FILE_PATH = "salt"; static final String SALT_FILE_PATH = "salt";
} }

View file

@ -9,6 +9,7 @@ import android.os.ParcelFileDescriptor;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import com.stevesoltys.backup.security.CipherUtil;
import com.stevesoltys.backup.security.KeyGenerator; import com.stevesoltys.backup.security.KeyGenerator;
import com.stevesoltys.backup.transport.component.RestoreComponent; import com.stevesoltys.backup.transport.component.RestoreComponent;
import libcore.io.IoUtils; import libcore.io.IoUtils;
@ -179,14 +180,11 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
private byte[] readBackupData(ZipInputStream inputStream) throws Exception { private byte[] readBackupData(ZipInputStream inputStream) throws Exception {
byte[] backupData = Streams.readFullyNoClose(inputStream); byte[] backupData = Streams.readFullyNoClose(inputStream);
if (configuration.getPassword() != null && !configuration.getPassword().isEmpty() && String password = configuration.getPassword();
restoreState.getSalt() != null) { byte[] salt = restoreState.getSalt();
SecretKey secretKey = KeyGenerator.generate(configuration.getPassword(), restoreState.getSalt()); if (password != null && !password.isEmpty() && salt != null) {
backupData = CipherUtil.decrypt(backupData, password, salt);
Cipher cipher = Cipher.getInstance(ContentProviderBackupConstants.CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(restoreState.getSalt()));
backupData = cipher.doFinal(backupData);
} }
return backupData; return backupData;