- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我惊讶地发现 Jatpack Security 提供了 only support for File
and SharedPreferences
encryption .但我需要能够加密和解密String
s 因为我想使用 AccountManager
并存储刷新和访问 token ,以及官方文档中建议的这种数据 should be send encrypted to the AccountManager
:
网上搜索有很多关于如何加密的教程String
s 在 Android 上,但它们中的大多数似乎已经很老了,我害怕选择错误的可能会导致 Play Store Console 上出现这种警告:
那么,加密 String
的正确和安全方法是什么? s 在 2021 年的 Android 应用程序中? Jetpack Security 还能在一定程度上使用(也许是生成 key ?)以及为什么它不支持开箱即用的字符串加密,而只支持 File
s 和 SharedPreferences
?
最佳答案
深入了解 EncryptedSharedPreferences
的实现后和 EncryptedFile
,我设法创建了一个 CryptoHelper
该类使用与 Jetpack Security 的 2 个类相同的方法,提供加密、解密、签名和验证的方法 ByteArray
年代:
import android.content.Context
import androidx.security.crypto.MasterKeys
import com.google.crypto.tink.Aead
import com.google.crypto.tink.DeterministicAead
import com.google.crypto.tink.KeyTemplate
import com.google.crypto.tink.KeyTemplates
import com.google.crypto.tink.PublicKeySign
import com.google.crypto.tink.PublicKeyVerify
import com.google.crypto.tink.aead.AeadConfig
import com.google.crypto.tink.daead.DeterministicAeadConfig
import com.google.crypto.tink.integration.android.AndroidKeysetManager
import com.google.crypto.tink.signature.SignatureConfig
import java.io.IOException
import java.security.GeneralSecurityException
/**
* Class used to encrypt, decrypt, sign ad verify data.
*
* <pre>
* // Encrypt
* val cypherText = cryptoHelper.encrypt(text.toByteArray())
* // Decrypt
* val plainText = cryptoHelper.decrypt(cypherText)
* // Sign
* val signature = cryptoHelper.sign(text.toByteArray())
* // Verify
* val verified = cryptoHelper.verify(signature, text.toByteArray())
* </pre>
*/
@Suppress("unused")
class CryptoHelper(
private val aead: Aead,
private val deterministicAead: DeterministicAead,
private val signer: PublicKeySign,
private val verifier: PublicKeyVerify,
) {
/**
* Builder class to configure CryptoHelper
*/
class Builder(
// Required parameters
private val context: Context,
) {
// Optional parameters
private var masterKeyAlias: String = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
private var keysetPrefName = KEYSET_PREF_NAME
private var keysetAlias = KEYSET_ALIAS
private var aeadKeyTemplate: KeyTemplate
private var deterministicAeadKeyTemplate: KeyTemplate
private var signKeyTemplate: KeyTemplate
init {
AeadConfig.register()
DeterministicAeadConfig.register()
SignatureConfig.register()
aeadKeyTemplate = KeyTemplates.get("AES256_GCM")
deterministicAeadKeyTemplate = KeyTemplates.get("AES256_SIV")
signKeyTemplate = KeyTemplates.get("ECDSA_P256")
}
/**
* @param masterKey The SharedPreferences file to store the keyset.
* @return This Builder
*/
fun setMasterKey(masterKey: String): Builder {
this.masterKeyAlias = masterKey
return this
}
/**
* @param keysetPrefName The SharedPreferences file to store the keyset.
* @return This Builder
*/
fun setKeysetPrefName(keysetPrefName: String): Builder {
this.keysetPrefName = keysetPrefName
return this
}
/**
* @param keysetAlias The alias in the SharedPreferences file to store the keyset.
* @return This Builder
*/
fun setKeysetAlias(keysetAlias: String): Builder {
this.keysetAlias = keysetAlias
return this
}
/**
* @param keyTemplate If the keyset for Aead encryption is not found or valid, generates a new one using keyTemplate.
* @return This Builder
*/
fun setAeadKeyTemplate(keyTemplate: KeyTemplate): Builder {
this.aeadKeyTemplate = keyTemplate
return this
}
/**
* @param keyTemplate If the keyset for deterministic Aead encryption is not found or valid, generates a new one using keyTemplate.
* @return This Builder
*/
fun setDeterministicAeadKeyTemplate(keyTemplate: KeyTemplate): Builder {
this.deterministicAeadKeyTemplate = keyTemplate
return this
}
/**
* @param keyTemplate If the keyset for signing/verifying is not found or valid, generates a new one using keyTemplate.
* @return This Builder
*/
fun setSignKeyTemplate(keyTemplate: KeyTemplate): Builder {
this.signKeyTemplate = keyTemplate
return this
}
/**
* @return An CryptoHelper with the specified parameters.
*/
@Throws(GeneralSecurityException::class, IOException::class)
fun build(): CryptoHelper {
val aeadKeysetHandle = AndroidKeysetManager.Builder()
.withKeyTemplate(aeadKeyTemplate)
.withSharedPref(context, keysetAlias + "_aead__", keysetPrefName)
.withMasterKeyUri(KEYSTORE_PATH_URI + masterKeyAlias)
.build().keysetHandle
val deterministicAeadKeysetHandle = AndroidKeysetManager.Builder()
.withKeyTemplate(deterministicAeadKeyTemplate)
.withSharedPref(context, keysetAlias + "_daead__", keysetPrefName)
.withMasterKeyUri(KEYSTORE_PATH_URI + masterKeyAlias)
.build().keysetHandle
val signKeysetHandle = AndroidKeysetManager.Builder()
.withKeyTemplate(signKeyTemplate)
.withSharedPref(context, keysetAlias + "_sign__", keysetPrefName)
.withMasterKeyUri(KEYSTORE_PATH_URI + masterKeyAlias)
.build().keysetHandle
val aead = aeadKeysetHandle.getPrimitive(Aead::class.java)
val deterministicAead = deterministicAeadKeysetHandle.getPrimitive(DeterministicAead::class.java)
val signer = signKeysetHandle.getPrimitive(PublicKeySign::class.java)
val verifier = signKeysetHandle.publicKeysetHandle.getPrimitive(PublicKeyVerify::class.java)
return CryptoHelper(aead, deterministicAead, signer, verifier)
}
}
fun encrypt(plainText: ByteArray, associatedData: ByteArray = ByteArray(0)): ByteArray =
aead.encrypt(plainText, associatedData)
fun decrypt(ciphertext: ByteArray, associatedData: ByteArray = ByteArray(0)): ByteArray =
aead.decrypt(ciphertext, associatedData)
fun encryptDeterministically(plainText: ByteArray, associatedData: ByteArray = ByteArray(0)): ByteArray =
deterministicAead.encryptDeterministically(plainText, associatedData)
fun decryptDeterministically(ciphertext: ByteArray, associatedData: ByteArray = ByteArray(0)): ByteArray =
deterministicAead.decryptDeterministically(ciphertext, associatedData)
fun sign(data: ByteArray): ByteArray =
signer.sign(data)
fun verify(signature: ByteArray, data: ByteArray): Boolean =
try {
verifier.verify(signature, data)
true
} catch (e: GeneralSecurityException) {
false
}
companion object {
private const val KEYSTORE_PATH_URI = "android-keystore://"
private const val KEYSET_PREF_NAME = "__crypto_helper_pref__"
private const val KEYSET_ALIAS = "__crypto_helper_keyset"
}
}
不要忘记添加
com.google.crypto.tink:tink-android
作为实现依赖项,因为 Jetpack Security 不会将其公开为 api。
关于android - 2021 年在 Android 中加密字符串的最佳和最安全的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69953633/
我正在学习 Spring 安全性,但我对它的灵活性感到困惑.. 我知道我可以通过在标签中定义规则来保护网址 然后我看到有一个@secure 注释可以保护方法。 然后还有其他注释来保护域(或 POJO)
假设有一个 key 加密 key 位于内存中并且未写入文件或数据库... byte[] kek = new byte[32]; secureRandom.nextBytes(kek); byte[]
我有 Spring Security 3.2.0 RC1 的问题 我正在使用标签来连接我 这表示“方法‘setF
我正在创建一个使用 Node Js 服务器 API 的 Flutter 应用程序。对于授权,我决定将 JWT 与私钥/公钥一起使用。服务器和移动客户端之间的通信使用 HTTPS。 Flutter 应用
在过去的几年里,我一直在使用范围从 Raphael.js 的 javascript 库。至 D3 ,我已经为自己的教育操纵了来自网络各地的动画。我已经从各种 git 存储库下载了 js 脚本,例如 s
在 python 中实现身份验证的好方法是什么?已经存在的东西也很好。我需要它通过不受信任的网络连接进行身份验证。它不需要太高级,只要足以安全地获取通用密码即可。我查看了 ssl 模块。但那个模块让我
我正在尝试学习“如何在 Hadoop 中实现 Kerberos?”我已经看过这个文档 https://issues.apache.org/jira/browse/HADOOP-4487我还了解了基本的
我有一个带有 apache2、php、mysql 的生产服务器。我现在只有一个站点 (mysite.com) 作为虚拟主机。我想把 phpmyadmin、webalizer 和 webmin 放在那里
前些天在网上看到防火墙软件OPNsense,对其有了兴趣,以前写过一个其前面的一个软件M0n0wall( 关于m0n0wa
我在 Spring Boot 和 oauth2(由 Google 提供)上编写了 rest 后端,在 "/login" 上自动重定向。除了 web 的 oauth 之外,我还想在移动后端进行 Fire
我想调用类 Foo,它的构造函数中有抽象类 Base。我希望能够从派生自 Base 的 Derived 调用 Foo 并使用 Derived覆盖方法而不是 Base 的方法。 我只能按照指示使用原始指
如何提高 session 的安全性? $this->session->userdata('userid') 我一直在为我的 ajax 调用扔掉这个小坏蛋。有些情况我没有。然后我想,使用 DOM 中的
我目前正在为某些人提供程序集编译服务。他们可以在在线编辑器中输入汇编代码并进行编译。然后编译它时,代码通过ajax请求发送到我的服务器,编译并返回程序的输出。 但是,我想知道我可以做些什么来防止对服务
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
目前,我通过将 session 中的 key 与 MySQl 数据库中的相同 key 相匹配来验证用户 session 。我使用随机数重新生成 session ,该随机数在每个页面加载时都受 MD5
Microsoft 模式与实践团队提供了一个很棒的 pdf,称为:“构建安全的 asp.net 应用程序”。 microsoft pdf 由于它是为 .Net 1.0 编写的,所以现在有点旧了。有谁知
在 Lua 中,通常会使用 math.random 生成随机值和/或字符串。 & math.randomseed , 其中 os.time用于 math.randomseed . 然而,这种方法有一个
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我们有一个严重依赖 Ajax 的应用程序。确保对服务器端脚本的请求不是通过独立程序而是通过坐在浏览器上的实际用户的好方法是什么 最佳答案 真的没有。 通过浏览器发送的任何请求都可以由独立程序伪造。 归
我正在寻找使用 WebSockets 与我们的服务器通信来实现 web (angular) 和 iPhone 应用程序。在过去使用 HTTP 请求时,我们使用请求数据、url、时间戳等的哈希值来验证和
我是一名优秀的程序员,十分优秀!