2

我有一个数据库,其中包含只能由我的应用程序访问的私人信息。我在资产文件夹中添加了我的数据库文件,该文件夹在应用程序第一次运行时被复制到应用程序数据库目录,但是任何其他应用程序都可以访问“资产”目录和“数据”目录(在根设备上)所以我决定加密数据库。Android 默认 SQLite 数据库不提供数据加密,所以我决定使用 SQLCipher for android http://sqlcipher.net/sqlcipher-for-android/

现在我已经成功地加密了数据库,我可以使用特定的密码访问它。但问题仍然存在......我应该在哪里存储这个密码?以便它只能由我的应用程序访问。

  1. 无法对其进行硬编码,因为即使它被混淆,反编译后也可以访问它。
  2. 也不能将其存储在文件系统中(资产/原始)
  3. 不能要求用户输入,因为用户可能是黑客

它是独立的应用程序,完全没有服务器交互

4

2 回答 2

5

Can't ask the user to enter it as the user could be a hacker那么您将无法安全地存储它。由于您已经确定的相同原因,特别是您的代码可以被反编译,您存储它的任何可访问的位置都可以通过反编译找出并因此由具有正确访问权限的任何代码检索。

用户提供的东西存储在用户存储它的任何地方——大概在他或她的脑海中。这不是软件可以访问的东西,因此非常适合降低恶意软件攻击的风险。如果输入的密码有效,您无法知道用户是否被授权,但是您可以定义策略,例如最小密钥长度、最大输入尝试次数(在引入一些延迟或其他锁定之前)等.

于 2012-08-14T20:40:02.180 回答
2

我不确定这个答案有多准确,但仍然发布它,因为我想从 Android 极客那里得到一些回应

考虑到 C 代码难以反编译,我使用 Android NDK 编写了一个简单的原生 C 库(.so),其中包含生成密码的算法。仅当应用程序由我的证书签名时才会执行该算法。如果有人在任何其他应用程序中重新使用此库,它不会返回密码,因为证书不匹配。我从这篇文章中得到了这个想法:http: //digital-identity.dk/2010/12/protecting-ip-in-android-applications/

这就是我获得证书的方式:

void Java_dk_digitalidetity_android_SomeClass_SomeMethod(JNIEnv* env, jobject obj) {
   // this.getPackageManager()
    jclass cls = (*env)->GetObjectClass(env, obj);
    jmethodID mid = (*env)->GetMethodID(env, cls, "getPackageManager", "()Landroid/content/pm/PackageManager;");
   jobject packageManager = (*env)->CallObjectMethod(env, obj, mid);

  // this.getPackageName()
   mid = (*env)->GetMethodID(env, cls, "getPackageName", "()Ljava/lang/String;");
   jstring packageName = (jstring) (*env)->CallObjectMethod(env, obj, mid);

  // packageManager->getPackageInfo(packageName, GET_SIGNATURES);
   cls = (*env)->GetObjectClass(env, packageManager);
   mid = (*env)->GetMethodID(env, cls, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
   jint flags = GET_SIGNATURES;
   jobject packageInfo = (*env)->CallObjectMethod(env, packageManager, mid, packageName, flags);

  // packageInfo->signatures
   cls = (*env)->GetObjectClass(env, packageInfo);
   jfieldID fid = (*env)->GetFieldID(env, cls, "signatures", "[Landroid/content/pm/Signature;");
   jobject signatures = (*env)->GetObjectField(env, packageInfo, fid);

 // signatures[0]
   jobject signature = (*env)->GetObjectArrayElement(env, signatures, 0);

 // signature->toByteArray()
   cls = (*env)->GetObjectClass(env, signature);
   mid = (*env)->GetMethodID(env, cls, "toByteArray", "()[B");
   jbytearray certificate = (*env)->CallObjectMethod(env, signature, mid);
}
于 2012-08-17T01:30:30.407 回答