Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac15253e authored by Joël Stemmer's avatar Joël Stemmer
Browse files

Update language to comply with Android's inclusive language guidance

See https://source.android.com/setup/contribute/respectful-code for reference

PerformAdb{Backup,Restore}Task handles backing up to and restoring from
a file. The backup data is encrypted with a randomly generated
encryption key. The encryption key is encrypted with a key that is
derived from a user supplied passphrase.

The key that was used to encrypt and decrypt the backup data used to be
called the "master key", I've renamed it to "encryption key" which
better describes its purpose.

Bug: 161896447
Test: `atest PerformAdbRestoreTaskTest`, `atest TarBackupReaderTest`
 and manually tested using adb with the following commands:
 `adb backup -all -apk -shared -f backup.ab` and
 `adb restore backup.ab`.
Change-Id: I8e6b22a06b2a583440839994f0626d370bdb2e19
parent 84e70df9
Loading
Loading
Loading
Loading
+22 −24
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEA
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;

import android.app.backup.BackupManager;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -143,7 +141,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor

    private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
            OutputStream ofstream) throws Exception {
        // User key will be used to encrypt the master key.
        // User key will be used to encrypt the encryption key.
        byte[] newUserSalt = mUserBackupManagerService
                .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
        SecretKey userKey = PasswordUtils
@@ -151,16 +149,16 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
                        newUserSalt,
                        PasswordUtils.PBKDF2_HASH_ROUNDS);

        // the master key is random for each backup
        byte[] masterPw = new byte[256 / 8];
        mUserBackupManagerService.getRng().nextBytes(masterPw);
        // the encryption key is random for each backup
        byte[] encryptionKey = new byte[256 / 8];
        mUserBackupManagerService.getRng().nextBytes(encryptionKey);
        byte[] checksumSalt = mUserBackupManagerService
                .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);

        // primary encryption of the datastream with the random key
        // primary encryption of the datastream with the encryption key
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
        c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
        SecretKeySpec encryptionKeySpec = new SecretKeySpec(encryptionKey, "AES");
        c.init(Cipher.ENCRYPT_MODE, encryptionKeySpec);
        OutputStream finalOutput = new CipherOutputStream(ofstream, c);

        // line 4: name of encryption algorithm
@@ -169,7 +167,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
        // line 5: user password salt [hex]
        headerbuf.append(PasswordUtils.byteArrayToHex(newUserSalt));
        headerbuf.append('\n');
        // line 6: master key checksum salt [hex]
        // line 6: encryption key checksum salt [hex]
        headerbuf.append(PasswordUtils.byteArrayToHex(checksumSalt));
        headerbuf.append('\n');
        // line 7: number of PBKDF2 rounds used [decimal]
@@ -184,21 +182,21 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
        headerbuf.append(PasswordUtils.byteArrayToHex(IV));
        headerbuf.append('\n');

        // line 9: master IV + key blob, encrypted by the user key [hex].  Blob format:
        // line 9: encryption IV + key blob, encrypted by the user key [hex].  Blob format:
        //    [byte] IV length = Niv
        //    [array of Niv bytes] IV itself
        //    [byte] master key length = Nmk
        //    [array of Nmk bytes] master key itself
        //    [byte] MK checksum hash length = Nck
        //    [array of Nck bytes] master key checksum hash
        //    [byte] encryption key length = Nek
        //    [array of Nek bytes] encryption key itself
        //    [byte] encryption key checksum hash length = Nck
        //    [array of Nck bytes] encryption key checksum hash
        //
        // The checksum is the (master key + checksum salt), run through the
        // The checksum is the (encryption key + checksum salt), run through the
        // stated number of PBKDF2 rounds
        IV = c.getIV();
        byte[] mk = masterKeySpec.getEncoded();
        byte[] mk = encryptionKeySpec.getEncoded();
        byte[] checksum = PasswordUtils
                .makeKeyChecksum(PBKDF_CURRENT,
                        masterKeySpec.getEncoded(),
                        encryptionKeySpec.getEncoded(),
                        checksumSalt, PasswordUtils.PBKDF2_HASH_ROUNDS);

        ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
@@ -347,15 +345,15 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
            // When line 4 is not "none", then additional header data follows:
            //
            // line 5: user password salt [hex]
            // line 6: master key checksum salt [hex]
            // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
            // line 6: encryption key checksum salt [hex]
            // line 7: number of PBKDF2 rounds to use (same for user & encryption key) [decimal]
            // line 8: IV of the user key [hex]
            // line 9: master key blob [hex]
            //     IV of the master key, master key itself, master key checksum hash
            // line 9: encryption key blob [hex]
            //     IV of the encryption key, encryption key itself, encryption key checksum hash
            //
            // The master key checksum is the master key plus its checksum salt, run through
            // The encryption key checksum is the encryption key plus its checksum salt, run through
            // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the
            // correct password for decrypting the archive:  the master key decrypted from
            // correct password for decrypting the archive:  the encryption key decrypted from
            // the archive using the user-supplied password is also run through PBKDF2 in
            // this way, and if the result does not match the checksum as stored in the
            // archive, then we know that the user-supplied password does not match the
