OBB: use PBKDF2 for key generation.
Switch to using PBKDF2 for the key generation for OBBs. Any previously
generated OBBs will stop being read correctly. A small pbkdf2gen program
is available to allow generation of appropriate keys with the salts.
Bug: 3059950
Change-Id: If4305c989fd692fd1150eb270dbf751e09c37295
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 775f5c8..8cf8f6a 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -17,7 +17,6 @@
package com.android.server;
import com.android.internal.app.IMediaContainerService;
-import com.android.internal.util.HexDump;
import com.android.server.am.ActivityManagerService;
import android.content.BroadcastReceiver;
@@ -46,13 +45,15 @@
import android.os.storage.IObbActionListener;
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageResultCode;
-import android.security.MessageDigest;
import android.util.Slog;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -62,6 +63,10 @@
import java.util.Map;
import java.util.Map.Entry;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
/**
* MountService implements back-end services for platform storage
* management.
@@ -154,6 +159,18 @@
final private HashSet<String> mAsecMountSet = new HashSet<String>();
/**
+ * The size of the crypto algorithm key in bits for OBB files. Currently
+ * Twofish is used which takes 128-bit keys.
+ */
+ private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
+
+ /**
+ * The number of times to run SHA1 in the PBKDF2 function for OBB files.
+ * 1024 is reasonably secure and not too slow.
+ */
+ private static final int PBKDF2_HASH_ROUNDS = 1024;
+
+ /**
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
*/
@@ -1901,16 +1918,23 @@
if (mKey == null) {
hashedKey = "none";
} else {
- final MessageDigest md;
try {
- md = MessageDigest.getInstance("MD5");
+ SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+
+ KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
+ PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
+ SecretKey key = factory.generateSecret(ks);
+ BigInteger bi = new BigInteger(key.getEncoded());
+ hashedKey = bi.toString(16);
} catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Could not load MD5 algorithm", e);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
+ sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
+ return;
+ } catch (InvalidKeySpecException e) {
+ Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
+ sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
return;
}
-
- hashedKey = HexDump.toHexString(md.digest(mKey.getBytes()));
}
int rc = StorageResultCode.OperationSucceeded;