密码学里目前有两大经典算法,一个是对称加解密,其代表是AES加解密;另一个是非对加解密,其代表是RSA加解密。这里就以这两个经典算法为例,简单列下其在golang里实现的代码。

一、AES加解密

AES加密又分为ECB、CBC、CFB、OFB等几种,这里只列两种吧。

1、CBC加解密

 1/*
 2code from www.361way.com
 3mail:itybku@139.com
 4desc:aes加密之一
 5*/
 6package main
 7import(
 8    "bytes"
 9    "crypto/aes"
10    "fmt"
11    "crypto/cipher"
12    "encoding/base64"
13)
14func main() {
15    orig := "hello world"
16    //key := "123456781234567812345678"
17    key := "9871267812345mn812345xyz"
18    fmt.Println("原文:", orig)
19    encryptCode := AesEncrypt(orig, key)
20    fmt.Println("密文:" , encryptCode)
21    decryptCode := AesDecrypt(encryptCode, key)
22    fmt.Println("解密结果:", decryptCode)
23}
24func AesEncrypt(orig string, key string) string {
25    // 转成字节数组
26    origData := []byte(orig)
27    k := []byte(key)
28    // 分组秘钥
29    block, _ := aes.NewCipher(k)
30    // 获取秘钥块的长度
31    blockSize := block.BlockSize()
32    // 补全码
33    origData = PKCS7Padding(origData, blockSize)
34    // 加密模式
35    blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
36    // 创建数组
37    cryted := make([]byte, len(origData))
38    // 加密
39    blockMode.CryptBlocks(cryted, origData)
40    return base64.StdEncoding.EncodeToString(cryted)
41}
42func AesDecrypt(cryted string, key string) string {
43    // 转成字节数组
44    crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
45    k := []byte(key)
46    // 分组秘钥
47    block, _ := aes.NewCipher(k)
48    // 获取秘钥块的长度
49    blockSize := block.BlockSize()
50    // 加密模式
51    blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
52    // 创建数组
53    orig := make([]byte, len(crytedByte))
54    // 解密
55    blockMode.CryptBlocks(orig, crytedByte)
56    // 去补全码
57    orig = PKCS7UnPadding(orig)
58    return string(orig)
59}
60//补码
61func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
62    padding := blocksize - len(ciphertext)%blocksize
63    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
64    return append(ciphertext, padtext...)
65}
66//去码
67func PKCS7UnPadding(origData []byte) []byte {
68    length := len(origData)
69    unpadding := int(origData[length-1])
70    return origData[:(length - unpadding)]
71}

其运行结果如下:

1[root@361way crypto]# go run aes.go
2原文 hello world
3密文 v3/NfSN7XwqXu2gC08+3QA==
4解密结果 hello world

2、CFB加解密

代码如下:

 1/*
 2code from www.361way.com
 3mail:itybku@139.com
 4desc:aes加密之一
 5*/
 6package main
 7import (
 8    "crypto/aes"
 9    "crypto/cipher"
10    "fmt"
11    "os"
12)
13var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
14func main() {
15    //需要去加密的字符串
16    plaintext := []byte("My name is Astaxie")
17    //如果传入加密串的话,plaint就是传入的字符串
18    if len(os.Args) > 1 {
19        plaintext = []byte(os.Args[1])
20    }
21    //aes的加密字符串
22    key_text := "astaxie12798akljzmknm.ahkjkljl;k"
23    if len(os.Args) > 2 {
24        key_text = os.Args[2]
25    }
26    fmt.Println(len(key_text))
27    // 创建加密算法aes
28    c, err := aes.NewCipher([]byte(key_text))
29    if err != nil {
30        fmt.Printf("Error: NewCipher(%d bytes) = %s", len(key_text), err)
31        os.Exit(-1)
32    }
33    //加密字符串
34    cfb := cipher.NewCFBEncrypter(c, commonIV)
35    ciphertext := make([]byte, len(plaintext))
36    cfb.XORKeyStream(ciphertext, plaintext)
37    fmt.Printf("%s=>%x\n", plaintext, ciphertext)
38    // 解密字符串
39    cfbdec := cipher.NewCFBDecrypter(c, commonIV)
40    plaintextCopy := make([]byte, len(plaintext))
41    cfbdec.XORKeyStream(plaintextCopy, ciphertext)
42    fmt.Printf("%x=>%s\n", ciphertext, plaintextCopy)
43}

其运行结果如下:

1[root@361way crypto]# go run aes2.go
232
3My name is Astaxie=>5072eadc20720cdb321b7c62947982d8227d
45072eadc20720cdb321b7c62947982d8227d=>My name is Astaxie

上面的代码如果细看和分解成加解密函数,发现是有问题的,这里再列个官方的示例 (需翻墙):

 1/*
 2code by www.361way.com,from golang.org
 3itybku@139.com
 4AES CFB加解密
 5*/
 6package main
 7import (
 8        "crypto/aes"
 9        "crypto/cipher"
10        "crypto/rand"
11        "encoding/hex"
12        "fmt"
13        "io"
14)
15func ExampleNewCFBDecrypter() {
16        key, _ := hex.DecodeString("6368616e676520746869732070617373")
17        ciphertext, _ := hex.DecodeString("e38932f30048f4cf2ecff113b29c4aed3dc0fb65c8d16ae0171aee54d207")
18        block, err := aes.NewCipher(key)
19        if err != nil {
20                panic(err)
21        }
22        if len(ciphertext) < aes.BlockSize {
23                panic("ciphertext too short")
24        }
25        iv := ciphertext[:aes.BlockSize]
26        ciphertext = ciphertext[aes.BlockSize:]
27        stream := cipher.NewCFBDecrypter(block, iv)
28        stream.XORKeyStream(ciphertext, ciphertext)
29        fmt.Printf("%s\n", ciphertext)
30}
31func ExampleNewCFBEncrypter() {
32        key, _ := hex.DecodeString("6368616e676520746869732070617373")
33        plaintext := []byte("www.361way.com")
34        block, err := aes.NewCipher(key)
35        if err != nil {
36                panic(err)
37        }
38        ciphertext := make([]byte, aes.BlockSize+len(plaintext))
39        iv := ciphertext[:aes.BlockSize]
40        if _, err := io.ReadFull(rand.Reader, iv); err != nil {
41                panic(err)
42        }
43        stream := cipher.NewCFBEncrypter(block, iv)
44        stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
45        fmt.Printf("%x\n", ciphertext)
46}
47func main() {
48        ExampleNewCFBDecrypter()
49        ExampleNewCFBEncrypter()
50}

