今天没有编码,还是属于纯理论的东东,概念也比较多,但是实际真正完全理解它们的人不多,也很重要,这些东东在实际中也经常被用到,但需要真正理解了才能正确的使用它们,这里列一下相关司:MD5、SHA1、RSA、DSA、AES、BASE64、encoded URL、Unicode、UTF-8、GBK、ISO-8859-1..........一看都眼熟,但是它们具体哪个场合去用它们还是比较难理清的,所以这次的目的就是彻底理清这些东东。

加密解密 Entryption & Decryption:

古典密码学:

起源于古代战争:在战争中,为了防止书信被截获后重要信息泄露,人们开始对书信进行加密。


  • 移位式加密:

如密码棒,使⽤布条缠绕在⽊棒上的方式来对书信进行加密,该密码棒长这样:
编码、加密、Hash_非对称加密

该密码棒的规格是严密定制的,也就是通信双方都有一样规格的密码棒,然后缠绕布条后进行书写,写好之后再将布条给拆掉,这样既使中途被敌人接活了布条,敌人也看不懂具体意思,这样也就达到了加密的效果。所以可以简单规纳一下:

加密算法:缠绕后书写
密钥:木棒的尺寸



替换式加密:

按规则使用不同的文字来替换掉原先的文字来进行加密,具体举个例子:
编码、加密、Hash_数据_02
也就是密码字符基于原始字符做了一个移位,然后将原始字符对应成密码字符也就对原内容进行了加密,然后对方就可以根据码表则将加密的字符进行还原,所以简单归纳:
加密算法:替换文字。
密钥:替换的码表。



现代密码学:【有了计算机之后】
不止可以用于文字内容,还可以用于各种二进制数据。


  • 对称加密:
    原理:使用密钥和加密算法对数据进行转换,得到的无意义数据为密文;使用密钥和解密算法对密文进行逆向转换,得到原数据。

通信双方使用同一个密钥,使用加密算法配合上密钥来加密,解密时使用加密过程的完全逆过程配合密钥来进⾏解密。

简化模型即上面的古典密码学中替换式加密的模型:对文字进行规则化替换来加密,对密文进行逆向的规则化替换来解密。

用图来表述一下:
编码、加密、Hash_数据_03

此时对方拿到密文则进行解密,如下:
编码、加密、Hash_非对称加密_04

这种加密有两个经典算法:

DES(56 位密钥,密钥太短而逐渐被弃⽤)、AES(128 位、192 位、256 位密钥,现在最流行)

它的作用

加密通信,防⽌信息在不安全⽹络上被截获后,信息被人读取或篡改。

另外对称加密是可以被破解的,其破解思路
        ①、拿到一组或多组原文-密文对。

        ②、设法找到一个密钥,这个密钥可以将这些原文-密文对中的原文加密为密文,以及将密⽂解密为 原文的组合,即为成功破解。
有破解就有反破解

一种优秀的对称加密算法的标准是,让破解者找不到⽐穷举法(暴力破解法)更有效的破解手段,并且穷举法的破解时间⾜够长(例如数千年)。
另外它也是有缺点的:密钥泄露:不能在不安全⽹络上传输密钥,⼀旦密钥泄露则加密通信失败。



非对称加密【重点】:

原理:使⽤公钥对数据进行加密得到密文;使⽤私钥对数据进行解密得到原数据。 ⾮对称加密使用的是复杂的数学技巧,在古典密码学中没有对应的原型。

用图表来表述一下:
编码、加密、Hash_对称加密_05
居然是用同一个算法应用了不同的钥匙就能达到解密的效果,那怎么做到的呢?这里举一个简单的例子用来理解它的原理,但并非是真正非对称加密所采用的,如下:
比如我们只能输入这些数字:0123456789,然后我遇到危险了想写110,但肯定不能名文,所以采用非对称加密,其加密规则如下:
加密算法:对数字位进行加法。
公钥:数字加4。
私钥:数字加6。
所以110加密的密文就为:
编码、加密、Hash_对称加密_06

此时对方则需要将554进行解密,还是使用相同的加密算法对数字位进行加法操作,只是这次是用私钥来进行加法,私钥需要加6,所以加完之后会变成:
编码、加密、Hash_数据_07

所以非对称加密会有溢出的处理。

使⽤⾮对称加密通信,可以在不可信网络上将双方的公钥传给对方,然后在发消息前分别对消息使用 对⽅的公钥来加密和使用⾃己的私钥来签名,做到不可信网络上的可靠密钥传播及加密通信。下面再来举个场景:
编码、加密、Hash_对称加密_08

