golang加密算法
|字数总计:3.8k|阅读时长:17分钟|阅读量:
对称加密
加密过程的每一步都是可逆的。加密和解密用的是同一组密钥。异或是最简单的对称加密算法。
1 2 3 4 5 6 7 8 9 10
| func XOR(plain string, key []byte) string { bPlain := []byte(plain) bCipher := make([]byte, len(key)) for i, k := range key { bCipher[i] = k ^ bPlain[i] } cipher := string(bCipher) return cipher }
|
DES(Data Encryption Standard)数据加密标准,是目前最为流行的加密算法之一。对原始数据(明文)进行分组,每组64位,最后一组不足64位时按一定规则填充。每一组上单独施加DES算法。
DES子密钥生成
初始密钥64位,实际有效位56位,每隔7位有一个校验位。根据初始密钥生成16个48位的子密钥。
N取值从1到16,N和x有固定的映射表。
DES加密过程
L1, R1 = f(L0, R0, K1),依此循环,得到L16和R16。
S盒替换。输入48位,输出32位。各分为8组,输入每组6位,输出每组4位。分别在每组上施加S盒替换,一共8个S盒。
DES加密过程
分组模式。CBC(Cipher Block Chaining )密文分组链接模式,将当前明文分组与前一个密文分组进行异或运算,然后再进行加密。其他分组模式还有ECB, CTR, CFR, OFB。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| func DesEncryptCBC(text string, key []byte) (string, error) { src := []byte(text) block, err := des.NewCipher(key) if err != nil { return "", err } blockSize := block.BlockSize() src = common.ZeroPadding(src, blockSize)
out := make([]byte, len(src)) encrypter := cipher.NewCBCEncrypter(block, key) encrypter.CryptBlocks(out, src) return hex.EncodeToString(out), nil }
func DesDecryptCBC(text string, key []byte) (string, error) { src, err := hex.DecodeString(text) if err != nil { return "", err } block, err := des.NewCipher(key) if err != nil { return "", err }
out := make([]byte, len(src)) encrypter := cipher.NewCBCDecrypter(block, key) encrypter.CryptBlocks(out, src) out = common.ZeroUnPadding(out) return string(out), nil }
|
AES(Advanced Encryption Standard)高级加密标准,旨在取代DES。
非对称加密
- 使用公钥加密,使用私钥解密。
- 公钥和私钥不同。
- 公钥可以公布给所有人。
- 私钥只有自己保存。
- 相比于对称加密,运算速度非常慢。
对称加密和非对称加密结合使用的案例。小明要给小红传输机密文件,他俩先交换各自的公钥,然后:
- 小明生成一个随机的AES口令,然后用小红的公钥通过RSA加密这个口令,并发给小红。
- 小红用自己的RSA私钥解密得到AES口令。
- 双方使用这个共享的AES口令用AES加密通信。
RSA是三个发明人名字的缩写:Ron Rivest,Adi Shamir,Leonard Adleman。密钥越长,越难破解。 目前768位的密钥还无法破解(至少没人公开宣布)。因此可以认为1024位的RSA密钥基本安全,2048位的密钥极其安全。RSA的算法原理主要用到了数论。
RSA加密过程
- 随机选择两个不相等的质数p和q。p=61, q=53
- 计算p和q的乘积n。n=3233
- 计算n的欧拉函数φ(n) = (p-1)(q-1)。 φ(n) =3120
- 随机选择一个整数e,使得1< e < φ(n),且e与φ(n) 互质。e=17
- 计算e对于φ(n)的模反元素d,即求解e*d+ φ(n)*y=1。d=2753, y=-15
- 将n和e封装成公钥,n和d封装成私钥。公钥=(3233,17),公钥=(3233,2753)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| func RsaEncrypt(origData []byte) ([]byte, error) { block, _ := pem.Decode(publicKey) if block == nil { return nil, errors.New("public key error") } pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, err } pub := pubInterface.(*rsa.PublicKey) return rsa.EncryptPKCS1v15(rand.Reader, pub, origData) }
func RsaDecrypt(ciphertext []byte) ([]byte, error) { block, _ := pem.Decode(privateKey) if block == nil { return nil, errors.New("private key error!") } priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err } return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext) }
|
ECC(Elliptic Curve Cryptography)椭圆曲线加密算法,相比RSA,ECC可以使用更短的密钥,来实现与RSA相当或更高的安全。定义了椭圆曲线上的加法和二倍运算。椭圆曲线依赖的数学难题是:k为正整数,P是椭圆曲线上的点(称为基点), k*P=Q , 已知Q和P,很难计算出k。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| func genPrivateKey() (*ecies.PrivateKey, error) { pubkeyCurve := elliptic.P256() p, err := ecdsa.GenerateKey(pubkeyCurve, rand.Reader) if err != nil { return nil, err } else { return ecies.ImportECDSA(p), nil } }
func ECCEncrypt(plain string, pubKey *ecies.PublicKey) ([]byte, error) { src := []byte(plain) return ecies.Encrypt(rand.Reader, pubKey, src, nil, nil) }
func ECCDecrypt(cipher []byte, prvKey *ecies.PrivateKey) (string, error) { if src, err := prvKey.Decrypt(cipher, nil, nil); err != nil { return "", err } else { return string(src), nil } }
|
哈希算法
哈希函数的基本特征
- 输入可以是任意长度。
- 输出是固定长度。
- 根据输入很容易计算出输出。
- 根据输出很难计算出输入(几乎不可能)。
- 两个不同的输入几乎不可能得到相同的输出。
SHA(Secure Hash Algorithm) 安全散列算法,是一系列密码散列函数,有多个不同安全等级的版本:SHA-1,SHA-224,SHA-256,SHA-384,SHA-512。其作用是防伪装,防窜扰,保证信息的合法性和完整性。
sha-1算法大致过程
- 填充。使得数据长度对512求余的结果为448。
- 在信息摘要后面附加64bit,表示原始信息摘要的长度。
- 初始化h0到h4,每个h都是32位。
- h0到h4历经80轮复杂的变换。
- 把h0到h4拼接起来,构成160位,返回。
1 2 3 4 5
| func Sha1(data string) string { sha1 := sha1.New() sha1.Write([]byte(data)) return hex.EncodeToString(sha1.Sum(nil)) }
|
MD5(Message-Digest Algorithm 5)信息-摘要算法5,算法流程跟SHA-1大体相似。MD5的输出是128位,比SHA-1短了32位。MD5相对易受密码分析的攻击,运算速度比SHA-1快。
1 2 3 4 5
| func Md5(data string) string { md5 := md5.New() md5.Write([]byte(data)) return hex.EncodeToString(md5.Sum(nil)) }
|
哈希函数的应用场景
- 用户密码的存储。
- 文件上传/下载完整性校验。
- mysql大字段的快速对比。
数字签名
比特币中验证交易记录的真实性用的就是数字签名。先hash再用私钥加密的原因是:非对称加密计算量比较大,先hash可以把原始数据转一条很短的信息,提高计算效率。
案例
对称加密AES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package main
import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/hex" "fmt" "log" )
func ZeroPadding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{0}, padding) return append(ciphertext, padtext...) }
func ZeroUnPadding(origData []byte) []byte { return bytes.TrimFunc(origData, func(r rune) bool { return r == rune(0) }) }
func AesEncrypt(text string, key []byte) (string, error) { blockSize := aes.BlockSize src := []byte(text) src = ZeroPadding(src, blockSize) encrypted := make([]byte, len(src)) block, err := aes.NewCipher(key) if err != nil { return "", err } encrypter := cipher.NewCBCEncrypter(block, key) encrypter.CryptBlocks(encrypted, src) return hex.EncodeToString(encrypted), nil }
func AesDecrypt(text string, key []byte) (string, error) { src, err := hex.DecodeString(text) if err != nil { return "", err } decrypted := make([]byte, len(src)) block, err := aes.NewCipher(key) if err != nil { return "", err } edecrypter := cipher.NewCBCDecrypter(block, key) edecrypter.CryptBlocks(decrypted, src) out := ZeroUnPadding(decrypted) return string(out), nil }
func main() { key := []byte("ir489u58ir489u54") plain := "因为我们没有什么不同" cipher, err := AesEncrypt(plain, key) if err != nil { log.Fatal(err) } fmt.Printf("密文:%s\n", cipher)
plain, err = AesDecrypt(cipher, key) if err != nil { log.Fatal(err) } fmt.Printf("明文:%s\n", plain) }
|
运行结果:
密文:854deaf62920930fa266eff575fb8fdd8d1473a3ebe345a3ebf87fd4232c1a2f
明文:因为我们没有什么不同
对称加密DES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| package main
import ( "bytes" "crypto/cipher" "crypto/des" "encoding/hex" "fmt" "log" )
func ZeroPadding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{0}, padding) return append(ciphertext, padtext...) }
func ZeroUnPadding(origData []byte) []byte { return bytes.TrimFunc(origData, func(r rune) bool { return r == rune(0) }) }
func DesEncrypt(text string, key []byte) (string, error) { src := []byte(text) block, err := des.NewCipher(key) if err != nil { return "", err } blockSize := block.BlockSize() src = ZeroPadding(src, blockSize)
out := make([]byte, len(src)) dst := out for len(src) > 0 { block.Encrypt(dst, src[:blockSize]) src = src[blockSize:] dst = dst[blockSize:] } return hex.EncodeToString(out), nil }
func DesDecrypt(text string, key []byte) (string, error) { src, err := hex.DecodeString(text) if err != nil { return "", err } block, err := des.NewCipher(key) if err != nil { return "", err }
blockSize := block.BlockSize() out := make([]byte, len(src)) dst := out for len(src) > 0 { block.Decrypt(dst, src[:blockSize]) src = src[blockSize:] dst = dst[blockSize:] } out = ZeroUnPadding(out) return string(out), nil }
func DesEncryptCBC(text string, key []byte) (string, error) { src := []byte(text) block, err := des.NewCipher(key) if err != nil { return "", err } blockSize := block.BlockSize() src = ZeroPadding(src, blockSize)
out := make([]byte, len(src)) encrypter := cipher.NewCBCEncrypter(block, key) encrypter.CryptBlocks(out, src) return hex.EncodeToString(out), nil }
func DesDecryptCBC(text string, key []byte) (string, error) { src, err := hex.DecodeString(text) if err != nil { return "", err } block, err := des.NewCipher(key) if err != nil { return "", err }
out := make([]byte, len(src)) encrypter := cipher.NewCBCDecrypter(block, key) encrypter.CryptBlocks(out, src) out = ZeroUnPadding(out) return string(out), nil }
func main() {
key := []byte("ir489u58") plain := "因为我们没有什么不同" cipher, err := DesEncrypt(plain, key) if err != nil { log.Fatal(err) } fmt.Printf("密文:%s\n", cipher)
plain, err = DesDecrypt(cipher, key) if err != nil { log.Fatal(err) } fmt.Printf("明文:%s\n", plain) fmt.Println("-------------------------------------")
cipher, _ = DesEncryptCBC(plain, key) fmt.Printf("密文:%s\n", cipher) plain, err = DesDecryptCBC(cipher, key) fmt.Printf("明文:%s\n", plain) }
|
运行结果:
密文:5dc1bc67723d97493e27e5f4993c5a8f743179e15671e34a63067838ce25311f
明文:因为我们没有什么不同
-------------------------------------
密文:3323587cb8e1c03f524cd87fbb0c2585fc71c713f5416cc9ae1ee3ca1350b28d
明文:因为我们没有什么不同
非对称加密ECC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package main
import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "fmt" "log"
"github.com/ethereum/go-ethereum/crypto/ecies" )
func genPrivateKey() (*ecies.PrivateKey, error) { pubkeyCurve := elliptic.P256() p, err := ecdsa.GenerateKey(pubkeyCurve, rand.Reader) if err != nil { return nil, err } else { return ecies.ImportECDSA(p), nil } }
func ECCEncrypt(plain string, pubKey *ecies.PublicKey) ([]byte, error) { src := []byte(plain) return ecies.Encrypt(rand.Reader, pubKey, src, nil, nil) }
func ECCDecrypt(cipher []byte, prvKey *ecies.PrivateKey) (string, error) { if src, err := prvKey.Decrypt(cipher, nil, nil); err != nil { return "", err } else { return string(src), nil } }
func main() { prvKey, err := genPrivateKey() if err != nil { log.Fatal(err) } pubKey := prvKey.PublicKey plain := "因为我们没有什么不同" cipher, err := ECCEncrypt(plain, &pubKey) if err != nil { log.Fatal(err) } plain, err = ECCDecrypt(cipher, prvKey) if err != nil { log.Fatal(err) } fmt.Printf("明文:%s\n", plain) }
|
非对称加密RSA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| package main
import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/hex" "encoding/pem" "errors" "fmt" "os" )
var ( publicKey []byte privateKey []byte )
func ReadFile(keyFile string) ([]byte, error) { if f, err := os.Open(keyFile); err != nil { return nil, err } else { content := make([]byte, 4096) if n, err := f.Read(content); err != nil { return nil, err } else { return content[:n], nil } } }
func ReadRSAKey(publicKeyFile, privateKeyFile string) (err error) { if publicKey, err = ReadFile(publicKeyFile); err != nil { return err } if privateKey, err = ReadFile(privateKeyFile); err != nil { return err } return }
func RsaEncrypt(origData []byte) ([]byte, error) { block, _ := pem.Decode(publicKey) if block == nil { return nil, errors.New("public key error") } pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, err } pub := pubInterface.(*rsa.PublicKey) return rsa.EncryptPKCS1v15(rand.Reader, pub, origData) }
func RsaDecrypt(ciphertext []byte) ([]byte, error) { block, _ := pem.Decode(privateKey) if block == nil { return nil, errors.New("private key error!") } priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err } return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext) } func main() { ReadRSAKey("D:\\rsa_public_key.pem", "D:\\rsa_private_key.pem")
plain := "因为我们没有什么不同" cipher, _ := RsaEncrypt([]byte(plain)) fmt.Printf("密文:%s\n", hex.EncodeToString(cipher)) bPlain, _ := RsaDecrypt(cipher) fmt.Printf("明文:%s\n", string(bPlain)) }
|
运行结果:
密文:03eb4e1a6b1444d5996d06e106f126ccb7803a3f3fb4d6ba7751734e410136cc442603b6adcdfaeef2bd7309931fc9f05a404c14ae31fffee7e48808e8b112d630568bbc39ccd5d799f0dfc6e021592c01ed8fac9b618030491813620fe69c891946b21e1dafcd4d8ca3897f6436a85f5548c8bf9e49ef2f13a70f8c0118efeb
明文:因为我们没有什么不同
数字签名验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package main
import ( "crypto" "crypto/rsa" "crypto/sha1" "crypto/x509" "encoding/pem" "fmt" "os" )
func ReadFile(keyFile string) ([]byte, error) { if f, err := os.Open(keyFile); err != nil { return nil, err } else { content := make([]byte, 4096) if n, err := f.Read(content); err != nil { return nil, err } else { return content[:n], nil } } }
func DigitalSignature(trade string) []byte { sha1 := sha1.New() sha1.Write([]byte(trade)) digest := sha1.Sum([]byte(""))
privateKey, _ := ReadFile("D:\\rsa_private_key.pem") block, _ := pem.Decode(privateKey) priv, _ := x509.ParsePKCS1PrivateKey(block.Bytes) signature, _ := rsa.SignPKCS1v15(nil, priv, crypto.Hash(0), digest) return signature }
func VerifySignature(trade string, signature []byte) bool { sha1 := sha1.New() sha1.Write([]byte(trade)) digest := sha1.Sum([]byte(""))
publicKey, _ := ReadFile("D:\\rsa_public_key.pem") block, _ := pem.Decode(publicKey) pubInterface, _ := x509.ParsePKIXPublicKey(block.Bytes) pub := pubInterface.(*rsa.PublicKey)
return rsa.VerifyPKCS1v15(pub, crypto.Hash(0), digest, signature) == nil }
func main() { trade := "zhangsan transfer 10 BTC to lisi" signature := DigitalSignature(trade) fmt.Println("验证数字签名", VerifySignature(trade, signature)) }
|
运行结果:
验证数字签名 true
哈希
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package main
import ( "bufio" "crypto/md5" "crypto/sha1" "encoding/hex" "fmt" "io/ioutil" "log" "os" )
func Sha1(data []byte) string { sha1 := sha1.New() sha1.Write(data) return hex.EncodeToString(sha1.Sum(nil)) }
func Md5(data []byte) string { md5 := md5.New() md5.Write(data) return hex.EncodeToString(md5.Sum(nil)) }
func main() { data := "因为我们没有什么不同" fmt.Printf("SHA-1: %s\n", Sha1([]byte(data))) fmt.Printf("MD5: %s\n", Md5([]byte(data)))
f, err := os.Open("go.sum") if err != nil { log.Fatal(err) } defer f.Close() r := bufio.NewReader(f) b, err2 := ioutil.ReadAll(r) if err2 != nil { log.Fatal(err2) } fmt.Printf("Sha1(b): %v\n", Sha1(b)) fmt.Printf("Md5(b): %v\n", Md5(b)) }
|
运行结果:
SHA-1: 0cfea402af137e3793a6c8a80152b5ab74ba380b
MD5: 78cfcd6021c4f04e7e709cb8148aa4dd
Sha1(b): 4c8180f36e736ae3158767fc2a9f959bb3c86448
Md5(b): c82232187701537f2dd16d5ca836be72