二、golang下RSA加解密

AES一般用于加解密文,而RSA算法一算用来加解密密码。这里列举一个代码示例,如下:

 1/*
 2code from www.361way.com
 3mail:itybku@139.com
 4desc:rsa加解密
 5*/
 6package main
 7import (
 8    "crypto/rand"
 9    "crypto/rsa"
10    "crypto/x509"
11    "encoding/base64"
12    "encoding/pem"
13    "errors"
14    "fmt"
15)
16// 可通过openssl产生
17//openssl genrsa -out rsa_private_key.pem 1024
18var privateKey = []byte(`
19-----BEGIN RSA PRIVATE KEY-----
20MIICXQIBAAKBgQDfw1/P15GQzGGYvNwVmXIGGxea8Pb2wJcF7ZW7tmFdLSjOItn9
21kvUsbQgS5yxx+f2sAv1ocxbPTsFdRc6yUTJdeQolDOkEzNP0B8XKm+Lxy4giwwR5
22LJQTANkqe4w/d9u129bRhTu/SUzSUIr65zZ/s6TUGQD6QzKY1Y8xS+FoQQIDAQAB
23AoGAbSNg7wHomORm0dWDzvEpwTqjl8nh2tZyksyf1I+PC6BEH8613k04UfPYFUg1
240F2rUaOfr7s6q+BwxaqPtz+NPUotMjeVrEmmYM4rrYkrnd0lRiAxmkQUBlLrCBiF
25u+bluDkHXF7+TUfJm4AZAvbtR2wO5DUAOZ244FfJueYyZHECQQD+V5/WrgKkBlYy
26XhioQBXff7TLCrmMlUziJcQ295kIn8n1GaKzunJkhreoMbiRe0hpIIgPYb9E57tT
27/mP/MoYtAkEA4Ti6XiOXgxzV5gcB+fhJyb8PJCVkgP2wg0OQp2DKPp+5xsmRuUXv
28720oExv92jv6X65x631VGjDmfJNb99wq5QJBAMSHUKrBqqizfMdOjh7z5fLc6wY5
29M0a91rqoFAWlLErNrXAGbwIRf3LN5fvA76z6ZelViczY6sKDjOxKFVqL38ECQG0S
30pxdOT2M9BM45GJjxyPJ+qBuOTGU391Mq1pRpCKlZe4QtPHioyTGAAMd4Z/FX2MKb
313in48c0UX5t3VjPsmY0CQQCc1jmEoB83JmTHYByvDpc8kzsD8+GmiPVrausrjj4p
32y2DQpGmUic2zqCxl6qXMpBGtFEhrUbKhOiVOJbRNGvWW
33-----END RSA PRIVATE KEY-----
34`)
35//openssl
36//openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
37var publicKey = []byte(`
38-----BEGIN PUBLIC KEY-----
39MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfw1/P15GQzGGYvNwVmXIGGxea
408Pb2wJcF7ZW7tmFdLSjOItn9kvUsbQgS5yxx+f2sAv1ocxbPTsFdRc6yUTJdeQol
41DOkEzNP0B8XKm+Lxy4giwwR5LJQTANkqe4w/d9u129bRhTu/SUzSUIr65zZ/s6TU
42GQD6QzKY1Y8xS+FoQQIDAQAB
43-----END PUBLIC KEY-----
44`)
45// 加密
46func RsaEncrypt(origData []byte) ([]byte, error) {
47    //解密pem格式的公钥
48    block, _ := pem.Decode(publicKey)
49    if block == nil {
50        return nil, errors.New("public key error")
51    }
52    // 解析公钥
53    pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
54    if err != nil {
55        return nil, err
56    }
57    // 类型断言
58    pub := pubInterface.(*rsa.PublicKey)
59    //加密
60    return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
61}
62// 解密
63func RsaDecrypt(ciphertext []byte) ([]byte, error) {
64    //解密
65    block, _ := pem.Decode(privateKey)
66    if block == nil {
67        return nil, errors.New("private key error!")
68    }
69    //解析PKCS1格式的私钥
70    priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
71    if err != nil {
72        return nil, err
73    }
74    // 解密
75    return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
76}
77func main() {
78    data, _ := RsaEncrypt([]byte("hello world"))
79    fmt.Println(base64.StdEncoding.EncodeToString(data))
80    origData, _ := RsaDecrypt(data)
81    fmt.Println(string(origData))
82}

运行结果如下:

1[root@361way crypto]# go run rsa.go
2ocYqyhRtngT/G9TteTHxAmg9E3KNuw0zskKXcQbxeWEwFoHzGGIrfkDokq+SMvYeQjVCWTADBL3zzlelBBaZIVaJ11PndffC+2AlDVhLrvRqy5MeEYFafH40ZH1qUptt/UiY4imgaQc1dhcQol0+4dTfGmgN8CMAi3od7AU+/RM=
3hello world