这样就可以大胆的将公钥在网络上进行传输,所以可以大胆的告诉对方公钥信息,如下:
编码、加密、Hash_非对称加密_09

然后A给B发送数据,则用公钥B对数据进行加密发送给B,此时B就可以用私钥B对密文进行解密了,同样的如果B给A发也是雷同,那假如公钥B和公钥A被C给截获到了,如下:
编码、加密、Hash_对称加密_10

那他拿了公钥信息也解不了密文的,所以非对称加密的一个核心就是私钥一定得要自己拿着,不能公开。

那用公钥能解出私钥加密内容么?其实是可以的,下面图解一下:
编码、加密、Hash_数据_11

编码、加密、Hash_对称加密_12

编码、加密、Hash_对称加密_13

然而描述的这个步骤刚好就是它:

编码、加密、Hash_非对称加密_14
所以很显然是可以用公钥解私钥加密的内容,由于私钥和公钥互相可解,因此非对称加密还可以应用于数字签名技术。具体表现如下:
编码、加密、Hash_数据_15

所以可以发现加密和数字签名的区别在于:加密是使用公钥加密,用私钥验证,而数字签名则是相反的,用私钥加密,公钥解密,需要注意一下它们之间的区别。

直接对原数据签名会导致原数据不可读,所以通常会对原数据 hash 以后对 hash 签名,然后附加在原数据的后面作为签名,所以完整版的签名与验证就为:
编码、加密、Hash_对称加密_16
另外对于加密和签名可以混合着使用,变形如下:
编码、加密、Hash_非对称加密_17
这里还需回过头来说一种情况,就是我们知道在非对称加密中对外公开了公钥信息,如下:
编码、加密、Hash_数据_18

但是!!!第三方拿到了公钥信息之后是可以对数据进行伪装的呢?如:
编码、加密、Hash_非对称加密_19

这里就可以用公钥加密+私钥解密的方式,具体如下:
编码、加密、Hash_非对称加密_20

经典算法:RSA(可用于加密和签名)、DSA(仅用于签名,但速度更快) 
非对称加密的优缺点:
优点:可以在不安全网络上传输密钥。
缺点:计算复杂,因此性能相比对称加密差很多。
非对称加密的破解:

和对称加密不同之处在于,非对称加密的公钥很容易获得,因此制造原文-密文对是没有困难的事。 所以,⾮对称加密的关键只在于,如何找到一个正确的私钥,可以解密所有经过公钥加密过的密文。找到这样的私钥即为成功破解。 由于⾮对称加密的⾃身特性,怎样通过公钥来推断出私钥通常是一种思路(例如 RSA),但往往最佳手段依然是穷举法,只是和对称加密破解的区别在于,对称加密破解是不断尝试自⼰的新密钥是否可以将⾃⼰拿到的原文-密文对进行加密和解密,而⾮对称加密时不断尝试⾃⼰的新私钥是否和公钥互相可解。非对称加密的反破解:和对称加密⼀样,非对称加密算法优秀的标准同样在于,让破解者找不到⽐穷举法更有效的破解手段,并且穷举法的破解时间⾜够⻓。




密码学密钥和登录密码:


  • 密钥(key)

场景:⽤于加密和解密。

目的:保证数据被盗时不会被人读懂内容。

焦点:数据。


登录密码(password)

场景:用户进⼊⽹站或游戏前的身份验证。
目的:数据提供方或应用服务方对账户拥有者数据的保护,保证「你是你」的时候才提供权限。 焦点:身份。



Base64:

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

什么是二进制数据呢?

广义:所有计算机数据都是二进制数据。 狭义:非⽂本数据即二进制数据。

算法: 将原数据每 6 位对应成 Base 64 索引表中的一个字符编排成一个字符串(每个字符 8 位)。 Base64 索引表:

编码、加密、Hash_数据_21

编码示例:把「Man」进行 Base64 编码

编码、加密、Hash_数据_22

那为啥要取6位二进制位,而非8位呢?因为2的6次方刚好是64,如果大于6位那不大于64了,那不大于64的数据无法对应Base64的字符了,所以。。

另外需要注意:Base64转换之后会比原数据的体积要大,从现象就可以看出:

编码、加密、Hash_数据_23

编码示例:Base64的末尾补足:

编码、加密、Hash_数据_24

用途:

