加密、签名与编码

密码学

古典密码学

从密码学开始说起,密码学的起源是古代战争。那个时候的密码学,现在被称为"古典密码学"。

古代战争中,两个国家之间经常需要进行书信沟通。为了防止信息泄露,古人发明了密码学,来对书信内容进行加密。

加密方式主要有:

  • 置换式加密 : 典型的代表是密码棒

    密码棒的规格就是加密和解密的关键。当需要书写密信时,就将纸条缠绕到木棒上进行书写;当需要解读密信时,就将纸条绕到同样规格的棒子上进行阅读。如果单独将纸条拿出来阅读,只会看到一串乱序的文本。

    密码棒虽然简单,但已包含了密码学的两个重要元素:

    • 加密算法: 缠绕到木棒上进行书写

    • 密钥: 木棒的规格

  • 替换式加密: 按照一个固定的规则,使用不同的文字替换掉原先的文字。最简单的方法就是将字母表整体移动几位,从而产生一个码表,让原文与密文形成映射关系。例如:

    kotlin 复制代码
    // 码表(向右平移5位)
    ABCDEFGHIJKLMNOPQRSTUVWXYZ  // 原始字符
    FGHIJKLMNOPQRSTUVWXYZABCDE  // 密码字符
    
    // 原文
    I love you.
    // 密文
    N qtaj dtz.

    此时,加密算法是替换文字,而密钥则是这张码表。

现代密码学

随着计算机出现,一些复杂的数学算法被应用在了加密上,就出现了"现代密码学"。

现代密码学使用数学算法对计算机数据进行加密,不止可以加密文字,还可以加密任何的二进制数据

现代密码学主要有两类:对称加密和非对称加密。

对称加密

原理: 使用密钥和加密算法对数据进行转换,得到密文;在使用密钥和解密算法对密文进行逆向转换,得到原数据。

与古典密码学不同,现代密码学中的密文会在网络中传输,无论如何都会被截获,所以更加注重反破解。

对称加密的经典算法有: DES、AES。

其中 DES 因密钥太短已被弃用(只有 56 位),在很短时间(一天)内就能够通过穷举法试出密钥。

非对称加密

对称加密有一个缺点:密钥无法安全地发送给对方。密钥在非安全的网络上传输,一旦泄露,加密就没有了意义。为此,就有了非对称加密。

非对称加密的原理: 创建一对密钥:公钥和私钥,分别来加密和解密。公钥是公开的,可以发送给任何人;私钥是保密的,只能自己持有。

这样一来,通信的过程也就安全了。比如 A 要给 B 发送消息,A 就可以使用 B 的公钥对消息进行加密,B 收到后再使用自己的私钥对密文进行解密。即使公钥和密文都被第三方拿到了,第三方也无法解密,因为没有 B 的私钥。

这样虽然安全,但是只能单向通信。要实现双向通信,解决办法也很简单,就是通信双方各自创建一对密钥,然后互相交换公钥即可。

非对称加密还可以用于做数字签名。这是因为非对称加密具有一个特性:公钥加密后的密文,可以使用私钥来解密;反过来,私钥加密后的密文,公钥同样能解。

这是为什么呢?因为 [原数据] 能够通过公钥得到 [密文][密文] 能够通过私钥得到 [原数据] 。我们如果将 [密文] 看作 [原数据] ,将 [原数据] 看作 [密文] 。这样不就变为了: [原数据] 能够通过私钥得到 [密文][密文] 能够通过公钥得到 [原数据]

需要注意的是,虽然公钥和私钥看似可以调换位置,但从诞生时就已经决定了谁是私钥,谁是公钥。因为公钥很多时候是可以通过私钥计算出的,例如比特币的密钥算法叫做椭圆曲线算法,当选定了某个私钥后,其对应的公钥也随之确定了。如果你将私钥当作公钥公开,把公钥当私钥保存,其实每个人都可以通过你公开的所谓"公钥"计算出你手中所谓的"私钥"。

数字签名的原理:

使用私钥对数据进行加密,得到的加密数据就被称为签名数据。只要对方能够使用公钥对签名数据进行解密得到原数据,那么就验证了签名的真实性。为了方便进行验证,在使用时通常会携带上原数据。

这样验证时,只需对签名数据通过公钥进行解密,如果得到的和附带的原数据一致,那么就说明验证成功。

