第一章 密碼學
第一節 密碼介紹
一、為什么要加密?
保證資料的安全
小明–>小紅:
-
原文:放學后,學校后門小樹林見
-
密鑰:+2
-
密文:讓他放引入學恩替后,潤如學請問校嗯嗯后學校門抽成小版本樹版本林你能見
-
密鑰(密碼):-2
-
解密:讓他放引入學恩替后,潤如學請問校嗯嗯后學校門抽成小版本樹版本林你能見
-
- 放學后,學校后門小樹林見
二、常見的幾種加密演算法
1.編碼解碼
2.哈希加密
3.對稱加密
4.非對稱加密
5.數字簽名
三、加密三要素
1.明文/密文
2.密鑰
3.加密演算法/解密演算法
第二節 解碼編碼
一、常見的編碼
-
base64:26個小寫字母、26個大寫字母、10個數字、/、+
-
base58(區塊鏈):去掉6個容易混淆的,去掉0,大寫O、大寫I、小寫L、/、+(64位-6位,還剩58位)
-
- /、+影響雙擊選擇
二、go實作base64編碼、解碼
- 編碼
使用:encoding/base64
input := []byte(“hello world”)
encodeString := base64.StdEncoding.EncodeToString(input)
在url中使用:
uEnc := base64.URLEncoding.EncodeToString([]byte(input))
- 解碼
decodeBytes, err := base64.StdEncoding.DecodeString(encodeString)
在url中使用:
uDec, err := base64.URLEncoding.DecodeString(uEnc)
三、go實作base58編碼解碼、解碼
base58編碼表
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xwtlfxQk-1633784349826)(file:///C:/Users/ZHOUWE~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)]
字符1代表0,字符2代表1,…,字符z代表57
-
編碼
-
流程:
-
- 將字串的每個位元組換算成ASCII**(256進制,2^8(二進制)**),字串實際上就是256進制的數字組合
- 將256進制的數字轉換成10進制數字
- 將10進制數字轉換成58進制數字(對比10進制轉2進制,不斷取余,0用編碼1來代表)
- 將58進制數字對照58編碼表找到對應的字符
-
256進制轉十進制:
-
- h:104
- a:97
- 104*256+97=26721
-
package utils import ( "fmt" "math/big" "bytes" ) //58進制規則 var b58 = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") // base58編碼 func Base58Encoding(src string) (string) { // he : 104 101 --> 104*256 + 101 = 26725 // 26725 / 58 = 15 16 17 //1.將字串換算成ASCII碼 src_byte := []byte(src) // 轉成十進制 i := big.NewInt(0).SetBytes(src_byte) var mod_slice []byte // 回圈取余 //for i.Cmp(big.NewInt(0)) != 0 { for i.Cmp(big.NewInt(0)) > 0 { mod := big.NewInt(0) i58 := big.NewInt(58) // 取余 i.DivMod(i,i58,mod) // 將余數添加到陣列中 mod_slice = append(mod_slice, b58[mod.Int64()]) } // 把0使用位元組'1'代替 for _,s := range src_byte { if s != 0 { break } mod_slice = append(mod_slice, byte('1')) } // 反轉byte陣列 //ret_mod_slice := ReverseByteArr(mod_slice) ret_mod_slice := ReverseByteArr2(mod_slice) fmt.Println(ret_mod_slice) return string(ret_mod_slice) } // byte陣列進行反轉方式 func ReverseByteArr(b []byte) []byte{ for i:=0; i<len(b)/2;i++ { b[i],b[len(b)-1-i] = b[len(b)-1-i],b[i] } return b } // byte陣列進行反轉方式2 func ReverseByteArr2(b []byte) []byte{ for i,j:=0,len(b)-1;i<j;i,j = i+1,j-1{ b[i] ,b[j] = b[j],b[i] } return b } - 解碼 // base58解碼(將編碼流程反過來) func Base58Decoding(src string) string{ // 轉成byte陣列 src_byte := []byte(src) // 這里得到的是十進制 ret := big.NewInt(0) for _, b := range src_byte { i := bytes.IndexByte(b58,b) fmt.Println(i) // 乘回去 ret.Mul(ret,big.NewInt(58)) // 相加 ret.Add(ret,big.NewInt(int64(i))) } return string(ret.Bytes()) }
第三節 哈希演算法
一、特點
**不可逆:**無法從一個哈希值恢復原始資料,哈希并不加密
**唯一性:**對于特定的資料 只能有一個哈希 并且這個哈希是唯一的
防篡改:改變輸入資料中的一個位元組 導致輸出一個完全不同的哈希值
注冊:賬號,密碼 存到資料庫中的密碼是md5加密后的
登錄:將密碼經過md5編碼比對資料庫中的密碼
二、常用的哈希演算法
- MD4
- MD5
- hash1
- sha224
- sha256
- sha384
- sha512
性能 : md4>md5>sha224>sha256>sha384>sha512
記憶體消耗:md5>md4>sha512>sha384>sha256=sha224
建議平常使用sha256即可,安全性可靠且消耗資源不高,
三、go實作MD4加密
src_byte := []byte(src)
//md4計算
md4_new := md4.New()
md4Bytes := md4_new.Sum(src_byte)
md4String := hex.EncodeToString(md4Bytes)
四、go實作MD5加密
src_byte := []byte(src)
//md5計算
md5_new := md5.New()
md5Bytes := md5_new.Sum(src_byte)
md5String := hex.EncodeToString(md5Bytes)
五、go實作SHA256加密
func GenSha256(src string) string {
src_byte := []byte(src)
hash := sha256.New()
sha256Bytes := hash.Sum(src_byte)
sha256String := hex.EncodeToString(sha256Bytes[:])
return sha256String
}
第四節 對稱加密
一、特點
加密和解密使用的是同一個密鑰
資料私密性雙向保證,也就是加密和解密都不能泄露密碼
二、優點
加密效率高,適合大些的資料加密
三、缺點
安全性相對非對稱低
四、具體的加密方式
1. AES加密
- AES-128加密:key長度16位元組
- AES-192加密:key長度24位元組
- AES-256加密:key長度32位元組
package utils
import (
"crypto/aes"
"fmt"
"bytes"
"encoding/base64"
"errors"
)
//key可以為16,24,32位的
var key []byte = []byte("hallenhallenhall") //key首字母小寫,其他包不能參考(這里就是密鑰)
// 填充密碼長度,填充依據為,block.BlockSize(),密碼長度必須為block.BlockSize()的整數倍
func PadPwd(src_byte []byte,block_size int) []byte{
// 假設密碼長度16,區塊長度 13 需要填充個數16-13 = 10
pad_num := block_size - len(src_byte) % block_size
ret := bytes.Repeat([]byte{byte(pad_num)},pad_num) //ret是要填充的陣列成的陣列
src_byte = append(src_byte, ret...) //拼接 ret...就是取陣列中所有的值
return src_byte
}
// 加密
func AesEncoding(src string) (string,error) {
src_byte := []byte(src)
// safer
block,err := aes.NewCipher(key) //block是物件,里面是很多塊
if err != nil {
return src,err
}
// 密碼填充,加密的字串不夠block.BlockSize整數倍,要進行填充
new_src_byte := PadPwd(src_byte,block.BlockSize())
dst := make([]byte,len(new_src_byte)) //用于存放加密后的結果,這里使用切片
block.Encrypt(dst,new_src_byte) //加密dst存放結果,其為byte陣列
// base64編碼
pwd := base64.StdEncoding.EncodeToString(dst)
return pwd,nil
}
// 解密
func AesDecoding(pwd string) (string,error) {
pwd_byte := []byte(pwd)
pwd_byte,err := base64.StdEncoding.DecodeString(pwd)
if err != nil {
return pwd,err
}
block,err_block := aes.NewCipher(key)
if err_block != nil {
return pwd,err_block
}
dst := make([]byte,len(pwd_byte))
block.Decrypt(dst,pwd_byte) //解密 dst存放結果,其為byte陣列
// 填充的要去掉
dst,_ = UnPadPwd(dst)
return string(dst),nil
}
//用于解密 去掉填充的部分
func UnPadPwd(dst []byte) ([]byte,error) {
if len(dst) <= 0 {
return dst,errors.New("長度有誤")
}
// 去掉的長度 填充的值就是要填充的長度,所有取最好一個值,他肯定就是填充的長度
unpad_num := int(dst[len(dst)-1])
return dst[:(len(dst)-unpad_num)],nil //切片
}
2. des 加密:支持位元組長度是8
package utils
import (
"crypto/des"
"encoding/base64"
)
// 只支持8位元組的長度
var des_key []byte = []byte("hallenha")//key首字母小寫,其他包不能參考(這里就是密鑰)
// 加密
func DesEncoding(src string) (string,error) {
src_byte := []byte(src)
block ,err := des.NewCiphe(des_key)
if err != nil {
return src,err
}
// 密碼填充
new_src_byte := PadPwd(src_byte,block.BlockSize())
dst := make([]byte,len(new_src_byte))
block.Encrypt(dst,new_src_byte)
// base64編碼
pwd := base64.StdEncoding.EncodeToString(dst)
return pwd,nil
}
// 解密
func DesDecoding(pwd string) (string,error) {
pwd_byte,err := base64.StdEncoding.DecodeString(pwd)
if err != nil {
return pwd,err
}
block,err_block := des.NewCipher(des_key)
if err_block != nil {
return pwd,err_block
}
dst := make([]byte,len(pwd_byte))
block.Decrypt(dst,pwd_byte)
// 填充的要去掉
dst,_ = UnPadPwd(dst)
return string(dst),nil
}
3. 3des加密——CBC模式,key長度必須為24
package utils
import (
"crypto/des"
"encoding/base64"
)
// 3des的key,長度是24
var tdes_key []byte = []byte("hallenhallenhallenhallen")
// 3des加密
func TDesEncoding(src string) (string,error) {
src_byte := []byte(src)
block ,err := des.**NewTripleDESCipher**(tdes_key) // 和des的區別
if err != nil {
return src,err
}
// 密碼填充
new_src_byte := PadPwd(src_byte,block.BlockSize())
dst := make([]byte,len(new_src_byte))
block.Encrypt(dst,new_src_byte)
// base64編碼
pwd := base64.StdEncoding.EncodeToString(dst)
return pwd,nil
}
// 3des解密
func TDesDecoding(pwd string) (string,error) {
pwd_byte,err := base64.StdEncoding.DecodeString(pwd)
if err != nil {
return pwd,err
}
block,err_block := des.**NewTripleDESCipher**(tdes_key) // 和des的區別
if err_block != nil {
return pwd,err_block
}
dst := make([]byte,len(pwd_byte))
block.Decrypt(dst,pwd_byte)
// 填充的要去掉
dst,_ = UnPadPwd(dst)
return string(dst),nil
}
第五節 非對稱加密
一、特點
加密和解密的密鑰不同,有兩個密鑰(公鑰和私鑰)
公鑰:可以公開的密鑰;公鑰加密,私鑰解密
私鑰:私密的密鑰;私鑰加密,公鑰解密
私密單方向保證,只要有一方不泄露就沒問題
二、優點
安全性相對對稱加密高
三、缺點
加密效率低,適合小資料加密
四、場景分析
對哪一方更重要,哪一方就拿私鑰
- 登錄認證
私鑰在客戶端,個人資訊在客戶端保存
公鑰在服務器,獲取個人資料
假如:不成立的
? 公鑰在用戶手里
? 私鑰在服務端
- A和B兩個人,資訊只允許B閱讀
公鑰在A
私鑰在B
假如:所有人都可以閱讀
? 公鑰在B
? 私鑰在A
五、具體的加密方式
RSA:三位作者的首字母
訊息發送方利用對方的公鑰進行加密,訊息接受方收到密文時使用自己的私鑰進行解密
注意:
- 公鑰和密鑰生成的時候要有一種關聯
- 要把密鑰和公鑰保存起來
package utils
import (
"crypto/rsa"
"crypto/rand"
"fmt"
"crypto/x509"
"encoding/pem"
"os"
)
// 保存生成的公鑰和密鑰
func SaveRsaKey(bits int) (error){
//privateKey是指標結構
privateKey,err := rsa.GenerateKey(rand.Reader,bits)
if err != nil {
fmt.Println(err)
return err
}
//公鑰要和私鑰產生關聯,//privateKey是一個結構體
publicKey := privateKey.PublicKey
// 使用x509標準對私鑰進行編碼,AsN.1編碼字串
x509_privete := x509.MarshalPKCS1PrivateKey(privateKey)
// 使用x509標準對公鑰進行編碼,AsN.1編碼字串
x509_public := x509.MarshalPKCS1PublicKey(&publicKey)//這里引數為指標型別
// 對私鑰封裝block 結構資料
block_private := pem.Block{Type:"private key",Bytes:x509_privete}
// 對公鑰封裝block 結構資料
block_public := pem.Block{Type:"public key",Bytes:x509_public}
// 創建存放私鑰的檔案,檔案名后綴為.pem
privateFile,err_pri := os.Create("privateKey.pem")
if err_pri != nil {
return err_pri
}
//defer釋放資源,將檔案關閉
defer privateFile.Close()
//將私鑰寫入檔案,block_private為指標型別,取地址符獲得其內容
pem.Encode(privateFile,&block_private)
// 創建存放公鑰的檔案,檔案名后綴為.pem
publicFile,err_pub := os.Create("publicKey.pem")
if err_pub != nil {
return err_pub
}
//defer釋放資源,將檔案關閉
defer publicFile.Close()
//將公鑰寫入檔案,block_public為指標型別,取地址符獲得其內容
pem.Encode(publicFile,&block_public)
return nil
}
// 加密
func RsaEncoding(src ,file_path string) ([]byte,error){
src_byte := []byte(src)
// 打開檔案
file,err := os.Open(file_path)
if err != nil {
return src_byte,err
}
// 獲取檔案資訊
file_info,err_info := file.Stat()
if err_info != nil {
return src_byte,err_info
}
// 存盤讀取檔案內容所用的切片
key_bytes := make([]byte,file_info.Size())
// 讀取內容到容器里面
file.Read(key_bytes)
// pem解碼
block,_ := pem.Decode(key_bytes)
// x509解碼
publicKey ,err_pb := x509.ParsePKCS1PublicKey(block.Bytes)
if err_pb != nil {
return src_byte,err_pb
}
// 使用公鑰對明文進行加密
ret_byte,err_ret := rsa.EncryptPKCS1v15(rand.Reader,publicKey,src_byte)
if err_ret != nil {
return src_byte,err_ret
}
return ret_byte,nil
}
// 解密
func RsaDecoding(src_byte []byte,file_path string) ([]byte,error) {
// 打開檔案
file,err := os.Open(file_path)
if err != nil {
return src_byte,err
}
// 獲取檔案資訊
file_info,err_info := file.Stat()
if err_info != nil {
return src_byte,err_info
}
// 讀取檔案內容
key_bytes := make([]byte,file_info.Size())
// 讀取內容到容器里面
file.Read(key_bytes)
// pem解碼
block,_ := pem.Decode(key_bytes)
// x509解碼
privateKey ,err_pb := x509.ParsePKCS1PrivateKey(block.Bytes)
if err_pb != nil {
return src_byte,err_pb
}
// 進行解密
ret_byte, err_ret := rsa.DecryptPKCS1v15(rand.Reader,privateKey,src_byte)
if err_ret != nil {
return src_byte,err_ret
}
return ret_byte,nil
}
第六節 數字簽名
一、數字簽名介紹
數字簽名相當于紙質合同的簽字章蓋
防篡改、防偽裝、防否認
rsa
- 公鑰加密
- 私鑰解密
rsa數字簽名:(數字簽名與rsa加密正好相反,更具作用的目的不同)
- 私鑰簽名
- 公鑰驗證簽名
二、go實作數字簽名演算法
package utils
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"os"
)
//保存生成的公鑰和密鑰
func SaveRsaSignKey(bits int)error{
//privateKey是指標結構
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err!=nil{
return err
}
//privateKey是一個結構體,公鑰要和私鑰產生關聯
publicKey := privateKey.PublicKey
// 使用x509標準對私鑰進行編碼,AsN.1編碼字串
x509_privete := x509.MarshalPKCS1PrivateKey(privateKey)
// 使用x509標準對公鑰進行編碼,AsN.1編碼字串,引數為指標
x509_public := x509.MarshalPKCS1PublicKey(&publicKey)
// 對私鑰封裝block 結構資料
block_private := pem.Block{Type:"private key",Bytes:x509_privete}
// 對公鑰封裝block 結構資料
block_public := pem.Block{Type:"public key",Bytes:x509_public}
// 創建存放私鑰的檔案,檔案名后綴為.pem
privateFile,err_pri := os.Create("privateKey.pem")
if err_pri != nil {
return err_pri
}
//defer釋放資源,將檔案關閉
defer privateFile.Close()
//將私鑰寫入檔案,block_private為指標型別,取地址符獲得其內容
pem.Encode(privateFile,&block_private)
// 創建存放公鑰的檔案,檔案名后綴為.pem
publicFile,err_pub := os.Create("publicKey.pem")
if err_pub != nil {
return err_pub
}
//defer釋放資源,將檔案關閉
defer publicFile.Close()
//將公鑰寫入檔案,block_public為指標型別,取地址符獲得其內容
pem.Encode(publicFile,&block_public)
return nil
}
//獲取私鑰
func GetPivateKey(file_path string)(*rsa.PrivateKey,error) {
// 打開檔案
file,err := os.Open(file_path)
if err != nil {
return &rsa.PrivateKey{},err
}
// 獲取檔案資訊
file_info,err_info := file.Stat()
if err_info != nil {
return &rsa.PrivateKey{},err_info
}
// 讀取檔案內容
key_bytes := make([]byte,file_info.Size())
// 讀取內容到容器里面
file.Read(key_bytes)
// pem解碼
block,_ := pem.Decode(key_bytes)
// x509解碼
privateKey ,err_pb := x509.ParsePKCS1PrivateKey(block.Bytes)
if err_pb != nil {
return &rsa.PrivateKey{},err_pb
}
return privateKey,nil
}
//獲取公鑰
func GetPublicKey(file_path string)(*rsa.PublicKey,error){
//打開檔案
file, err := os.Open(file_path)
if err!=nil{
return &rsa.PublicKey{},err
}
// 獲取檔案資訊
file_info, err_info := file.Stat()
if err_info != nil {
return &rsa.PublicKey{},err_info
}
// 存盤讀取檔案內容所用的切片
key_bytes := make([]byte,file_info.Size())
// 讀取內容到容器里面
file.Read(key_bytes)
// pem解碼
block,_ := pem.Decode(key_bytes)
// x509解碼
publicKey ,err_pb := x509.ParsePKCS1PublicKey(block.Bytes)
if err_pb != nil {
return &rsa.PublicKey{},err_pb
}
return publicKey,nil
}
//陣列簽名,使用私鑰
func RsaGetSign(file_path string,src string)([]byte,error){
//拿到私鑰
privateKey, err := GetPivateKey(file_path)
if err!=nil{
return []byte{},err
}
hash := sha256.New()
src_byte := []byte(src)
hash.Write(src_byte)
sha_bytes := hash.Sum(nil)
//簽名
signPKCS1v15, err_sign := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.*SHA256*, sha_bytes)
if err!=nil{
return []byte{},err_sign
}
return signPKCS1v15,nil
}
//驗證簽名,使用的是公鑰
func RsaVarifySign(sign []byte,file_path string,src string)(bool,error){
publicKey, err := GetPublicKey(file_path)
if err!=nil{
return false,nil
}
hash := sha256.New()
src_byte := []byte(src)
hash.Write(src_byte)
sha_bytes := hash.Sum(nil)
err_verify := rsa.VerifyPKCS1v15(publicKey, crypto.*SHA256*, sha_bytes, sign)
if err_verify!=nil{
return false,nil
}
return true,nil
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/308917.html
標籤:區塊鏈
