golang常用加密解密算法總結(jié)(AES、DES、RSA、Sha1、MD5)
在項目開發(fā)過程中,當操作一些用戶的隱私信息,諸如密碼、帳戶密鑰等數(shù)據(jù)時,往往需要加密后可以在網(wǎng)上傳輸。這時,需要一些高效地、簡單易用的加密算法加密數(shù)據(jù),然后把加密后的數(shù)據(jù)存入數(shù)據(jù)庫或進行其他操作;當需要讀取數(shù)據(jù)時,把加密后的數(shù)據(jù)取出來,再通過算法解密。
關(guān)于加密解密
當前我們項目中常用的加解密的方式無非三種.
- 對稱加密, 加解密都使用的是同一個密鑰, 其中的代表就是AES、DES
- 非對加解密, 加解密使用不同的密鑰, 其中的代表就是RSA
- 簽名算法, 如MD5、SHA1、HMAC等, 主要用于驗證,防止信息被修改, 如:文件校驗、數(shù)字簽名、鑒權(quán)協(xié)議
Base64不是加密算法,它是一種數(shù)據(jù)編碼方式,雖然是可逆的,但是它的編碼方式是公開的,無所謂加密。本文也對Base64編碼方式做了簡要介紹。
AES
AES,即高級加密標準(Advanced Encryption Standard),是一個對稱分組密碼算法,旨在取代DES成為廣泛使用的標準。AES中常見的有三種解決方案,分別為AES-128、AES-192和AES-256。
AES加密過程涉及到4種操作:字節(jié)替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和輪密鑰加(AddRoundKey)。解密過程分別為對應的逆操作。由于每一步操作都是可逆的,按照相反的順序進行解密即可恢復明文。加解密中每輪的密鑰分別由初始密鑰擴展得到。算法中16字節(jié)的明文、密文和輪密鑰都以一個4x4的矩陣表示。
AES 有五種加密模式:電碼本模式(Electronic Codebook Book (ECB))、密碼分組鏈接模式(Cipher Block Chaining (CBC))、計算器模式(Counter (CTR))、密碼反饋模式(Cipher FeedBack (CFB))和輸出反饋模式(Output FeedBack (OFB))
import ( ? ? "bytes" ? ? "crypto/aes" ? ? "fmt" ? ? "crypto/cipher" ? ? "encoding/base64" ) func main() { ? ? orig := "hello world" ? ? key := "123456781234567812345678" ? ? fmt.Println("原文:", orig) ? ? encryptCode := AesEncrypt(orig, key) ? ? fmt.Println("密文:" , encryptCode) ? ? decryptCode := AesDecrypt(encryptCode, key) ? ? fmt.Println("解密結(jié)果:", decryptCode) } func AesEncrypt(orig string, key string) string { ? ? // 轉(zhuǎn)成字節(jié)數(shù)組 ? ? origData := []byte(orig) ? ? k := []byte(key) ? ? // 分組秘鑰 ? ? block, _ := aes.NewCipher(k) ? ? // 獲取秘鑰塊的長度 ? ? blockSize := block.BlockSize() ? ? // 補全碼 ? ? origData = PKCS7Padding(origData, blockSize) ? ? // 加密模式 ? ? blockMode := cipher.NewCBCEncrypter(block, k[:blockSize]) ? ? // 創(chuàng)建數(shù)組 ? ? cryted := make([]byte, len(origData)) ? ? // 加密 ? ? blockMode.CryptBlocks(cryted, origData) ? ? return base64.StdEncoding.EncodeToString(cryted) } func AesDecrypt(cryted string, key string) string { ? ? // 轉(zhuǎn)成字節(jié)數(shù)組 ? ? crytedByte, _ := base64.StdEncoding.DecodeString(cryted) ? ? k := []byte(key) ? ? // 分組秘鑰 ? ? block, _ := aes.NewCipher(k) ? ? // 獲取秘鑰塊的長度 ? ? blockSize := block.BlockSize() ? ? // 加密模式 ? ? blockMode := cipher.NewCBCDecrypter(block, k[:blockSize]) ? ? // 創(chuàng)建數(shù)組 ? ? orig := make([]byte, len(crytedByte)) ? ? // 解密 ? ? blockMode.CryptBlocks(orig, crytedByte) ? ? // 去補全碼 ? ? orig = PKCS7UnPadding(orig) ? ? return string(orig) } //補碼 func PKCS7Padding(ciphertext []byte, blocksize int) []byte { ? ? padding := blocksize - len(ciphertext)%blocksize ? ? padtext := bytes.Repeat([]byte{byte(padding)}, padding) ? ? return append(ciphertext, padtext...) } //去碼 func PKCS7UnPadding(origData []byte) []byte { ? ? length := len(origData) ? ? unpadding := int(origData[length-1]) ? ? return origData[:(length - unpadding)] }
DES
DES是一種對稱加密算法,又稱為美國數(shù)據(jù)加密標準。DES加密時以64位分組對數(shù)據(jù)進行加密,加密和解密都使用的是同一個長度為64位的密鑰,實際上只用到了其中的56位,密鑰中的第8、16…64位用來作奇偶校驗。DES有ECB(電子密碼本)和CBC(加密塊)等加密模式。
DES算法的安全性很高,目前除了窮舉搜索破解外, 尚無更好的的辦法來破解。其密鑰長度越長,破解難度就越大。
填充和去填充函數(shù)。
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 Encrypt(text string, key []byte) (string, error) { src := []byte(text) block, err := des.NewCipher(key) if err != nil { return "", err } bs := block.BlockSize() src = ZeroPadding(src, bs) if len(src)%bs != 0 { return "", errors.New("Need a multiple of the blocksize") } out := make([]byte, len(src)) dst := out for len(src) > 0 { block.Encrypt(dst, src[:bs]) src = src[bs:] dst = dst[bs:] } return hex.EncodeToString(out), nil }
解密。
func Decrypt(decrypted string , key []byte) (string, error) { src, err := hex.DecodeString(decrypted) if err != nil { return "", err } block, err := des.NewCipher(key) if err != nil { return "", err } out := make([]byte, len(src)) dst := out bs := block.BlockSize() if len(src)%bs != 0 { return "", errors.New("crypto/cipher: input not full blocks") } for len(src) > 0 { block.Decrypt(dst, src[:bs]) src = src[bs:] dst = dst[bs:] } out = ZeroUnPadding(out) return string(out), nil }
測試。在這里,DES中使用的密鑰key只能為8位。
func main() { key := []byte("2fa6c1e9") str :="I love this beautiful world!" strEncrypted, err := Encrypt(str, key) if err != nil { log.Fatal(err) } fmt.Println("Encrypted:", strEncrypted) strDecrypted, err := Decrypt(strEncrypted, key) if err != nil { log.Fatal(err) } fmt.Println("Decrypted:", strDecrypted) } //Output: //Encrypted: 5d2333b9fbbe5892379e6bcc25ffd1f3a51b6ffe4dc7af62beb28e1270d5daa1 //Decrypted: I love this beautiful world!
RSA
首先使用openssl生成公私鑰,使用RSA的時候需要提供公鑰和私鑰 , 可以通過openss來生成對應的pem格式的公鑰和私鑰匙
import ( ? ? "crypto/rand" ? ? "crypto/rsa" ? ? "crypto/x509" ? ? "encoding/base64" ? ? "encoding/pem" ? ? "errors" ? ? "fmt" ) // 私鑰生成 //openssl genrsa -out rsa_private_key.pem 1024 var privateKey = []byte(` -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bM h0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPaco qDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQAB AoGAeWAZvz1HZExca5k/hpbeqV+0+VtobMgwMs96+U53BpO/VRzl8Cu3CpNyb7HY 64L9YQ+J5QgpPhqkgIO0dMu/0RIXsmhvr2gcxmKObcqT3JQ6S4rjHTln49I2sYTz 7JEH4TcplKjSjHyq5MhHfA+CV2/AB2BO6G8limu7SheXuvECQQDwOpZrZDeTOOBk z1vercawd+J9ll/FZYttnrWYTI1sSF1sNfZ7dUXPyYPQFZ0LQ1bhZGmWBZ6a6wd9 R+PKlmJvAkEA6o32c/WEXxW2zeh18sOO4wqUiBYq3L3hFObhcsUAY8jfykQefW8q yPuuL02jLIajFWd0itjvIrzWnVmoUuXydwJAXGLrvllIVkIlah+lATprkypH3Gyc YFnxCTNkOzIVoXMjGp6WMFylgIfLPZdSUiaPnxby1FNM7987fh7Lp/m12QJAK9iL 2JNtwkSR3p305oOuAz0oFORn8MnB+KFMRaMT9pNHWk0vke0lB1sc7ZTKyvkEJW0o eQgic9DvIYzwDUcU8wJAIkKROzuzLi9AvLnLUrSdI6998lmeYO9x7pwZPukz3era zncjRK3pbVkv0KrKfczuJiRlZ7dUzVO0b6QJr8TRAA== -----END RSA PRIVATE KEY----- `) // 公鑰: 根據(jù)私鑰生成 //openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem var publicKey = []byte(` -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcGsUIIAINHfRTdMmgGwLrjzfM NSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdT nCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Z y682X1+R1lRK8D+vmQIDAQAB -----END PUBLIC KEY----- `) // 加密 func RsaEncrypt(origData []byte) ([]byte, error) { ? ? //解密pem格式的公鑰 ? ? 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!") ? ? } ? ? //解析PKCS1格式的私鑰 ? ? priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) ? ? if err != nil { ? ? ? ? return nil, err ? ? } ? ? // 解密 ? ? return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext) } func main() { ? ? data, _ := RsaEncrypt([]byte("hello world")) ? ? fmt.Println(base64.StdEncoding.EncodeToString(data)) ? ? origData, _ := RsaDecrypt(data) ? ? fmt.Println(string(origData)) }?
MD5
MD5的全稱是Message-DigestAlgorithm 5,它可以把一個任意長度的字節(jié)數(shù)組轉(zhuǎn)換成一個定長的整數(shù),并且這種轉(zhuǎn)換是不可逆的。對于任意長度的數(shù)據(jù),轉(zhuǎn)換后的MD5值長度是固定的,而且MD5的轉(zhuǎn)換操作很容易,只要原數(shù)據(jù)有一點點改動,轉(zhuǎn)換后結(jié)果就會有很大的差異。正是由于MD5算法的這些特性,它經(jīng)常用于對于一段信息產(chǎn)生信息摘要,以防止其被篡改。其還廣泛就于操作系統(tǒng)的登錄過程中的安全驗證,比如Unix操作系統(tǒng)的密碼就是經(jīng)過MD5加密后存儲到文件系統(tǒng)中,當用戶登錄時輸入密碼后, 對用戶輸入的數(shù)據(jù)經(jīng)過MD5加密后與原來存儲的密文信息比對,如果相同說明密碼正確,否則輸入的密碼就是錯誤的。
MD5以512位為一個計算單位對數(shù)據(jù)進行分組,每一分組又被劃分為16個32位的小組,經(jīng)過一系列處理后,輸出4個32位的小組,最后組成一個128位的哈希值。對處理的數(shù)據(jù)進行512求余得到N和一個余數(shù),如果余數(shù)不為448,填充1和若干個0直到448位為止,最后再加上一個64位用來保存數(shù)據(jù)的長度,這樣經(jīng)過預處理后,數(shù)據(jù)變成(N+1)x 512位。
加密。Encode 函數(shù)用來加密數(shù)據(jù),Check函數(shù)傳入一個未加密的字符串和與加密后的數(shù)據(jù),進行對比,如果正確就返回true。
func Check(content, encrypted string) bool { return strings.EqualFold(Encode(content), encrypted) } func Encode(data string) string { h := md5.New() h.Write([]byte(data)) return hex.EncodeToString(h.Sum(nil)) }
測試。
func main() { strTest := "I love this beautiful world!" strEncrypted := "98b4fc4538115c4980a8b859ff3d27e1" fmt.Println(Check(strTest, strEncrypted)) } //Output: //true
Sha1
package main import ( ?? ?"crypto/sha1" ?? ? "fmt" ) func main() { ? ?s := "sha1 this string" ? ?//產(chǎn)生一個散列值得方式是 sha1.New(),sha1.Write(bytes),然后 sha1.Sum([]byte{})。這里我們從一個新的散列開始。 ? ?h := sha1.New() ? ?//寫入要處理的字節(jié)。如果是一個字符串,需要使用[]byte(s) 來強制轉(zhuǎn)換成字節(jié)數(shù)組。 ? ?h.Write([]byte(s)) ? ?//這個用來得到最終的散列值的字符切片。Sum 的參數(shù)可以用來都現(xiàn)有的字符切片追加額外的字節(jié)切片:一般不需要要。 ? ?bs := h.Sum(nil) ? ?//SHA1 值經(jīng)常以 16 進制輸出,例如在 git commit 中。使用%x 來將散列結(jié)果格式化為 16 進制字符串。 ? ?fmt.Println(s) ? ?fmt.Printf("%x\n", bs) }
Base64
Base64是一種任意二進制到文本字符串的編碼方法,常用于在URL、Cookie、網(wǎng)頁中傳輸少量二進制數(shù)據(jù)。
首先使用Base64編碼需要一個含有64個字符的表,這個表由大小寫字母、數(shù)字、+和/組成。采用Base64編碼處理數(shù)據(jù)時,會把每三個字節(jié)共24位作為一個處理單元,再分為四組,每組6位,查表后獲得相應的字符即編碼后的字符串。編碼后的字符串長32位,這樣,經(jīng)Base64編碼后,原字符串增長1/3。如果要編碼的數(shù)據(jù)不是3的倍數(shù),最后會剩下一到兩個字節(jié),Base64編碼中會采用\x00在處理單元后補全,編碼后的字符串最后會加上一到兩個 = 表示補了幾個字節(jié)。
const ( ? ?base64Table = "IJjkKLMNO567PQX12RVW3YZaDEFGbcdefghiABCHlSTUmnopqrxyz04stuvw89+/" ) var coder = base64.NewEncoding(base64Table) func Base64Encode(src []byte) []byte { ? ? ? ? //編碼 ? ?return []byte(coder.EncodeToString(src)) } func Base64Decode(src []byte) ([]byte, error) { ? //解碼 ? ?return coder.DecodeString(string(src)) }
到此這篇關(guān)于golang常用加密解密算法總結(jié)(AES、DES、RSA、Sha1MD5)的文章就介紹到這了,更多相關(guān)golang 加密解密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go 迭代string數(shù)組操作 go for string[]
這篇文章主要介紹了go 迭代string數(shù)組操作 go for string[],具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12Go語言時間管理利器之深入解析time模塊的實戰(zhàn)技巧
本文深入解析了Go語言標準庫中的time模塊,揭示了其高效用法和實用技巧,通過學習time模塊的三大核心類型(Time、Duration、Timer/Ticker)以及高頻使用場景,開發(fā)者可以更好地處理時間相關(guān)的任務,感興趣的朋友一起看看吧2025-03-03golang hack插件開發(fā)動態(tài)鏈接庫實例探究
這篇文章主要為大家介紹了golang hack插件開發(fā)動態(tài)鏈接庫實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01