+19 −20
Original line number Diff line number Diff line
@@ -212,10 +212,9 @@ public class PerformAdbRestoreTask implements Runnable {
        return buffer.toString();
    }

    private static InputStream attemptMasterKeyDecryption(String decryptPassword, String algorithm,
            byte[] userSalt, byte[] ckSalt,
            int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
            boolean doLog) {
    private static InputStream attemptEncryptionKeyDecryption(String decryptPassword,
            String algorithm, byte[] userSalt, byte[] ckSalt, int rounds, String userIvHex,
            String encryptionKeyBlobHex, InputStream rawInStream, boolean doLog) {
        InputStream result = null;

        try {
@@ -228,31 +227,31 @@ public class PerformAdbRestoreTask implements Runnable {
            c.init(Cipher.DECRYPT_MODE,
                    new SecretKeySpec(userKey.getEncoded(), "AES"),
                    ivSpec);
            byte[] mkCipher = PasswordUtils.hexToByteArray(masterKeyBlobHex);
            byte[] mkCipher = PasswordUtils.hexToByteArray(encryptionKeyBlobHex);
            byte[] mkBlob = c.doFinal(mkCipher);

            // first, the master key IV
            // first, the encryption key IV
            int offset = 0;
            int len = mkBlob[offset++];
            IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
            offset += len;
            // then the master key itself
            // then the encryption key itself
            len = mkBlob[offset++];
            byte[] mk = Arrays.copyOfRange(mkBlob,
            byte[] encryptionKey = Arrays.copyOfRange(mkBlob,
                    offset, offset + len);
            offset += len;
            // and finally the master key checksum hash
            // and finally the encryption key checksum hash
            len = mkBlob[offset++];
            byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
                    offset, offset + len);

            // now validate the decrypted master key against the checksum
            byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, mk, ckSalt,
            // now validate the decrypted encryption key against the checksum
            byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, encryptionKey, ckSalt,
                    rounds);
            if (Arrays.equals(calculatedCk, mkChecksum)) {
                ivSpec = new IvParameterSpec(IV);
                c.init(Cipher.DECRYPT_MODE,
                        new SecretKeySpec(mk, "AES"),
                        new SecretKeySpec(encryptionKey, "AES"),
                        ivSpec);
                // Only if all of the above worked properly will 'result' be assigned
                result = new CipherInputStream(rawInStream, c);
@@ -265,7 +264,7 @@ public class PerformAdbRestoreTask implements Runnable {
            }
        } catch (BadPaddingException e) {
            // This case frequently occurs when the wrong password is used to decrypt
            // the master key.  Use the identical "incorrect password" log text as is
            // the encryption key.  Use the identical "incorrect password" log text as is
            // used in the checksum failure log in order to avoid providing additional
            // information to an attacker.
            if (doLog) {
@@ -273,7 +272,7 @@ public class PerformAdbRestoreTask implements Runnable {
            }
        } catch (IllegalBlockSizeException e) {
            if (doLog) {
                Slog.w(TAG, "Invalid block size in master key");
                Slog.w(TAG, "Invalid block size in encryption key");
            }
        } catch (NoSuchAlgorithmException e) {
            if (doLog) {
@@ -309,15 +308,15 @@ public class PerformAdbRestoreTask implements Runnable {
                int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
                String userIvHex = readHeaderLine(rawInStream); // 8

                String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
                String encryptionKeyBlobHex = readHeaderLine(rawInStream); // 9

                // decrypt the master key blob
                result = attemptMasterKeyDecryption(decryptPassword, PBKDF_CURRENT,
                        userSalt, ckSalt, rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
                // decrypt the encryption key blob
                result = attemptEncryptionKeyDecryption(decryptPassword, PBKDF_CURRENT, userSalt,
                        ckSalt, rounds, userIvHex, encryptionKeyBlobHex, rawInStream, false);
                if (result == null && pbkdf2Fallback) {
                    result = attemptMasterKeyDecryption(
                    result = attemptEncryptionKeyDecryption(
                            decryptPassword, PBKDF_FALLBACK, userSalt, ckSalt,
                            rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
                            rounds, userIvHex, encryptionKeyBlobHex, rawInStream, true);
                }
            } else {
                Slog.w(TAG, "Unsupported encryption method: " + encryptionName);