Android加密学
作为一名 Android 开发人员, 我们不必深入研究密码学就能了解如何加密数据. 然而, 许多开发人员仍因缺乏加密术语知识而感到困惑.
我们不想盲目地编写代码, 而是希望了解自己在写什么.
那么什么是密码学呢? 简单地说, 它是一种让我们的数据保密的方法, 也就是说, 没有人能看到数据背后的内容. 想象一下, 你想保护自己的手机不被他人误用. 那么, 你会采取一些安全措施. 假设你在设备上设置了一个密码, 只有你才能解锁. 这样, 只有你知道key(PIN 码), 也只有你能使用该key解锁并查看手机中的内容. 其他不知道key的人就无法偷偷进入你的手机.
想象一下另一种情况, 你想和朋友秘密通信, 这样就没人能听懂你们俩的话了. 你和你的朋友选择创建一种只有你们两个人懂的新语言, 每个单词都使用特殊代码. 这就是密码学. 它就像用神奇的密码来锁定和解锁你的信息, 确保只有你和你的朋友才能理解它们.
密码学基本图解
在数字世界中, 这些神奇的密码是数学技术和算法, 它们可以保护你的信息不被窥探. 这就好比你有一把特殊的key, 你可以用它让你的信息在别人看来像胡言乱语. 但是, 你的朋友可以使用相同的密钥将信息变回原样.
那么, 我们用来确保信息安全的这些算法又是怎么回事呢? 有很多技术可以确保我们的信息安全, 比如使用
- 对称密钥算法(AES, GMS)
- 非对称密钥算法(RCA, ECC)
- 哈希函数(MD5, SHA)
让我们来谈谈它们吧.
对称密钥算法: 想象一下, 你有一个宝箱和一把钥匙. 你用这把钥匙锁住宝箱(加密), 只有拥有相同钥匙的人才能解锁(解密). 换句话说, 我们使用相同的密钥进行加密和解密. 因此, 如果有人拥有相同的密钥, 就可以打开箱子.
对称加密图解. 它使用相同的密钥进行加密和解密.
非对称密钥算法: 也称为公钥加密. 假设你有两把钥匙, 一把用来锁定宝箱, 另一把用来解锁. 我们称它们为公钥和私钥. 你用公钥锁定宝箱(加密). 其他人无法用相同的公钥打开(解密)宝箱. 只有私钥才能打开箱子. 它被广泛使用, 尤其是 TLS/SSL, 它使 HTTPS 成为可能.
非对称加密图解. 它使用不同的密钥进行加密和解密.
散列函数: 顾名思义, 散列函数是一种算法, 可以接受任何输入并生成散列值. 无论输入大小如何, 输出哈希值的大小总是固定的. 例如, MD5 算法的输出哈希值大小为128 位或16 字节. 值得注意的是, 哈希函数是单向操作, 这意味着我们只能加密数据, 而不能解密, 这与对称密钥和非对称密钥算法不同.
生成哈希值的过程称为哈希. 为简单起见, 我使用了加密/解密, 但一般来说, 散列和加密有不同的含义.
如果不能解密, 我们为什么需要散列函数呢? ) 在某些情况下, 我们只需要哈希值. 例如, 我们可以用它们来安全地存储密码. 与其保存实际密码, 不如保存密码的哈希值. 登录时, 我们将根据存储的哈希值检查输入密码的哈希值.
散列生成(散列)示例
Android密码学API提供了一系列类和接口, 允许我们在应用程序中实现密码操作. 我们来看看 MessageDigest
和 Cipher
.
来自 java.security
的 MessageDigest
类提供了一种实现散列函数的方法. 我们可以使用它为数据生成哈希值, 使用的哈希算法包括 MD5, SHA-1, SHA-256 等.
密码学中的“密码”是一组允许我们加密和解密数据的规则. 密码通过将原始明文或其他数据处理成密文来转换数据. 密文应显示为随机数据. 我们可以使用 javax.crypto
中的 Cipher
类来实现这些目的.
我将举一个使用 MD5(Message-Digest) 算法生成哈希值的小例子.
我们将在下一部分讨论
Cipher
类.
首先, 我们需要获取MessageDigest
实例, 并将相应的algorithm作为参数.
val md = MessageDigest.getInstance("MD5")
我们将使用MessageDigest
的public byte[] digest(byte[] input)
方法为输入生成哈希值. 如你所见, 该方法接收字节数组形式的输入, 并返回相同的值. 我们可以将用户的输入转换成字节数组, 然后调用 digest
函数为输入生成哈希值. 假设用户输入了一些文本, 我们要为其生成一个哈希值.
val inputBytes: ByteArray = userInput.encodeToByteArray()
val hashData: ByteArray = md.digest(inputBytes)
这个 hashData
就是生成的哈希值. 让我们来看看完整的函数.
private const val MD5_ALGORITHM = "MD5"
@Throws(NoSuchAlgorithmException::class, NullPointerException::class)
fun String.generateMD5Hash(): String {
val md = MessageDigest.getInstance(MD5_ALGORITHM)
val inputBytes: ByteArray = this.encodeToByteArray()
val hashData: ByteArray = md.digest(inputBytes)
return hashData.toHex()
}
为了简单起见, 我为 String
创建了一个扩展函数, 用于生成哈希值. MessageDigest.getInstance(String)
函数可能会抛出异常, 因此我们需要处理它们. 这就是我们用 @Throws
对函数进行注解的原因.
该函数将 String
作为输入, 并返回 String
. 为避免输出中出现无法识别的字符, 我们使用 toHex()
函数将ByteArray
转换为人类可读的十六进制String
.
fun ByteArray.toHex(): String {
return joinToString("") { "%02x".format(it) }
}
但一般来说, 你应该只使用 ByteArray
. 因此, 让我们测试一下我们的代码, 看看它是否有效.
fun main() {
val inputText = "Let's encrypt this message with MD5"
// You should apply error handling as this function may through an exception
val hashValue = inputText.generateMD5Hash()
println("#1 Generated hash is: $hashValue")
val anotherInput = "Completely another message, could be song lyrics"
val anotherHashValue = anotherInput.generateMD5Hash()
println("#2 Generated hash is: $anotherHashValue")
}
运行代码后, 我们将在控制台看到以下输出:
#1 Generated hash is: 867cf9069b40121f451b22013ec03e54
#2 Generated hash is: a2860d6a8d92c785067fc5ad081081f4
如前所述, MD5 算法的哈希值大小为128 位或16 字节. 如果我们看一下输出结果, 就会发现十六进制字符串长度为32个字符. 由于十六进制字符串中的每对字符代表一个字节, 因此我们的哈希值大小为 16 字节.
MessageDigest (MD5) 示例
一家之言, 欢迎斧正!
Happy Coding! Stay GOLDEN!