Android App中的简单加密

Every Android developer sooner or later faced with situation when he needs to keep save sensitive information inside an app. You may think right now :

每个Android开发人员迟早都需要将敏感信息保存在应用程序内部的情况。 您可能现在想:

— uhh!! Seems we are going to code a lot!

恩! 似乎我们要编写很多代码!

and you will be almost right :) as in comparison with our iOS colleagues that simply use the KeyChain service, which is a part of Apple’s overall security framework for iOS. Ah, as always!

与您只使用KeyChain服务的 iOS同事相比,您几乎是正确的:),该服务是Apple iOS总体安全框架的一部分。 啊,一如既往!

And what should we do with data on Android? Yes, store it in SharedPreferences, but after it’s been encrypted.

我们应该如何处理Android上的数据? 是的,将其存储在SharedPreferences中,但是在加密之后。

Lets take a look to javax.crypto package and find out what we need to encrypt information:

让我们看一下javax.crypto包,找出我们需要对信息进行加密的内容:

  • Generate SecretKey

    生成密钥

  • Retrieve it from KeyStore

    KeyStore检索它

  • Obtain instance of Cipher

    获取密码实例

  • Initialize Cipher with corresponds encryption mode and SecretKey

    初始化密码 与相应的加密模式SecretKey

  • Encrypt or decrypt data

    加密或解密数据
  • Fight with wish to hard code something during cipher initialization.

    希望在密码初始化期间对某些内容进行硬编码。

Let’s start coding!

让我们开始编码!

Image for post
Photo by Serghei Trofimov on Unsplash
Serghei Trofimov在《 Unsplash》上的 照片
  1. Generate SecretKey

    生成密钥

To generate SecretKey you will need to generate some alias that will bound to secret key in KeyStore. Using this alias you will be able to retrieve it from KeyStore. Usually this alias bound to user, it is very helpful if you application support multi accounts login.

要生成SecretKey,您将需要生成一些绑定到KeyStore中的密钥的别名 。 使用此别名,您将能够从KeyStore检索它。 通常,此别名绑定到用户,如果您的应用程序支持多帐户登录,这将非常有用。

const val KEYSTORE_PROVIDER_ANDROID = "AndroidKeyStore"private fun generateSecretKey(alias: String): SecretKey {
try {
val builder =
KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_ENCRYPT or
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
KEYSTORE_PROVIDER_ANDROID)
keyGenerator?.init(builder.build())
return keyGenerator?.generateKey()
} catch (e: Exception) {
Timber.d("Failed to create key")
throw e
}
}

2. Retrieve it from KeyStore

2.从KeyStore检索它

Retrieve SecretKey from KeyStore using alias from the previous step.

使用上一步中的别名KeyStore中检索SecretKey

val keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER_ANDROID)
keyStore.load(null)private fun retrieveSecretKey(): SecretKey? {
val entry = keyStore.getEntry(privateKeyId, null)
val secretKey: SecretKey? = (entry as?
(KeyStore.SecretKeyEntry))?.secretKey return secretKey
}

3. Obtain instance of Cipher

3.获取密码实例

val AES_TRANSFORMATION = "AES/GCM/NoPadding"
val cipher = Cipher.getInstance(AES_TRANSFORMATION)

4. Initialize Cipher it with correspond encryption mode and SecretKey

4.用相应的加密模式和SecretKey初始化Cipher。

To initialize Cipher we will need Initialization Vector (IV). Initialization Vector is is a fixed-size input to a cryptographic primitive. It is typically required to be random or pseudorandom. The point of an IV is to tolerate the use of the same key to encrypt several distinct messages.

要初始化密码,我们将需要 初始化向量 (IV)。 初始化向量是加密原语的固定大小输入。 通常要求它是随机或伪随机的。 IV的重点是允许使用相同的密钥来加密几个不同的消息。

To put it simply, it’s a cryptographic feature that injects randomness to make it more secure.

简而言之,它是一种加密功能,可注入随机性以使其更加安全。

val secureRandom = SecureRandom()
val initVector = ByteArray(128)
secureRandom.nextBytes(initVector)

The important part is that the IV you use in the encryption must be the same one you use in the decryption. So it should be stored like this.

重要的是,加密中使用的IV必须与解密中使用的IV相同。 所以应该这样存储。

val encodedInitVector =
Base64.encodeToString(initVector, Base64.DEFAULT)sharedPreferences.edit()
.putString(ENCRYPTION_IV_KEY, encodedInitVector)
.apply()

Now we are ready to init Cipher for encryption

现在我们准备初始化密码进行加密

val gcmSpec = GCMParameterSpec(128, initVector)
cipher?.init(Cipher.ENCRYPT_MODE, getSecretKey(), gcmSpec)

