非對稱加密
1. 對稱加密的弊端
祕鑰分發困難
可以通過非對稱加密完成祕鑰的分發
https
Alice 和 Bob通訊, Alice給bob傳送資料, 使用對稱加密的方式
- 生成一個非對稱的祕鑰對, bob生成
- bob將公鑰傳送給alice
- alice生成一個用於對稱加密的祕鑰
- alice使用bob的公鑰就對稱加密的祕鑰進行加密, 並且傳送給bob
- bob使用私鑰就資料解密, 得到對稱加密的祕鑰
- 通訊的雙方使用寫好的祕鑰進行對稱加密資料加密
2. 非對稱加密的祕鑰
- 不存在祕鑰分發困難的問題
2.1 場景分析
資料對誰更重要, 誰就拿私鑰
直觀上看: 私鑰比公鑰長
使用第三方工具生成金鑰對: 公鑰檔案xxx.pub xxx
- 通訊流程, 資訊加密 (A寫資料, 傳送給B, 資訊只允許B讀)
A: 公鑰
B: 私鑰
- 登入認證 (客戶端要登入, 連線伺服器, 向伺服器請求個人資料)
客戶端: 私鑰
伺服器: 公鑰
- 數字簽名(表明資訊沒有受到偽造,確實是資訊擁有者發出來的,附在資訊原文的後面)
- 傳送資訊的人: 私鑰
- 收到資訊的人: 公鑰
- 網銀U盾
- 個人: 私鑰
- 銀行拿公鑰
3. 使用RSA非對稱加密通訊流程
要求: Alice 給 bob傳送資料, 保證資料資訊只有bob能看到
4. 生成RSA的祕鑰對
4.1 一些概念
- x509證照規範、pem、base64
pem編碼規範 - 資料加密
base64 - 對資料編碼, 可逆
不管原始資料是什麼, 將原始資料使用64個字元來替代
a-z A-Z 0-9 + /
ASN.1抽象語法標記
PKCS1標準
4.2 金鑰對生成流程
- 生成私鑰操作流程概述
- 使用rsa中的GenerateKey方法生成私鑰
func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error)
- rand.Reader -> import “crypto/rand”
- 1024 的整數倍 - 建議
- 通過x509標準將得到的ras私鑰序列化為ASN.1 的 DER編碼字串
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
- 將私鑰字串設定到pem格式塊中
初始化一個pem.Block塊
type Block struct {
Type string // 得自前言的型別(如"RSA PRIVATE KEY")
Headers map[string]string // 可選的頭項
Bytes []byte // 內容解碼後的資料,一般是DER編碼的ASN.1結構
}
- 通過pem將設定好的資料進行編碼, 並寫入磁碟檔案中
func Encode(out io.Writer, b *Block) error
- out - 準備一個檔案指標
- 生成公鑰操作流程
- 從得到的私鑰物件中將公鑰資訊取出
type PrivateKey struct {
PublicKey // 公鑰
D *big.Int // 私有的指數
Primes []*big.Int // N的素因子,至少有兩個
// 包含預先計算好的值,可在某些情況下加速私鑰的操作
Precomputed PrecomputedValues
}
- 通過x509標準將得到 的rsa公鑰序列化為字串
func MarshalPKIXPublicKey(pub interface{}) ([]byte, error)
- 將公鑰字串設定到pem格式塊中
type Block struct {
Type string // 得自前言的型別(如"RSA PRIVATE KEY")
Headers map[string]string // 可選的頭項
Bytes []byte // 內容解碼後的資料,一般是DER編碼的ASN.1結構
}
- 通過pem將設定好的資料進行編碼, 並寫入磁碟檔案
func Encode(out io.Writer, b *Block) error
5. RSA加解密
5.1 RSA加密
- 將公鑰檔案中的公鑰讀出, 得到使用pem編碼的字串
– 讀檔案
- 將得到的字串解碼
– pem.Decode
- 使用x509將編碼之後的公鑰解析出來
– func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)
- 使用得到的公鑰通過rsa進行資料加密
5.2 RSA解密
將私鑰檔案中的私鑰讀出, 得到使用pem編碼的字串
將得到的字串解碼
使用x509將編碼之後的私鑰解析出來
使用得到的私鑰通過rsa進行資料解密
6. 雜湊演算法
6.1 概念
稱謂: 單向雜湊函式, 雜湊函式, 雜湊函式, 訊息摘要函式
接收的輸入: 原像
輸出: 雜湊值, 雜湊值, 指紋, 摘要
6.2 單向雜湊函式特性
將任意長度的資料轉換成固定長度的資料
很強的抗碰撞性
不可逆
MD4/MD5
不安全
雜湊值長度: 128bit == 16byte
- sha1
不安全
雜湊值長度: 160bit == 20byte
- sha2 - 安全
sha224
雜湊值長度: 224bit == 28byte
sha256
雜湊值長度: 256== 32byte
sha384
雜湊值長度: 384bit == 48byte
sha512
雜湊值長度: 512bit == 64byte
6.3 go中使用單向雜湊函式
// 第一種方式, 直接呼叫sum
// 適用於資料量比較小的情況
func Sum(data []byte) [Size]byte
// 第二種方式
// 1. 建立雜湊介面物件
func New() hash.Hash
type Hash interface {
// 通過嵌入的匿名io.Writer介面的Write方法向hash中新增更多資料,永遠不返回錯誤
io.Writer
// 返回新增b到當前的hash值後的新切片,不會改變底層的hash狀態
Sum(b []byte) []byte
// 重設hash為無資料輸入的狀態
Reset()
// 返回Sum會返回的切片的長度
Size() int
// 返回hash底層的塊大小;Write方法可以接受任何大小的資料,
// 但提供的資料是塊大小的倍數時效率更高
BlockSize() int
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// 2. 往建立出的雜湊物件中新增資料
hash.Hash.Write([]byte("新增的資料..."))
hash.Hash.Write([]byte("新增的資料..."))
hash.Hash.Write([]byte("新增的資料..."))
hash.Hash.Write([]byte("新增的資料..."))
// 3. 計算結果, md5就是雜湊值
md5 := hash.Sum(nil);
// 雜湊值一般是一個二進位制的字串, 有些字元不可見, 需要格式化
// 格式化為16進位制的數字串 - 0-9, a-f
func EncodeToString(src []byte) string
// 資料轉換完成之後, 長度是原來的2倍
計算一個大檔案比如1G檔案的雜湊值
使用udp的方式分發祕鑰, 進行一個對稱加密的通訊
伺服器
生成金鑰對
公鑰傳送給客戶端
客戶端
客戶端收到了公鑰
生成一個祕鑰 - 用於對稱加密
使用公鑰加密, 傳送給伺服器
複習
- 概念
加密三要素
明文/密文
祕鑰
演算法
對稱加密和非對稱加密
對稱加密: 加解密使用同一個祕鑰, 1個
效率高
非…: 金鑰對
公鑰加密, 私鑰解密
私鑰加密, 公鑰解密
對稱加密中的公開的加密演算法
des
分組長度: 8位元組
祕鑰長度: 8位元組
3des
分組長度: 8位元組
祕鑰長度: 24byte
aes
分組長度: 16位元組
祕鑰長度: 16位元組, 24位元組, 32位元組
在go的api中只能使用16位元組
對稱加密的分組模式
EBC - 不推薦使用
CBC - 常用的方式
準備的資料:
初始化向量iv - 字元陣列
長度 == 明文分組長度
加解密初始化向量值必須相同
祕鑰
根據加密演算法定
===========================
OFB - 不推薦使用
CFB - 不推薦使用
CTR - 推薦使用, 效率最高
禁止 學習某地爬蟲,知乎爬蟲,CSDN 爬蟲。
本文,首發在 learnku 社群。
@author
汪春波(www.shxdledu.cn)
本作品採用《CC 協議》,轉載必須註明作者和本文連結