密码学介绍,不完整
对称加密
DES
明文64bit
密钥56bit+8bit
XOR是三轮加密
ECB电子密码本
简单分组,不安全,需要填充
package main
import (
"bytes"
"crypto/des"
"encoding/hex"
"fmt"
)
func main() {
src := []byte("微信公众号【福大大架构师每日一题】")
fmt.Println("明文:", string(src))
key := []byte("moonfdd1") //64bit
ret := EncryptDES(src, key)
fmt.Println("密文:", hex.EncodeToString(ret))
ret = DecryptDes(ret, key)
fmt.Println("明文:", string(ret))
}
// 加密
func EncryptDES(src, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
length := block.BlockSize()
src = PaddingText(src, length)
dst := make([]byte, len(src))
out := dst
for len(src) > 0 {
block.Encrypt(out, src[:length])
src = src[length:]
out = out[length:]
}
return dst
}
// 解密
func DecryptDes(src, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
length := block.BlockSize()
dst := make([]byte, len(src))
out := dst
for len(src) > 0 {
block.Decrypt(out, src[:length])
src = src[length:]
out = out[length:]
}
dst = UnPaddingText(dst)
return dst
}
// 填充数据
func PaddingText(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
nextText := append(src, padText...)
return nextText
}
// 删除尾部填充数据
func UnPaddingText(src []byte) []byte {
len := len(src)
number := int(src[len-1])
newText := src[:len-number]
return newText
}
CBC密码分组链接
需要填充
初始化向量:当加密第一个明文分组时,由于不存在前一个密文分组,因此需要事先准备一个长度为一个分组的比特序列来代替前一个密文分组,这个比特序列就称之为初始化向量,通常缩写称IV。
分析:
1.假设CBC模式加密的密文分组中有一个分组损坏了(由于硬盘故障导致密文分组的值发生了变化),只要密文分组的长度没有发生变化,则解密是最多只会有2个分组受到数据损坏的影响。
2.假设CBC模式的密文分组中长度发生了变化,会导致每一个分组会向后一个分组借位,这样就导致了后面的分组全部发生变化,最终导致后面的数据全部解密失败。
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/hex"
"fmt"
)
func main() {
src := []byte("微信公众号【福大大架构师每日一题】")
fmt.Println("明文:", string(src))
key := []byte("moonfdd1") //64bit
ret := EncryptDES(src, key)
fmt.Println("密文:", hex.EncodeToString(ret))
ret = DecryptDes(ret, key)
fmt.Println("明文:", string(ret))
}
// 加密
func EncryptDES(src, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
length := block.BlockSize()
src = PaddingText(src, length)
iv := []byte("12345678")
blockMode := cipher.NewCBCEncrypter(block, iv)
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
return dst
}
// 解密
func DecryptDes(src, key []byte) []byte {
block, err := des.NewCipher(key)
if err != nil {
panic(err)
}
iv := []byte("12345678")
blockMode := cipher.NewCBCDecrypter(block, iv)
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
dst = UnPaddingText(dst)
return dst
}
// 填充数据
func PaddingText(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
nextText := append(src, padText...)
return nextText
}
// 删除尾部填充数据
func UnPaddingText(src []byte) []byte {
len := len(src)
number := int(src[len-1])
newText := src[:len-number]
return newText
}
CFB密码反馈模式
需要填充
OFB输出反馈模式
不需要填充
CTR计数器
不需要填充
3DES
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/hex"
"fmt"
)
func main() {
key := []byte("moonfdd1moonfdd1moonfdd1") //24个字符
data := []byte("微信公众号【福大大架构师每日一题】")
fmt.Println("原文:", string(data))
encrypt_msg := Encrypt3DES(data, key)
fmt.Println("encrypt_msg = ", hex.EncodeToString(encrypt_msg))
decrypt_msg := Decrypt3DES(encrypt_msg, key)
fmt.Println("decrypt_msg = ", string(decrypt_msg))
}
//使用3des加密
func Encrypt3DES(src, key []byte) []byte {
block, err := des.NewTripleDESCipher(key)
if err != nil {
panic(err)
}
src = PaddingText(src, block.BlockSize())
iv := []byte("12345678")
blockMode := cipher.NewCBCEncrypter(block, iv)
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
return dst
}
//解密
func Decrypt3DES(src, key []byte) []byte {
block, err := des.NewTripleDESCipher(key)
if err != nil {
panic(err)
}
iv := []byte("12345678")
blockMode := cipher.NewCBCDecrypter(block, iv)
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
dst = UnPaddingText(dst)
return dst
}
// 填充数据
func PaddingText(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
nextText := append(src, padText...)
return nextText
}
// 删除尾部填充数据
func UnPaddingText(src []byte) []byte {
len := len(src)
number := int(src[len-1])
newText := src[:len-number]
return newText
}
AES
明文分组的长度为128位即16字节
密钥长度可以为16、24、32字节(128、192、256位)
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func main() {
key := []byte("moonfdd1moonfdd1moonfdd1") //24个字符 16,24,32
data := []byte("微信公众号【福大大架构师每日一题】")
fmt.Println("原文:", string(data))
encrypt_msg := EncryptAes(data, key)
fmt.Println("encrypt_msg = ", hex.EncodeToString(encrypt_msg))
decrypt_msg := DecryptAes(encrypt_msg, key)
fmt.Println("decrypt_msg = ", string(decrypt_msg))
}
//aes加密
func EncryptAes(src, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
src = PaddingText(src, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[:block.BlockSize()])
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
return dst
}
//aes解密
func DecryptAes(src, key []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockMode := cipher.NewCBCDecrypter(block, key[:block.BlockSize()])
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
dst = UnPaddingText(dst)
return dst
}
// 填充数据
func PaddingText(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
nextText := append(src, padText...)
return nextText
}
// 删除尾部填充数据
func UnPaddingText(src []byte) []byte {
len := len(src)
number := int(src[len-1])
newText := src[:len-number]
return newText
}
SM4
分组对称加密算法,秘钥长度和分组长度均为128位。
package main
import (
"bytes"
"crypto/cipher"
"encoding/hex"
"fmt"
"github.com/tjfoc/gmsm/sm4"
)
//sm4加密
//src:明文
//key:秘钥
func EncryptSm4(src, key []byte) []byte {
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
src = PaddingText(src, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[:block.BlockSize()])
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
return dst
}
//sm4解密
//src:密文
//key:秘钥
func DecryptSm4(src, key []byte) []byte {
block, err := sm4.NewCipher(key)
if err != nil {
panic(err)
}
blockMode := cipher.NewCBCDecrypter(block, key[:block.BlockSize()])
dst := make([]byte, len(src))
blockMode.CryptBlocks(dst, src)
newText := UnPaddingText(dst)
return newText
}
// 填充数据
func PaddingText(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
nextText := append(src, padText...)
return nextText
}
// 删除尾部填充数据
func UnPaddingText(src []byte) []byte {
len := len(src)
number := int(src[len-1])
newText := src[:len-number]
return newText
}
func main() {
key := []byte("12345678abcdefgh")
msg := []byte("微信公众号【福大大架构师每日一题】")
encrypt_msg := EncryptSm4(msg, key)
fmt.Println("encrypt_msg = ", hex.EncodeToString(encrypt_msg))
decrypt_msg := DecryptSm4(encrypt_msg, key)
fmt.Println("decrypt_msg = ", string(decrypt_msg))
}
非对称加密
公钥加密,私钥解密
数字签名可以识别篡改和伪装和防止否认,在数字签名中有两种行为:
a. 生成消息签名
b. 验证消息签名
公钥通信流程:
公钥密码:
数字签名如下:
RSA
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
"os"
)
func RsaGenKey(bits int) error {
//GenerateKey函数使用随机数生成器生成一对指定长度的公钥和私钥
//rand.Reader是一个全局,共享的密码随机生成器
privKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
panic(err)
}
//x509是通用的整数格式:序列号 签名算法 颁发者 有效时间 持有者 公钥
//PKCS:RSA实验室与其他安全系统开发商为促进公钥密码的发展而指定的一系列标准
priStream := x509.MarshalPKCS1PrivateKey(privKey)
//将私钥字符串设置pem格式的块中
/*
pem是一种整数或私钥的格式:
---------------BEGIN RSA Private Key---------------
--------------END RSA Private Key-------------------
*/
block := pem.Block{
Type: "RSA Private Key",
Bytes: priStream,
}
privFile, err := os.Create("private.pem")
if err != nil {
panic(err)
}
defer privFile.Close()
//将块编码到文件
err = pem.Encode(privFile, &block)
if err != nil {
panic(err)
}
//从私钥中获取公钥
pubKey := privKey.PublicKey
//将公钥序列化
pubStream := x509.MarshalPKCS1PublicKey(&pubKey)
//将公钥设置到pem块中
block = pem.Block{
Type: "RSA Public Key",
Bytes: pubStream,
}
pubFile, err := os.Create("publiv.pem")
defer pubFile.Close()
if err != nil {
panic(err)
}
err = pem.Encode(pubFile, &block)
if err != nil {
panic(err)
}
return nil
}
//公钥加密
func RsaPublicEncrypt(src, pathName []byte) ([]byte, error) {
file, err := os.Open(string(pathName))
msg := []byte("")
if err != nil {
return msg, err
}
defer file.Close()
info, err := file.Stat()
if err != nil {
return msg, err
}
//创建切片,用于存储公钥
recvBuf := make([]byte, info.Size())
//读取公钥
file.Read(recvBuf)
//将得到的公钥反序列化
//参数一:存储公钥的切片, 参数二:剩余未解密的数据
block, _ := pem.Decode(recvBuf)
//使用x509将编码之后的公钥解析出来
pubKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return msg, err
}
msg, err = rsa.EncryptPKCS1v15(rand.Reader, pubKey, src)
if err != nil {
return msg, err
}
return msg, nil
}
//使用私钥解密
func RsaPrivateDecrypt(src []byte, pathName string) ([]byte, error) {
msg := []byte("")
file, err := os.Open(pathName)
if err != nil {
return msg, err
}
info, err := file.Stat()
if err != nil {
return msg, err
}
//创建切片,用于存储公钥
recvBuf := make([]byte, info.Size())
//读取公钥
file.Read(recvBuf)
block, _ := pem.Decode(recvBuf)
privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return msg, err
}
msg, err = rsa.DecryptPKCS1v15(rand.Reader, privKey, src)
if err != nil {
panic(err)
}
return msg, nil
}
func main() {
err := RsaGenKey(1024)
if err != nil {
fmt.Println("秘钥对生成失败!")
} else {
fmt.Println("秘钥对生成成功!")
}
src := []byte("微信公众号【福大大架构师每日一题】")
encrypt_msg, _ := RsaPublicEncrypt(src, []byte("publiv.pem"))
fmt.Println("encrypt_msg = ", hex.EncodeToString(encrypt_msg))
decrypt_msg, _ := RsaPrivateDecrypt(encrypt_msg, "private.pem")
fmt.Println("decrypt_msg = ", string(decrypt_msg))
}
dsa
直接对消息进行签名(DSA)
package main
import (
"crypto/dsa"
"crypto/rand"
"fmt"
)
/*
验证签名的作用:
1.保证数据的完整性
2.确保数据的来源
*/
func main() {
//Parameters代表秘钥的域参数
var param dsa.Parameters
//GenerateParameters函数随机的设置合法的参数到params,
//根据第三个参数就决定L和N的长度,长度越长,加密强度越高
dsa.GenerateParameters(¶m, rand.Reader, dsa.L1024N160)
//生成私钥
var priv dsa.PrivateKey
priv.Parameters = param
dsa.GenerateKey(&priv, rand.Reader)
//利用私钥签名数据
message := []byte("微信公众号【福大大架构师每日一题】")
r, s, _ := dsa.Sign(rand.Reader, &priv, message)
//通过私钥获取公钥
pub := priv.PublicKey
message1 := []byte("微信公众号【福大大架构师每日一题】")
//使用公钥验证签名
if dsa.Verify(&pub, message1, r, s) {
fmt.Println("验证通过!")
} else {
fmt.Println("验证失败!")
}
}
对消息的散列值进行签名
package main
import (
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"fmt"
)
func main() {
//生成秘钥对
priv, _ := rsa.GenerateKey(rand.Reader, 1024)
//消息
msg := []byte("微信公众号【福大大架构师每日一题】")
//给消息进行散列处理
h := md5.New()
h.Write(msg)
hashed := h.Sum(nil)
//签名
opts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.MD5}
sig, _ := rsa.SignPSS(rand.Reader, priv, crypto.MD5, hashed, opts)
//获取公钥
pub := &priv.PublicKey
err := rsa.VerifyPSS(pub, crypto.MD5, hashed, sig, opts)
if err == nil {
fmt.Println("验证通过!")
}
}
ECC
ecdsa
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
)
func main() {
message := []byte("微信公众号【福大大架构师每日一题】")
//参数一:曲线类型
privateKey, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
//获取公钥
pub := privateKey.PublicKey
//散列明文
digest := sha256.Sum256(message)
r, s, _ := ecdsa.Sign(rand.Reader, privateKey, digest[:])
message1 := []byte("微信公众号【福大大架构师每日一题】")
digest = sha256.Sum256(message1)
flag := ecdsa.Verify(&pub, digest[:], r, s)
if flag {
fmt.Println("验证成功")
} else {
fmt.Println("验证失败")
}
}
SM2
非对称加密,基于椭圆加密,签名速度与秘钥生成速度都快于RSA。
摘要
能辨认出篡改,不能辨认真伪。
md5
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
)
func main() {
hash := md5.New()
hash.Write([]byte("微信公众号【福大大架构师每日一题】"))
result := hash.Sum(nil)
fmt.Println(hex.EncodeToString(result))
hash.Reset()
hash.Write([]byte("微信公众号【福大大架构师每日一题】"))
result = hash.Sum(nil)
fmt.Println(hex.EncodeToString(result))
}
sha256
package main
import (
"crypto/sha256"
"fmt"
)
/*
go语言sha256包中实现了两种哈希函数,分别是sha256hesha224
*/
func main() {
hash := sha256.New()
hash.Write([]byte("微信公众号【福大大架构师每日一题】"))
result := hash.Sum(nil)
fmt.Printf("%x\n", result)
}
SM3
消息摘要算法,散列值为256位
package main
import (
"encoding/hex"
"fmt"
"github.com/tjfoc/gmsm/sm3"
)
func main2() {
hash := sm3.New()
hash.Write([]byte("微信公众号【福大大架构师每日一题】"))
result := hash.Sum(nil)
fmt.Println(hex.EncodeToString(result))
fmt.Println("length = ", len(result)*8)
}
func main() {
result := sm3.Sm3Sum([]byte("微信公众号【福大大架构师每日一题】"))
fmt.Println("length = ", len(result)*8)
fmt.Println(hex.EncodeToString(result))
}
国密算法
SM2:非对称加密,基于椭圆加密,签名速度与秘钥生成速度都快于RSA。
SM3:消息摘要算法,散列值为256位
SM4:分组对称加密算法,秘钥长度和分组长度均为128位。
SSL协议
工作原理:
SSL协议主要是有三个自协议组成,分别是握手协议,记录协议,警报协议。
CA证书颁发机构
openssl模拟CA
公众号:福大大架构师每日一题