And here we create Cipher for decryption

在这里,我们创建用于解密的 密码

private fun getInitVectorKey(): ByteArray? {
val encodedIv = preferenceManager
.getString(ENCRYPTION_IV_KEY, null)
return Base64.decode(encodedIv, Base64.DEFAULT)
}val cipher = Cipher.getInstance(AES_TRANSFORMATION)
val spec = GCMParameterSpec(AUTH_TAG_LENGTH, getInitVectorKey())
cipher?.init(Cipher.DECRYPT_MODE, retrieveSecretKey(), spec)

5. Encrypt or decrypt data

5.加密或解密数据

After Cipher has been created and initialized, we are able to encrypt or decrypt data

创建和初始化密码后,我们便可以加密或解密数据

@Throws(Exception::class)
fun encrypt(message: ByteArray): ByteArray? {
return encryptCipher.doFinal(message)
}@Throws(Exception::class)
fun decrypt(encryptionKey: ByteArray?): ByteArray? {
return decryptCipher.doFinal(encryptionKey)
}

6. Fight with wish to hard code something during cipher initialization.

6.希望在密码初始化期间对某些内容进行硬编码。

During setting Cipher you might be tempted to hard code Initialization Vector or store it from initialized Cipher with method that does not need GCMParameterSpec with IV

在设置Cipher的过程中,您可能会尝试对初始化向量进行硬编码或使用不需要IV的 GCMParameterSpec的方法从初始化的Cipher中存储它

val cipher = Cipher.getInstance(AES_TRANSFORMATION)
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
val initVector = cipher.iv
storeInitVector(initVector)

Don’t do it.

不要这样做

After data is encrypted it is ready to be stored in SharedPreferences as follows

数据加密后,可以按如下所示存储在SharedPreferences

val encryptedBytes = aesCipher.encrypt(message.toByteArray())
val encodedMsg = Base64.encodeToString(
encryptedBytes, Base64.DEFAULT)
sharedPreferences.edit()
.putString(YOUR_DATA_KEY, encodedMsg)
.apply()

Or retrieved from SharedPreferences

或从SharedPreferences中检索

val encodedMsg = sharedPreferences.getString(YOUR_DATA_KEY, null)
val encryptedMsg = Base64.decode(encodedMsg, Base64.DEFAULT)
val messageBytes = aesCipher.decrypt(encryptedMsg)
val message = String(messageBytes, Charsets.UTF_8)

Integration

积分

This code sample intended to work on Android 6 and newer, so please check you build.gradle file

该代码示例旨在在Android 6及更高版本上运行,因此请检查您的build.gradle文件

android {
defaultConfig {
minSdkVersion 23
}
}

All this code may obsolete very soon as new Encrypted Shared Preference API from the AndroidX artifacts will be released, so that it will be available right from the box!

随着来自AndroidX工件的新的Encrypted Shared Preference API即将发布,所有这些代码可能很快就会过时,因此可以立即使用!

Enjoy coding!

享受编码!

翻译自: https://medium.com/@jacobvynnyk/simple-encryption-in-android-app-74a85e572b1b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 代码混淆与加密是一种保护应用程序的方法,可以防止反编译和代码分析。下面是一个示例,演示如何使用 ProGuard 进行代码混淆和加密。 1. 配置 ProGuard 在 Android Studio 打开 app 模块的 build.gradle 文件,在文件添加以下代码: ``` android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... } ``` 这将启用 ProGuard,并告诉 Android Studio 使用 `proguard-rules.pro` 文件的规则来混淆和加密代码。 2. 编写 proguard-rules.pro 文件 在项目的 `app` 目录下创建一个名为 `proguard-rules.pro` 的文件,并添加以下规则: ``` # 防止类名、方法名、字段名被修改 -keepattributes Signature,InnerClasses,*Annotation* # 防止类名被修改 -keep class com.example.myapp.** { *; } # 防止方法名被修改 -keepclassmembers class com.example.myapp.** { *; } # 防止字段名被修改 -keepclassmembers class * { ** myFieldName; } # 混淆代码 -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # 加密字符串 -encryptstrings ``` 这些规则将防止类名、方法名和字段名被修改,并使用默认的 ProGuard 混淆代码。`-encryptstrings` 规则将启用字符串加密。 3. 运行 ProGuard 在 Android Studio ,选择 Build > Generate Signed Bundle/APK,选择 APK,然后按照向导的指示生成一个签名的 APK。Android Studio 将自动运行 ProGuard,并混淆和加密您的代码。 以上就是一个 Android 代码混淆与加密的示例。请注意,代码混淆和加密并不能完全保护您的应用程序,只能增加攻击者分析和反编译代码的难度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值