我有一个包含私人信息的数据库,只能由我的应用程序访问。我在assets文件夹中添加了我的数据库文件,该文件夹在应用程序第一次运行时被复制到应用程序数据库目录,但是“assets”目录和“data”目录(在root设备上)可以被任何其他应用程序访问所以我决定加密数据库。 Android默认的SQLite数据库不提供数据加密,所以我决定使用SQLCipher for android http://sqlcipher.net/sqlcipher-for-android/。
现在我已成功加密数据库,我可以使用特定密码访问它。但问题仍然存在......我应该在哪里存储这个密码?这样它只能被我的应用程序访问。
它是独立的应用程序,完全没有服务器交互
答案 0 :(得分:5)
Can't ask the user to enter it as the user could be a hacker
然后你无法安全地存储它。由于您已经确定的相同原因,特别是您的代码可以被反编译,您存储的任何可访问的地方都可以通过反编译找出,因此可以通过任何具有正确访问权限的代码进行检索。
用户提供的东西存储在用户存储的任何地方 - 可能是在他或她的头脑中。这不是软件可以访问的,这使其成为降低恶意软件攻击风险的理想选择。如果输入的密码有效,您无法知道用户是否被授权,但是您可以定义策略,例如最小密钥长度,最大入口尝试次数(在引入一些延迟或其他锁定之前)等等
答案 1 :(得分: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);
}