Loading services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +22 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 Loading @@ -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] Loading @@ -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 Loading Loading @@ -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 Loading services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +19 −20 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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); Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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); Loading Loading
services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +22 −24 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 Loading @@ -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] Loading @@ -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 Loading Loading @@ -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 Loading
services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +19 −20 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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); Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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); Loading