- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我只是在熟悉 Android Keystore API。我发现可以使用以下功能:
- At least on some devices the Android Keystore is hardware backed, meaning that crypto operations run in a secure environment (TEE).
- When the keystore is hardware backed, private RSA keys as well as secret symmetric keys that have been created within the Keystore can be configured to never leave the Keystore and the raw keys cannot be read out even with root access.
我现在想知道以下是否可行:
- Generate a Public/Private key pair where the private key never leaves the Keystore
- Upload the public key of this pair to a server
- On the server: create a random symmetric AES key and encrypt it with the public RSA key uploaded by the user
- On the device: Download this encrypted AES key
- Import it into the hardware backed Keystore such that it is decrypted in there with the private key of the pair and stored under a new alias
- Use this new key alias to perform symmetric encryption and decryption
1-4 应该是可能的,我现在缺少的链接是此列表中的第 5 点。有人可以帮助我并告诉我这是否可能和/或指向正确的 API 引用吗?
但在我看来, key 的解包似乎发生在正常环境中,并且解密后的 AES key 将在 App 中可用,这不能满足我的安全要求。
更新:
我使用链接 SecretKeyWrapper
创建了一个小型测试项目这是两个代码 fragment :
第一个执行以下操作:
- Create a random AES key (not within in the keystore, this is what would happen on a server later). Obviously the raw key can be retrieved from the generated
SecretKey
object what isn't a problem since the server can know the key.- Encrypt/wrap the key with a RSA public key that was created in the client's Android Keystore (this would also happen on a server).
- Decrypt the key again with the RSA private key (this would happen on the client and actually happens within the TEE in the example).
fragment 1:
SecretKeyWrapper secretKeyWrapper = new SecretKeyWrapper(this,"testKeyRsa");
// Generate a random AES key (not in the keystore) [1]
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKeyGenerated = keyGen.generateKey();
byte[] secretKeyGeneratedRaw = secretKeyGenerated.getEncoded();
// wrap this key with the RSA key from the keystore [2]
byte[] wrappedKey = secretKeyWrapper.wrap(secretKeyGenerated);
// unwrap it again with the RSA key from the keystore [3]
SecretKey unwrappedKey = secretKeyWrapper.unwrap(wrappedKey);
// the raw key can be read again [4]
byte[] unwrappedKeyRaw = secretKeyGenerated.getEncoded();
我想要实现的是 [3] 中的解包 key 使用新别名存储在 keystore 中,而不返回原始 key 。当然我可以轻松导入 SecretKey
对象进入 keystore ,但问题是,此时可以使用语句 [4] 从对象中检索原始 key ,这会导致安全漏洞。很明显,解包/解密已经在 keystore /TEE 中进行,因为用于解密的 RSA 私钥存在于 keystore 中,无法检索。
如果我将此与在 keystore 中创建随机 secret AES key 的情况进行比较,我注意到返回了不同的类型(实现 SecretKey
接口(interface))。在上面的例子中,类型是 SecretKeySpec
,而对于从 Android Keystore 返回的 key (请参阅下面的代码段 2),“不透明”类型用于 getEncoded()
的位置方法总是返回 null。在以下示例中,keyAesKeystore
的类型是AndroidKeyStoreSecretKey
.
fragment 2:
// create a new AES key in the keystore
KeyGenerator keyGenAndroid = KeyGenerator.getInstance("AES","AndroidKeyStore");
keyGenAndroid.init(
new KeyGenParameterSpec.Builder("testKeyAes",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
SecretKey keyAesKeystore = keyGenAndroid.generateKey();
// this returns null
byte[] keyAesKeystoreRaw = keyAesKeystore.getEncoded();
因此换个问题:是否可以通过某种方式将 RSA 包装的 AES key 安全地导入到 Android Keystore 中而不向应用程序泄露 key ?
更新 2:
@Robert 在下面的回答中绝对有效,如果解包发生在 TEE 或 Rich OS(应用程序)中实际上并不重要,因为应用程序(或篡改版本)以后总是可以(在拦截包装 key )只需“使用”Keystore 中的 RSA 私钥来解包 AES key (根本不需要访问原始私钥)。
不过还有一个想法:我发现可以在 Android keystore 中为 key 设置 key 保护参数(请参阅 here)。
SecretKeyWrapper
的链接实现不使用此类保护参数。更改 generateKeyPair
后方法如下并添加 PURPOSE_DECRYPT
和 PURPOSE_ENCRYPT
属性一切仍然有效。
private static void generateKeyPair(Context context, String alias)
throws GeneralSecurityException {
final Calendar start = new GregorianCalendar();
final Calendar end = new GregorianCalendar();
end.add(Calendar.YEAR, 100);
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build();
final KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
gen.initialize(keyGenParameterSpec);
gen.generateKeyPair();
}
我现在可以通过删除 PURPOSE_DECRYPT
来保护 RSA key ,使其不能用于解密属性(property)。正如预期的那样 Cipher.unwrap
方法停止工作并抛出 Incompatible purpose
那么异常(exception)。
那么我需要的是一个保护属性,其中普通解密功能被阻止,但它允许我正在寻找的这种“安全导入功能”。类似“PURPOSE_IMPORT
”的东西显然不存在。
最佳答案
从 API 级别 28 (Android Pie) 开始,您正在寻找的东西现在已经存在。要使用你,你需要:
这应该适用于 API 级别 28 的任何设备。但是,如果设备的 Keymaster 版本 < 4(请参阅认证证书以了解存在的 Keymaster 版本),然后解包操作将返回包装后的 key Android 用户空间的 Material 。 Keymaster 版本 4(或更高版本)会将未包装的 Material 保存在安全的硬件中,但由于较低版本不支持包装 key 功能,因此必须对其进行模拟。
如果您的 Keymaster 版本较低,会发生以下情况:当您创建 PURPOSE_WRAP_KEY key 对时,安全硬件实际请求的是 PURPOSE_DECRYPT key 对。然后当你进行导入时,keystore 守护进程使用这个 PURPOSE_DECRYPT 私钥从包装器中解密 secret ,然后它将 secret 导入安全硬件并删除保存它的用户空间内存。因此, key Material 在 keystore 守护程序的内存中存在几分之一毫秒。同样,如果设备具有 Keymaster 版本 4+,它只会在安全硬件中解包并且永远不会离开。
关于java - 将加密的 AES key 导入 Android Keystore 并将其存储在新别名下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39249856/
我正在使用框架的对象编写一个用于加密/解密的简单库。方法如下: public static byte[] Encrypt(byte[] key, byte[] vector, byte[] input
据我所知,RIM Crypto API 似乎只提供用于对称加密 (3Des) 的 PKCS5 填充模式。我正在使用 JDE 4.6.0。 我正在尝试为黑莓应用程序提供密码学,该应用程序需要与已经使用标
我已经获得了用于加密的 Java 实现,但遗憾的是我们是一家 .net 商店,我无法将 Java 整合到我们的解决方案中。可悲的是,我也不是 Java 专家,所以我已经为此苦苦挣扎了几天,我想我终于可
我正在尝试使用 KMS 和 AWS 加密 SDK 加密数据。查看 AWS documentation 中提供的示例,似乎没有地方可以明确设置数据 key 。 我找到了 EncryptionMateri
我目前有一个用于为我的网站制作哈希的代码,该代码使用 SALT 进行哈希处理,因此密码是不可逆的...... 目前它是 100% 为我的网站工作,它是使用 ASP.NET(C#) 编码的 这是我的代码
我想要做的是在 javascript 中生成一个 key 对,并在 PHP 中使用这些加密,然后用 JS 解密。 我在附加的代码中有两个问题 它不会从装甲文本块重新加载私钥 并且它不会解密 PHP 加
在进行密码哈希时,我有以下 node.js 代码。 body.password = covid@19 salt = "hello@world" body.passwordhex = crypto.cr
我想知道的是在配置文件中加密连接字符串的明确方法。以下是我的问题: 使用机器级加密,访问我的服务器的任何人都不能编写一个小的 .Net 程序来读取连接字符串的内容吗? 如果我将我的应用程序部署到企业环
我知道 rsync 可以在文件传输期间启用/禁用 ssh 加密协议(protocol)。那么,如果 ssh 加密协议(protocol)被禁用了,是不是意味着 rsync 根本不做任何加密呢? 另外,
脚本必须搜索网页内的字符串。但该脚本不应显示它正在搜索的字符串。我的意思是搜索字符串应该采用加密格式或任何其他格式。但如果没有该搜索字符串,则不应显示网页或应在页面上显示错误。 我要开发一个插件。如果
我正在尝试加密 MySQL 上的某些字段。我正在使用 TPC-DS 的 v2.8 版本,并尝试在客户地址表的某些列上使用 AES。知道如何加密字段的所有行吗?我尝试使用 UPDATE customer
我需要一个简单的 javascript 函数,它允许我使用 key 加密 textarea 数据( key 是存储为散列 session 变量的用户密码,由 PHP 打印到字段中) 我基本上希望在用户
如何在 JavaScript 中散列/加密字符串值?我需要一种机制来隐藏 localStorage/cookie 中的一些数据吗? 这与安全问题有关,但我想为我的数据提供一些保护。 最佳答案 有很多
我有一个程序,其中数据库的密码由远程用户设置。该程序将用户名和密码保存到 xml 文件中的加密字符串中,否则应该是人类可读的。现在,这工作正常,我使用带有 key 的 C# DES 加密,它被加密和解
Kotlin 中是否有任何关于椭圆曲线加密的信息? 用于生成 key 对和加密、解密消息。 关于这个主题的信息很少甚至没有。 例如,我想实现 ECC P-521 椭圆曲线。 是否可以在 Kotlin
所以我知道 MD5 在技术上是新应用程序的禁忌,但我随机想到了这个: 自 md5($password); 不安全,不会 md5(md5($password)) 是更好的选择?我使用它的次数越多,它会变
我一直在努力使用 crypto_secretbox_easy() 在 libsodium 中加密/解密一些数据| .我似乎找不到关于使用的任何好的文档。 我想从用户那里获取密码,用它来以某种方式制作
我正在做一个加密项目 视频,我对这个程序有几个问题。 我用命令转码mp4至HLS与 ts段持续时间约为 10 秒。 首先,我需要使用数据库中的 key 加密这些视频。然而, 我不知道是否使用 ffmp
我有一个加密/复制保护问题。 我正在为使用加密狗的公司编写应用程序。请不要告诉我软件保护是没有用的,或者我应该让它自由地飞向空中,或者我花任何时间这样做都是浪费;这不是关于软件保护有效性的哲学问题,更
我对 有一个疑问VIM 加密 key . 我有一个文本文件,我使用加密该文件 :X 现在,加密 key 的存储位置(路径)。 无论是存储在单独的文件中还是存储在文本文件本身中。 如果我打开文件,它会询
我是一名优秀的程序员,十分优秀!