现在,我们回头看看之前的非对称加密通信模型。它虽然可以防止第三方得到原数据,但防不了第三方做消息伪造。第三方可以冒充 A,使用 B 的公钥加密假信息发送给 B,B 是无法辨别消息真伪的。

要解决这个问题,就需要在加密数据的同时,加上数字签名,防止信息的伪造。

不过,直接对原文进行签名是有漏洞的:别人虽然不能拿到 [对方私钥] 解开密文,但可以使用 [公钥] 验证签名数据,这样原数据就泄露了。

以上的加密、签名过程,还少了一个对数据进行 Hash 的过程。

Hash(哈希)的作用是将任何数据都变为一串固定长度的、独特的"指纹"(摘要)。这个过程是单向的,无法从指纹得到原文。

所以,正确的做法是:发送方先对原数据 进行 Hash 运算,得到一个固定长度的摘要 。然后使用自己的私钥对这个摘要进行签名。再使用对方的公钥加密原数据 ,得到密文。最后将密文和签名发送给对方。

如图所示:

这样,即使第三方使用公钥验证签名,得到了也不会是原数据,而是原数据的摘要,避免了信息泄露。另外,接受方也可以通过比对 Hash 值来验证原数据的完整性。

非对称加密的经典算法有 RSA 和 DSA。其中 RSA 可用于加密和签名,而 DSA 只能用来签名。这是因为 DSA 专门为签名做了优化,在签名和验证的速度上通常比 RSA 更快。

Base64

Base64 是将二进制数据转换为由 64 个字符组成的字符串的编码算法。

这 64 个字符分别是:小写字母a-z、大写字母A-Z、数字0-9、符号"+" 和 "/"。

什么是二进制数据?

广义上来说,所有计算机数据(如文本、图片)都是二进制数据;狭义上,非文本数据(如视频、图片)就是二进制数据,这种说法也是最通用的、大家最认可的。而 Base64 针对的是任意的二进制数据。

编码的过程是将二进制数据的每 6 个比特位转成一个 Base64 码表中对应的字符。例如 "Man" 编码的结果是TWFu,其原理为:
码表为:

另外,Base64 编码是每 3 个字节(24位)一组进行处理的,如果原文数据的字节数不能被 3 整除,那么会在编码后的字符串末尾使用 = 字符进行填充,使得编码后的字符串长度是 4 的倍数。

例如:

那么 Base64 编码的作用是什么?

其实它的作用是将二进制数据转换为纯文本字符串,使其能够在只支持文本的场景下使用。比如可以将图片保存到文本文件中;可以通过邮件传输图片(之前的邮件中不能传输图片)。

最后补充一点,使用 Base64 来传输图片,一点也不高效和安全。

  • 不安全: 因为 Base64 并不是加密算法,只是一种编码,其编码规则是公开的,任何人都可以进行解码。

  • 不高效: 通过它编码后的数据体积会增大至少 1/3,存储和传输都会变得更低效(更慢、更耗资源)。

URL encoding

这种编码也就是我们在浏览器的地址栏中看到的编码,它会将 URL 中的保留字符(如空格、&?)使用 % 百分号进行编码。

比如访问 http://www.example.com/这是示例 网址时,其中的 URL 实际上会变为 http://www.example.com/%E8%BF%99%E6%98%AF%E7%A4%BA%E4%BE%8B

URL 编码的作用是消除歧义,避免解析错误 。比如要表示一个 / 字符本身,而不是当做路径分隔符时,我们就可以使用 %2F 来代替。

相关推荐
李新_4 小时前
【Android Bug Fix】UI不响应、异位异常排查
android·程序员
帅得不敢出门5 小时前
Android Framework定制长按电源键关机的窗口
android·java·framework
爬山算法5 小时前
MySQL(191) 如何优化MySQL的磁盘I/O?
android·数据库·mysql
深盾安全8 小时前
Kotlin Data Classes 快速上手
android
一枚小小程序员哈9 小时前
安卓\android程序开发之基于 Android 的校园报修系统的设计与实现
android
用户20187928316710 小时前
🌟 一场失败的加密舞会:SSL握手失败的奇幻冒险
android
tangweiguo0305198711 小时前
面向对象编程三剑客:Dart、Java 和 Kotlin 的核心区别
android·flutter·kotlin
幼稚园的山代王12 小时前
Kotlin数据类型
android·开发语言·kotlin
xixixin_12 小时前
【H5】禁止IOS、安卓端长按的一些默认操作
android·css·ios·h5