1. 将二进制数据扩充了储存和传输途径(例如可以把数据保存到⽂本⽂件、可以通过聊天对话框或 短信形式发送⼆进制数据、可以在 URL 中加入简单的⼆进制数据)。

2. 普通的字符串在经过 Base64 编码后的结果会变得⾁眼不可读,因此可以适用于⼀定条件下的防偷窥(较少用)。

缺点:

因为⾃身的原理(6 位变 8 位),因此每次 Base64 编码之后,数据都会增⼤约 1/3,所以会影响存储和传输性能。

「Base64 加密图⽚传输更安全和高效」???

不。首先,Base64 并不是加密;另外,Base64 会导致数据增大 1/3,降低⽹络性能,增⼤用户流量开销,是画蛇添足的手段。(最好不要拿来 diss 你们公司的后端哟,友善),Base64 对图片进⾏编码的⽤途在于,有时需要使用文本形式来传输图片。除此之外,完全没必要使用 Base64 对图片进行额处理。

变种:Base58:

⽐特币使用的编码⽅式,去掉了 Base64 中的数字 "0",字母⼤写 "O",字母⼤写 "I",和字母⼩写 "l",以及 "+" 和 "/" 符号,⽤于⽐特币地址的表示。

Base58 对于 Base64 的改动,主要⽬的在于⽤户的便捷性。由于去掉了难以区分的字符,使得 Base58 对于「人工抄写」更加⽅便。另外,去掉了 "+" "/" 号后也让大多数的软件可以方便双击选取。

URL encoding:

在 URL 的字符串中,对一些不⽤于特殊用途的保留字符,使⽤百分号 "%" 为前缀进行单独编码,以避免出现解析错误。

例如,要在 http://hencoder.com/users 后⾯添加查询字符串,查询 name 为「隐匿匿&伟⼤大」的⽤户,如果直接写成 http://hencoder.com/user/?name=隐匿&伟大 ,"&" 符号就会被解析为分隔符号,因此需要对它进行转码,转码后的 URL 为 http://hencoder.com/user/?name=隐匿%26伟大 。

这种编码仅用于 URL,⽬的是避免解析错误的出现。

压缩与解压缩 Compression & Decompression:


含义:

压缩:把数据转换一种方式来存储,以减小存储空间。

解压缩:把压缩后的数据还原成原先的形式,以便使用。

目的:

减小数据占用的存储空间。

常见的压缩算法:

DEFLATE、JPEG、MP3 等。

压缩是编码吗?

是。所谓编码,即把数据从一种形式转换为另一种形式。压缩过程属于编码过程,解压缩过程属于解码过程。

图片与音频、视频编解码:含义:

将图像、音频、视频数据通过编码来转换成存档形式(编码),以及从存档形式转换回来(解码)。

目的:

存储和压缩媒体数据(⼤多数媒体编码算法会压缩数据,但不是全部)。

图片压缩粗暴算法举例:

⼀张纯白(⽩色的 16 进制数值为 0xffffff)的 64x64 不透明像素图片,原数据格式⼤大致为:

编码、加密、Hash_对称加密_25

使⽤某种算法压缩后的数据为:

编码、加密、Hash_非对称加密_26

注:具体的压缩场景有很多,因此压缩算法也会复杂得多,上面只是一个原型算法。 音频与视频的编码与上面的图片编码同理。

序列化 Serialization:

把数据对象(一般是内存中的,例例如 JVM 中的对象)转换成字节序列的过程。对象在程序内存里的存放形式是散乱的(存放在不同的内存区域、并且由引用进行连接),通过序列化可以把内存中的对象转换成⼀个字节序列,从而使用 byte[] 等形式进行本地存储或⽹络传输,在需要的时候重新组装(反序列化)来使用。

目的:

让内存中的对象可以被储存和传输。

序列列化是编码吗?

不是,编码是把数据由一种数据格式转换成另⼀种数据格式;而序列化是把数据由内存中的对象(⽽不是某种具体的格式)转换成字节序列。

哈希 Hash:

定义:

把任意数据转换成指定大小范围(通常很⼩,例如 256 字节以内)的数据。

作用:

相当于从数据中提出摘要信息,因此最主要用途是数字指纹。

经典算法:


MD5、SHA1、SHA256等。

举例说明Hash的本质:

写一个简单的Hash的算法,当然只是为了说明Hash的一个原理,并非真实的实现,比如定义这么一个hash实现的方法:

编码、加密、Hash_对称加密_27

