diff options
author | Kenny Root <kroot@google.com> | 2010-10-15 14:00:58 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-10-15 14:00:58 -0700 |
commit | fcab0f5502410b975afe045354bbae31ccba68a5 (patch) | |
tree | 184b37e57a998580c15fdaa98d7d8bf0c9155a90 | |
parent | 10aca41e51934822dc492cb69b69cef37f42ad42 (diff) | |
parent | 8fda1636e3e35f060b9046294efd3c062a1fdb84 (diff) | |
download | frameworks_base-fcab0f5502410b975afe045354bbae31ccba68a5.zip frameworks_base-fcab0f5502410b975afe045354bbae31ccba68a5.tar.gz frameworks_base-fcab0f5502410b975afe045354bbae31ccba68a5.tar.bz2 |
am 8fda1636: am bdf8034c: Merge "OBB: use PBKDF2 for key generation." into gingerbread
Merge commit '8fda1636e3e35f060b9046294efd3c062a1fdb84'
* commit '8fda1636e3e35f060b9046294efd3c062a1fdb84':
OBB: use PBKDF2 for key generation.
-rw-r--r-- | core/java/android/content/res/ObbInfo.java | 9 | ||||
-rw-r--r-- | core/jni/android_content_res_ObbScanner.cpp | 11 | ||||
-rw-r--r-- | core/tests/coretests/res/raw/test1.obb | bin | 37432 -> 37440 bytes | |||
-rw-r--r-- | core/tests/coretests/res/raw/test1_wrongpackage.obb | bin | 37423 -> 37431 bytes | |||
-rw-r--r-- | include/utils/ObbFile.h | 27 | ||||
-rw-r--r-- | libs/utils/ObbFile.cpp | 44 | ||||
-rw-r--r-- | libs/utils/tests/ObbFile_test.cpp | 18 | ||||
-rw-r--r-- | services/java/com/android/server/MountService.java | 40 | ||||
-rw-r--r-- | tools/obbtool/Android.mk | 16 | ||||
-rw-r--r-- | tools/obbtool/Main.cpp | 91 | ||||
-rwxr-xr-x | tools/obbtool/mkobb.sh | 18 | ||||
-rw-r--r-- | tools/obbtool/pbkdf2gen.cpp | 78 |
12 files changed, 316 insertions, 36 deletions
diff --git a/core/java/android/content/res/ObbInfo.java b/core/java/android/content/res/ObbInfo.java index 5d6ed44..b653f9f 100644 --- a/core/java/android/content/res/ObbInfo.java +++ b/core/java/android/content/res/ObbInfo.java @@ -48,6 +48,13 @@ public class ObbInfo implements Parcelable { */ public int flags; + /** + * The salt for the encryption algorithm. + * + * @hide + */ + public byte[] salt; + // Only allow things in this package to instantiate. /* package */ ObbInfo() { } @@ -75,6 +82,7 @@ public class ObbInfo implements Parcelable { dest.writeString(packageName); dest.writeInt(version); dest.writeInt(flags); + dest.writeByteArray(salt); } public static final Parcelable.Creator<ObbInfo> CREATOR @@ -93,5 +101,6 @@ public class ObbInfo implements Parcelable { packageName = source.readString(); version = source.readInt(); flags = source.readInt(); + salt = source.createByteArray(); } } diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp index 2a9eacf..3fd7985 100644 --- a/core/jni/android_content_res_ObbScanner.cpp +++ b/core/jni/android_content_res_ObbScanner.cpp @@ -32,6 +32,7 @@ static struct { jfieldID packageName; jfieldID version; jfieldID flags; + jfieldID salt; } gObbInfoClassInfo; static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) @@ -69,6 +70,14 @@ static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz env->SetObjectField(obbInfo, gObbInfoClassInfo.packageName, packageName); env->SetIntField(obbInfo, gObbInfoClassInfo.version, obb->getVersion()); env->SetIntField(obbInfo, gObbInfoClassInfo.flags, obb->getFlags()); + + size_t saltLen; + const unsigned char* salt = obb->getSalt(&saltLen); + if (saltLen > 0) { + jbyteArray saltArray = env->NewByteArray(saltLen); + env->SetByteArrayRegion(saltArray, 0, saltLen, (jbyte*)salt); + env->SetObjectField(obbInfo, gObbInfoClassInfo.salt, saltArray); + } } /* @@ -99,6 +108,8 @@ int register_android_content_res_ObbScanner(JNIEnv* env) "version", "I"); GET_FIELD_ID(gObbInfoClassInfo.flags, gObbInfoClassInfo.clazz, "flags", "I"); + GET_FIELD_ID(gObbInfoClassInfo.salt, gObbInfoClassInfo.clazz, + "salt", "[B"); return AndroidRuntime::registerNativeMethods(env, "android/content/res/ObbScanner", gMethods, NELEM(gMethods)); diff --git a/core/tests/coretests/res/raw/test1.obb b/core/tests/coretests/res/raw/test1.obb Binary files differindex 170e36f..8466588 100644 --- a/core/tests/coretests/res/raw/test1.obb +++ b/core/tests/coretests/res/raw/test1.obb diff --git a/core/tests/coretests/res/raw/test1_wrongpackage.obb b/core/tests/coretests/res/raw/test1_wrongpackage.obb Binary files differindex 2e02eaa..d0aafe1 100644 --- a/core/tests/coretests/res/raw/test1_wrongpackage.obb +++ b/core/tests/coretests/res/raw/test1_wrongpackage.obb diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h index 5243f50..47559cd 100644 --- a/include/utils/ObbFile.h +++ b/include/utils/ObbFile.h @@ -27,6 +27,7 @@ namespace android { // OBB flags (bit 0) #define OBB_OVERLAY (1 << 0) +#define OBB_SALTED (1 << 1) class ObbFile : public RefBase { protected: @@ -70,6 +71,26 @@ public: mFlags = flags; } + const unsigned char* getSalt(size_t* length) const { + if ((mFlags & OBB_SALTED) == 0) { + *length = 0; + return NULL; + } + + *length = sizeof(mSalt); + return mSalt; + } + + bool setSalt(const unsigned char* salt, size_t length) { + if (length != sizeof(mSalt)) { + return false; + } + + memcpy(mSalt, salt, sizeof(mSalt)); + mFlags |= OBB_SALTED; + return true; + } + bool isOverlay() { return (mFlags & OBB_OVERLAY) == OBB_OVERLAY; } @@ -103,6 +124,12 @@ private: /* Flags for this OBB type. */ int32_t mFlags; + /* Whether the file is salted. */ + bool mSalted; + + /* The encryption salt. */ + unsigned char mSalt[8]; + const char* mFileName; size_t mFileSize; diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp index e170ab8..2c3724c 100644 --- a/libs/utils/ObbFile.cpp +++ b/libs/utils/ObbFile.cpp @@ -29,10 +29,11 @@ #define kFooterTagSize 8 /* last two 32-bit integers */ -#define kFooterMinSize 25 /* 32-bit signature version (4 bytes) +#define kFooterMinSize 33 /* 32-bit signature version (4 bytes) * 32-bit package version (4 bytes) * 32-bit flags (4 bytes) - * 32-bit package name size (4-bytes) + * 64-bit salt (8 bytes) + * 32-bit package name size (4 bytes) * >=1-character package name (1 byte) * 32-bit footer size (4 bytes) * 32-bit footer marker (4 bytes) @@ -47,8 +48,9 @@ /* offsets in version 1 of the header */ #define kPackageVersionOffset 4 #define kFlagsOffset 8 -#define kPackageNameLenOffset 12 -#define kPackageNameOffset 16 +#define kSaltOffset 12 +#define kPackageNameLenOffset 20 +#define kPackageNameOffset 24 /* * TEMP_FAILURE_RETRY is defined by some, but not all, versions of @@ -79,11 +81,12 @@ typedef off64_t my_off64_t; namespace android { -ObbFile::ObbFile() : - mPackageName(""), - mVersion(-1), - mFlags(0) +ObbFile::ObbFile() + : mPackageName("") + , mVersion(-1) + , mFlags(0) { + memset(mSalt, 0, sizeof(mSalt)); } ObbFile::~ObbFile() { @@ -192,7 +195,7 @@ bool ObbFile::parseObbFile(int fd) #ifdef DEBUG for (int i = 0; i < footerSize; ++i) { - LOGI("char: 0x%02x", scanBuf[i]); + LOGI("char: 0x%02x\n", scanBuf[i]); } #endif @@ -206,6 +209,8 @@ bool ObbFile::parseObbFile(int fd) mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset); mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset); + memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt)); + uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset); if (packageNameLen <= 0 || packageNameLen > (footerSize - kPackageNameOffset)) { @@ -255,7 +260,7 @@ bool ObbFile::writeTo(int fd) my_lseek64(fd, 0, SEEK_END); if (mPackageName.size() == 0 || mVersion == -1) { - LOGW("tried to write uninitialized ObbFile data"); + LOGW("tried to write uninitialized ObbFile data\n"); return false; } @@ -264,43 +269,48 @@ bool ObbFile::writeTo(int fd) put4LE(intBuf, kSigVersion); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - LOGW("couldn't write signature version: %s", strerror(errno)); + LOGW("couldn't write signature version: %s\n", strerror(errno)); return false; } put4LE(intBuf, mVersion); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - LOGW("couldn't write package version"); + LOGW("couldn't write package version\n"); return false; } put4LE(intBuf, mFlags); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - LOGW("couldn't write package version"); + LOGW("couldn't write package version\n"); + return false; + } + + if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) { + LOGW("couldn't write salt: %s\n", strerror(errno)); return false; } size_t packageNameLen = mPackageName.size(); put4LE(intBuf, packageNameLen); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - LOGW("couldn't write package name length: %s", strerror(errno)); + LOGW("couldn't write package name length: %s\n", strerror(errno)); return false; } if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) { - LOGW("couldn't write package name: %s", strerror(errno)); + LOGW("couldn't write package name: %s\n", strerror(errno)); return false; } put4LE(intBuf, kPackageNameOffset + packageNameLen); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - LOGW("couldn't write footer size: %s", strerror(errno)); + LOGW("couldn't write footer size: %s\n", strerror(errno)); return false; } put4LE(intBuf, kSignature); if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - LOGW("couldn't write footer magic signature: %s", strerror(errno)); + LOGW("couldn't write footer magic signature: %s\n", strerror(errno)); return false; } diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp index 29bb70a..46b30c2 100644 --- a/libs/utils/tests/ObbFile_test.cpp +++ b/libs/utils/tests/ObbFile_test.cpp @@ -23,6 +23,7 @@ #include <gtest/gtest.h> #include <fcntl.h> +#include <string.h> namespace android { @@ -63,6 +64,10 @@ TEST_F(ObbFileTest, WriteThenRead) { mObbFile->setPackageName(String8(packageName)); mObbFile->setVersion(versionNum); +#define SALT_SIZE 8 + unsigned char salt[SALT_SIZE] = {0x01, 0x10, 0x55, 0xAA, 0xFF, 0x00, 0x5A, 0xA5}; + EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE)) + << "Salt should be successfully set"; EXPECT_TRUE(mObbFile->writeTo(mFileName)) << "couldn't write to fake .obb file"; @@ -77,6 +82,19 @@ TEST_F(ObbFileTest, WriteThenRead) { const char* currentPackageName = mObbFile->getPackageName().string(); EXPECT_STREQ(packageName, currentPackageName) << "package name didn't come out the same as it went in"; + + size_t saltLen; + const unsigned char* newSalt = mObbFile->getSalt(&saltLen); + + EXPECT_EQ(sizeof(salt), saltLen) + << "salt sizes were not the same"; + + for (int i = 0; i < sizeof(salt); i++) { + EXPECT_EQ(salt[i], newSalt[i]) + << "salt character " << i << " should be equal"; + } + EXPECT_TRUE(memcmp(newSalt, salt, sizeof(salt)) == 0) + << "salts should be the same"; } } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index f8611e4..62dec7e 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.IMountShutdownObserver; 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.List; 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. @@ -156,6 +161,18 @@ class MountService extends IMountService.Stub 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. */ @@ -1916,16 +1933,23 @@ class MountService extends IMountService.Stub 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; diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk index b02c1cb..9300bb7 100644 --- a/tools/obbtool/Android.mk +++ b/tools/obbtool/Android.mk @@ -13,6 +13,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ Main.cpp +LOCAL_CFLAGS := -Wall -Werror + #LOCAL_C_INCLUDES += LOCAL_STATIC_LIBRARIES := \ @@ -27,4 +29,18 @@ LOCAL_MODULE := obbtool include $(BUILD_HOST_EXECUTABLE) +include $(CLEAR_VARS) + +LOCAL_MODULE := pbkdf2gen + +LOCAL_MODULE_TAGS := optional + +LOCAL_CFLAGS := -Wall -Werror + +LOCAL_SRC_FILES := pbkdf2gen.cpp + +LOCAL_SHARED_LIBRARIES := libcrypto + +include $(BUILD_HOST_EXECUTABLE) + endif # TARGET_BUILD_APPS diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp index 49e077f..932dbec 100644 --- a/tools/obbtool/Main.cpp +++ b/tools/obbtool/Main.cpp @@ -20,6 +20,7 @@ #include <getopt.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> using namespace android; @@ -29,7 +30,9 @@ static const char* gProgVersion = "1.0"; static int wantUsage = 0; static int wantVersion = 0; -#define ADD_OPTS "n:v:o" +#define SALT_LEN 8 + +#define ADD_OPTS "n:v:os:" static const struct option longopts[] = { {"help", no_argument, &wantUsage, 1}, {"version", no_argument, &wantVersion, 1}, @@ -38,14 +41,27 @@ static const struct option longopts[] = { {"name", required_argument, NULL, 'n'}, {"version", required_argument, NULL, 'v'}, {"overlay", optional_argument, NULL, 'o'}, + {"salt", required_argument, NULL, 's'}, {NULL, 0, NULL, '\0'} }; -struct package_info_t { +class PackageInfo { +public: + PackageInfo() + : packageName(NULL) + , packageVersion(-1) + , overlay(false) + , salted(false) + { + memset(&salt, 0, sizeof(salt)); + } + char* packageName; int packageVersion; bool overlay; + bool salted; + unsigned char salt[SALT_LEN]; }; /* @@ -59,6 +75,13 @@ void usage(void) " %s a[dd] [ OPTIONS ] FILENAME\n" " Adds an OBB signature to the file.\n\n", gProgName); fprintf(stderr, + " Options:\n" + " -n <package name> sets the OBB package name (required)\n" + " -v <OBB version> sets the OBB version (required)\n" + " -o sets the OBB overlay flag\n" + " -s <8 byte hex salt> sets the crypto key salt (if encrypted)\n" + "\n"); + fprintf(stderr, " %s r[emove] FILENAME\n" " Removes the OBB signature from the file.\n\n", gProgName); fprintf(stderr, @@ -66,7 +89,7 @@ void usage(void) " Prints the OBB signature information of a file.\n\n", gProgName); } -void doAdd(const char* filename, struct package_info_t* info) { +void doAdd(const char* filename, struct PackageInfo* info) { ObbFile *obb = new ObbFile(); if (obb->readFrom(filename)) { fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename); @@ -76,6 +99,9 @@ void doAdd(const char* filename, struct package_info_t* info) { obb->setPackageName(String8(info->packageName)); obb->setVersion(info->packageVersion); obb->setOverlay(info->overlay); + if (info->salted) { + obb->setSalt(info->salt, SALT_LEN); + } if (!obb->writeTo(filename)) { fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n", @@ -113,6 +139,40 @@ void doInfo(const char* filename) { printf(" Version: %d\n", obb->getVersion()); printf(" Flags: 0x%08x\n", obb->getFlags()); printf(" Overlay: %s\n", obb->isOverlay() ? "true" : "false"); + printf(" Salt: "); + + size_t saltLen; + const unsigned char* salt = obb->getSalt(&saltLen); + if (salt != NULL) { + for (int i = 0; i < SALT_LEN; i++) { + printf("%02x", salt[i]); + } + printf("\n"); + } else { + printf("<empty>\n"); + } +} + +bool fromHex(char h, unsigned char *b) { + if (h >= '0' && h <= '9') { + *b = h - '0'; + return true; + } else if (h >= 'a' && h <= 'f') { + *b = h - 'a' + 10; + return true; + } else if (h >= 'A' && h <= 'F') { + *b = h - 'A' + 10; + return true; + } + return false; +} + +bool hexToByte(char h1, char h2, unsigned char* b) { + unsigned char first, second; + if (!fromHex(h1, &first)) return false; + if (!fromHex(h2, &second)) return false; + *b = (first << 4) | second; + return true; } /* @@ -120,11 +180,9 @@ void doInfo(const char* filename) { */ int main(int argc, char* const argv[]) { - const char *prog = argv[0]; - struct options *options; int opt; int option_index = 0; - struct package_info_t package_info; + struct PackageInfo package_info; int result = 1; // pessimistically assume an error. @@ -145,7 +203,7 @@ int main(int argc, char* const argv[]) package_info.packageName = optarg; break; case 'v': { - char *end; + char* end; package_info.packageVersion = strtol(optarg, &end, 10); if (*optarg == '\0' || *end != '\0') { fprintf(stderr, "ERROR: invalid version; should be integer!\n\n"); @@ -157,6 +215,25 @@ int main(int argc, char* const argv[]) case 'o': package_info.overlay = true; break; + case 's': + if (strlen(optarg) != SALT_LEN * 2) { + fprintf(stderr, "ERROR: salt must be 8 bytes in hex (e.g., ABCD65031337D00D)\n\n"); + wantUsage = 1; + goto bail; + } + + package_info.salted = true; + + unsigned char b; + for (int i = 0, j = 0; i < SALT_LEN; i++, j+=2) { + if (!hexToByte(optarg[j], optarg[j+1], &b)) { + fprintf(stderr, "ERROR: salt must be in hex (e.g., ABCD65031337D00D)\n"); + wantUsage = 1; + goto bail; + } + package_info.salt[i] = b; + } + break; case '?': wantUsage = 1; goto bail; diff --git a/tools/obbtool/mkobb.sh b/tools/obbtool/mkobb.sh index ba5256f..725250d 100755 --- a/tools/obbtool/mkobb.sh +++ b/tools/obbtool/mkobb.sh @@ -35,6 +35,7 @@ find_binaries() { UMOUNTBIN=`which umount` DDBIN=`which dd` RSYNCBIN=`which rsync` + PBKDF2GEN=`which pbkdf2gen` } check_prereqs() { @@ -76,6 +77,11 @@ check_prereqs() { echo "ERROR: ${LOSETUPBIN} is not executable!" exit 1 fi + + if [ "${PBKDF2GEN}x" = "x" ]; then \ + echo "ERROR: Could not find pbkdf2gen in your path!" + exit 1 + fi } cleanup() { @@ -142,7 +148,6 @@ onexit() { usage() { echo "mkobb.sh -- Create OBB files for use on Android" echo "" - echo " -c Use an encrypted OBB; must specify key" echo " -d <directory> Use <directory> as input for OBB files" echo " -k <key> Use <key> to encrypt OBB file" echo " -K Prompt for key to encrypt OBB file" @@ -156,7 +161,7 @@ check_prereqs use_crypto=0 -args=`getopt -o cd:hk:Ko:v -- "$@"` +args=`getopt -o d:hk:Ko:v -- "$@"` eval set -- "$args" while true; do \ @@ -223,9 +228,9 @@ loop_dev=$(${LOSETUPBIN} -f) || ( echo "ERROR: losetup wouldn't tell us the next ${LOSETUPBIN} ${loop_dev} ${tempfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 ) if [ ${use_crypto} -eq 1 ]; then \ - hashed_key=`echo -n "${key}" | md5sum | awk '{ print $1 }'` + eval `${PBKDF2GEN} ${key}` unique_dm_name=`basename ${tempfile}` - echo "0 `blockdev --getsize ${loop_dev}` crypt ${CRYPTO} ${hashed_key} 0 ${loop_dev} 0" | dmsetup create ${unique_dm_name} + echo "0 `blockdev --getsize ${loop_dev}` crypt ${CRYPTO} ${key} 0 ${loop_dev} 0" | dmsetup create ${unique_dm_name} old_loop_dev=${loop_dev} loop_dev=/dev/mapper/${unique_dm_name} fi @@ -253,6 +258,11 @@ echo "" echo "Successfully created \`${filename}'" +if [ ${use_crypto} -eq 1 ]; then \ + echo "salt for use with obbtool is:" + echo "${salt}" +fi + # # Undo all the temporaries # diff --git a/tools/obbtool/pbkdf2gen.cpp b/tools/obbtool/pbkdf2gen.cpp new file mode 100644 index 0000000..98d67c0 --- /dev/null +++ b/tools/obbtool/pbkdf2gen.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <openssl/evp.h> + +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/** + * Simple program to generate a key based on PBKDF2 with preset inputs. + * + * Will print out the salt and key in hex. + */ + +#define SALT_LEN 8 +#define ROUNDS 1024 +#define KEY_BITS 128 + +int main(int argc, char* argv[]) +{ + if (argc != 2) { + fprintf(stderr, "Usage: %s <password>\n", argv[0]); + exit(1); + } + + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Could not open /dev/urandom: %s\n", strerror(errno)); + close(fd); + exit(1); + } + + unsigned char salt[SALT_LEN]; + + if (read(fd, &salt, SALT_LEN) != SALT_LEN) { + fprintf(stderr, "Could not read salt from /dev/urandom: %s\n", strerror(errno)); + close(fd); + exit(1); + } + close(fd); + + unsigned char rawKey[KEY_BITS]; + + if (PKCS5_PBKDF2_HMAC_SHA1(argv[1], strlen(argv[1]), salt, SALT_LEN, + ROUNDS, KEY_BITS, rawKey) != 1) { + fprintf(stderr, "Could not generate PBKDF2 output: %s\n", strerror(errno)); + exit(1); + } + + printf("salt="); + for (int i = 0; i < SALT_LEN; i++) { + printf("%02x", salt[i]); + } + printf("\n"); + + printf("key="); + for (int i = 0; i < (KEY_BITS / 8); i++) { + printf("%02x", rawKey[i]); + } + printf("\n"); +} |