8、Cipher 模式详解:加密模式、解密模式、签名模式、验证模式

聊到 Android 生物识别,绕不开一个核心概念——Cipher(密码器)。

很多初学者一上来就被 ENCRYPT_MODEDECRYPT_MODE 这些常量搞晕了。其实没那么复杂。我个人的理解是:Cipher 就像一把瑞士军刀,不同的模式就是不同的刀头。你用哪个模式,决定了这把刀怎么干活。

四种模式,一张图说清楚

先别急着看代码。我画了一张图,帮你快速建立整体认知。这张图我反复改了三版,就是为了让你一眼看明白四种模式分别用在哪儿。

Cipher 四种模式核心逻辑 Cipher 密码器 ENCRYPT_MODE 加密模式:生成加密数据 DECRYPT_MODE 解密模式:还原原始数据 SIGN_MODE 签名模式:生成数字签名 VERIFY_MODE 验证模式:验证签名真伪 左侧:加密/签名 → 需要生物识别授权 右侧:解密/验证 → 通常不需要再次授权

看到这张图,你应该有个大概印象了。左边两个模式(加密、签名)是「写操作」,需要用户按指纹授权。右边两个(解密、验证)是「读操作」,一般不需要重复验证。

ENCRYPT_MODE:加密模式

加密模式,说白了就是把你的数据变成一堆看不懂的乱码。我刚开始做生物识别时,以为加密就是随便调个 API 就行。后来踩了坑才明白——加密模式的核心在于「保护密钥」。

在 Android 生物识别中,加密模式通常这样用:

// 初始化 Cipher 为加密模式
val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val secretKey = keyStore.getKey("my_key", null) as SecretKey

// 关键:用加密模式初始化
cipher.init(Cipher.ENCRYPT_MODE, secretKey)

// 加密数据
val plainText = "这是需要保护的敏感数据"
val encryptedData = cipher.doFinal(plainText.toByteArray())

这里有个细节要注意:cipher.init() 调用之后,Cipher 对象就「锁定」了。你不能换个模式继续用,必须重新初始化。

核心要点:加密模式生成的密文,只有用对应的密钥和解密模式才能还原。密钥如果存在 AndroidKeyStore 里,那只有用户通过生物识别验证后才能使用。

DECRYPT_MODE:解密模式

解密模式是加密的逆操作。把乱码还原成可读的数据。

我记得有一次,同事问我:「为什么解密的时候不需要用户再按一次指纹?」

嗯,这个问题问得好。原因其实很简单:解密操作本身不暴露密钥。密钥在 KeyStore 里,解密过程在安全环境中完成,App 拿到的只是解密后的结果。所以系统认为——既然你之前已经验证过了,这次就不必再按了。

// 解密模式初始化
cipher.init(Cipher.DECRYPT_MODE, secretKey)

// 解密数据
val decryptedData = cipher.doFinal(encryptedData)
val originalText = String(decryptedData)

避坑指南:我曾经犯过一个错误——加密和解密用了不同的 IV(初始化向量)。结果解密出来的数据全是乱码。记住:加密时生成的 IV 必须保存下来,解密时要用同一个 IV。

SIGN_MODE:签名模式

签名模式,说白了就是「盖章」。你用自己的私钥给一段数据盖个章,别人拿到后可以验证这个章是不是你盖的。

签名模式和加密模式最大的区别是什么?

加密是为了保密,签名是为了防篡改。你想想看,如果只是加密,中间人虽然看不懂内容,但他可以把密文替换掉。而签名可以保证——数据一旦被改,签名就失效了。

// 签名模式初始化
val signature = Signature.getInstance("SHA256withRSA")
signature.initSign(privateKey)

// 对数据进行签名
signature.update(dataToSign)
val signedData = signature.sign()

在生物识别场景下,签名模式常用于「证明这个操作是本人发起的」。比如支付确认、授权操作等。

注意:签名模式需要用户验证生物特征。因为签名操作会暴露私钥的使用能力,系统必须确保「是本人」。

VERIFY_MODE:验证模式

验证模式是签名的配套操作。别人拿着你的公钥,来验证签名是不是你生成的。

这里有个有意思的点:验证模式不需要生物识别。为什么?因为验证用的是公钥,公钥本来就是公开的。你不需要按指纹来证明「我有权使用公钥」。

// 验证模式初始化
val signature = Signature.getInstance("SHA256withRSA")
signature.initVerify(publicKey)

// 验证签名
signature.update(originalData)
val isValid = signature.verify(signedData)

我个人习惯把验证逻辑放在服务端。客户端只负责签名,服务端拿公钥验证。这样即使客户端被逆向,攻击者也伪造不了合法的签名。

四种模式对比一览

模式 操作类型 是否需要生物识别 典型场景
ENCRYPT_MODE 写操作 加密用户敏感数据
DECRYPT_MODE 读操作 否(通常) 解密已加密的数据
SIGN_MODE 写操作 交易签名、身份认证
VERIFY_MODE 读操作 验证签名真伪

实际项目中的选择建议

说了这么多,到底什么时候用哪个?我根据实际项目经验,给你几个参考:

  • 存储密码、Token 等敏感信息 → 用 ENCRYPT_MODE + DECRYPT_MODE
  • 支付确认、授权操作 → 用 SIGN_MODE + VERIFY_MODE
  • 既想保密又想防篡改 → 先加密,再对密文签名
  • 只需要验证身份 → 只用签名模式就够了,不用加密

一句话总结:加密模式和解密模式是一对,用于保护数据机密性;签名模式和验证模式是一对,用于保证数据完整性和身份真实性。别搞混了。

好了,四种模式就讲到这里。你只要记住——左边两个要按指纹,右边两个不用。这个规律能帮你避免 90% 的初始化错误。

公众号:蓝海资料掘金营,微信deep3321