然后咱们对这样两个字符串进行hash的结果如下:

编码、加密、Hash_对称加密_28

但是!!!咱们这个碰撞率比较高,也就是说很容易重,比如:

编码、加密、Hash_对称加密_29

这就是由于咱们的这个hash算法是比较low,成熟的碰撞率会比较低的。

实际用途:


  • 数据完整性验证:
    从⽹络上下载⽂件后,通过比对⽂件的 Hash 值(例如 MD5、SHA1),可以确认下载的⽂件是否有损坏。如果下载的⽂件 Hash 值和⽂件提供⽅给出的 Hash 值一致,则证明下载的⽂件是完好⽆损的。
  • 快速查找:
    hashCode()和HashMap,在我们学j2se时教科书上通常会说重写了类的equals()方法,就一定要重写类的hashCode()方法,为啥呢?下面来用例子来阐述一下,对于这个类重写了equals()方法:
    编码、加密、Hash_非对称加密_30
    然后按照教科书式的要求又重写了hashCode()方法:
    编码、加密、Hash_数据_31

当然此时的hashCode是比较脆弱,很容易发生碰撞,不过这里重点是为了理解为啥重写了equals()方法之后一定要重写hashCode()方法呢?这就要说到HashMap了,在存数据时是根据对象的hashCode()来进行内存的存储的,如果对象木有重写hashCode()则会默认用Object的默认hashCode()的实现,那就在使用HashMap存对象时会出BUG,对于两个不同的对象由于hashCode()是一样导致值被替换了,所以重写hashCode()是为了给Hash相关的存储对象来使用的,如果对象不会被存储到Hash相关的存储对象中,那确实是木有必要重写hashCode(),但!!谁又能保证你定义的对象不被存储到Hash相当的集合当中呢?所以,保险起见重写了equals()之后,一定要重写hashCode()。


隐私保护:
当重要数据必须暴露的时候,有时可以选择暴露它的 Hash 值(例如 MD5),以保障原数据的安全。 例如网站登录时,可以只保存用户密码的 Hash 值,在每次登录验证时只需要将输入的密码的 Hash 值和数据库中保存的 Hash 值作比对就好,⽹站⽆需知道⽤户的密码。这样,当⽹站数据失窃时,⽤户不会因为⾃⼰的密码被盗导致其他网站的安全也受到威胁。

Hash是编码吗?

不是。 Hash 是单向过程,往往是不可逆的【因为只是抽取了对象的一些特征,比如一个图片是1MB,但是它的hash只是1k,怎么可能从1k还原成1MB的图片原数据呢?】,⽆法进行逆向恢复操作,因此 Hash 不属于编码。

Hash是加密吗?据说MD5是“不可逆加密”?

不是。Hash 是单向过程,无法进行逆向恢复操作,因此 Hash不属于加密。(记住,MD5 不是加密!),但是百度百科说它是一种加密,如:

编码、加密、Hash_对称加密_32

这是错误的!!!所以说“不可逆加密”的说法也不正确。

知道了Hash的概念之后,这里就要回过头来说一下非对称加密的,先回顾一下:

编码、加密、Hash_数据_33

其中标红的“签名数据”的大小跟原数据是一样的大的,如果一个10G的视频文件,它的签名数据有10G那么大,那显得太臃肿了,所以事实上会对原数据的hash值进行签名,完整版的非对称加密如下:

编码、加密、Hash_对称加密_34

编码、加密、Hash_非对称加密_35


字符集 Charset:

含义:

一个由整数向现实世界中的文字符号的Map。

分支:



  • ASCII:128 个字符,1 字节。
  • ISO-8859-1:对 ASCII 进行扩充,1 字节
  • Unicode:13 万个字符,多字节。
    1、UTF-8:Unicode 的编码分⽀。

2、UTF-16 :Unicode 的编码分⽀。 

啥叫“编码分支”呢?下面举个浅显一点的例子说明一下:
编码、加密、Hash_非对称加密_36

每个字对应一个8位的字节数,但是可能UTF-8的表示法不会表示全,可能会这样写:
编码、加密、Hash_对称加密_37

也就是省略了一些位,而对于UTF-16可能会表示成这样:
编码、加密、Hash_对称加密_38

当然上面的举例不是太严谨,对于UTF-16很显然是用16位表示一个字符,没有上面例子中写得这么短,但只是为了说明一下“编码分支”这个词的意思。


GBK / GB2312 / GB18030:中国自研标准,多字节,字符集 + 编码。