首页>>后端>>Golang->Golang:加密解密算法

Golang:加密解密算法

时间:2023-12-01 本站 点击:0

0. 摘要

在项目开发过程中,当操作一些用户的隐私信息,诸如密码,帐户密钥等数据时,往往需要加密后可以在网上传输.这时,需要一些高效地,简单易用的加密算法加密数据,然后把加密后的数据存入数据库或进行其他操作;当需要读取数据时,把加密后的数据取出来,再通过算法解密.

1. 关于加密解密

当前我们项目中常用的加解密的方式无非三种.

对称加密, 加解密都使用的是同一个密钥, 其中的代表就是AES,DES

非对加解密, 加解密使用不同的密钥, 其中的代表就是RSA

签名算法, 如MD5,SHA1,HMAC等, 主要用于验证,防止信息被修改, 如:文件校验,数字签名,鉴权协议

1.1. Base64不是加密算法

它是一种数据编码方式,虽然是可逆的,但是它的编码方式是公开的,无所谓加密.本文也对Base64编码方式做了简要介绍.

2. AES

AES,即高级加密标准(Advanced Encryption Standard),是一个对称分组密码算法,旨在取代DES成为广泛使用的标准.AES中常见的有三种解决方案,分别为AES-128,AES-192和AES-256. AES加密过程涉及到4种操作:字节替代(SubBytes),行移位(ShiftRows),列混淆(MixColumns)和轮密钥加(AddRoundKey).解密过程分别为对应的逆操作.由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文.加解密中每轮的密钥分别由初始密钥扩展得到.算法中16字节的明文,密文和轮密钥都以一个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")funcmain(){orig:="helloworld"key:="123456781234567812345678"fmt.Println("原文:",orig)encryptCode:=AesEncrypt(orig,key)fmt.Println("密文:",encryptCode)decryptCode:=AesDecrypt(encryptCode,key)fmt.Println("解密结果:",decryptCode)}funcAesEncrypt(origstring,keystring)string{//转成字节数组origData:=[]byte(orig)k:=[]byte(key)//分组秘钥block,err:=aes.NewCipher(k)iferr!=nil{panic(fmt.Sprintf("key长度必须16/24/32长度:%s",err.Error()))}//获取秘钥块的长度blockSize:=block.BlockSize()//补全码origData=PKCS7Padding(origData,blockSize)//加密模式blockMode:=cipher.NewCBCEncrypter(block,k[:blockSize])//创建数组cryted:=make([]byte,len(origData))//加密blockMode.CryptBlocks(cryted,origData)//使用RawURLEncoding不要使用StdEncoding//不要使用StdEncoding放在url参数中回导致错误returnbase64.RawURLEncoding.EncodeToString(cryted)}funcAesDecrypt(crytedstring,keystring)string{//使用RawURLEncoding不要使用StdEncoding//不要使用StdEncoding放在url参数中回导致错误crytedByte,_:=base64.RawURLEncoding.DecodeString(cryted)k:=[]byte(key)//分组秘钥block,err:=aes.NewCipher(k)iferr!=nil{panic(fmt.Sprintf("key长度必须16/24/32长度:%s",err.Error()))}//获取秘钥块的长度blockSize:=block.BlockSize()//加密模式blockMode:=cipher.NewCBCDecrypter(block,k[:blockSize])//创建数组orig:=make([]byte,len(crytedByte))//解密blockMode.CryptBlocks(orig,crytedByte)//去补全码orig=PKCS7UnPadding(orig)returnstring(orig)}//补码funcPKCS7Padding(ciphertext[]byte,blocksizeint)[]byte{padding:=blocksize-len(ciphertext)%blocksizepadtext:=bytes.Repeat([]byte{byte(padding)},padding)returnappend(ciphertext,padtext...)}//去码funcPKCS7UnPadding(origData[]byte)[]byte{length:=len(origData)unpadding:=int(origData[length-1])returnorigData[:(length-unpadding)]}

3. DES

DES是一种对称加密算法,又称为美国数据加密标准.DES加密时以64位分组对数据进行加密,加密和解密都使用的是同一个长度为64位的密钥,实际上只用到了其中的56位,密钥中的第8,16…64位用来作奇偶校验.DES有ECB(电子密码本)和CBC(加密块)等加密模式. DES算法的安全性很高,目前除了穷举搜索破解外, 尚无更好的的办法来破解.其密钥长度越长,破解难度就越大. 填充和去填充函数.

funcZeroPadding(ciphertext[]byte,blockSizeint)[]byte{padding:=blockSize-len(ciphertext)%blockSizepadtext:=bytes.Repeat([]byte{0},padding)returnappend(ciphertext,padtext...)}funcZeroUnPadding(origData[]byte)[]byte{returnbytes.TrimFunc(origData,func(rrune)bool{returnr==rune(0)})}

加密.

funcEncrypt(textstring,key[]byte)(string,error){src:=[]byte(text)block,err:=des.NewCipher(key)iferr!=nil{return"",err}bs:=block.BlockSize()src=ZeroPadding(src,bs)iflen(src)%bs!=0{return"",errors.New("Needamultipleoftheblocksize")}out:=make([]byte,len(src))dst:=outforlen(src)>0{block.Encrypt(dst,src[:bs])src=src[bs:]dst=dst[bs:]}returnhex.EncodeToString(out),nil}

解密.

funcDecrypt(decryptedstring,key[]byte)(string,error){src,err:=hex.DecodeString(decrypted)iferr!=nil{return"",err}block,err:=des.NewCipher(key)iferr!=nil{return"",err}out:=make([]byte,len(src))dst:=outbs:=block.BlockSize()iflen(src)%bs!=0{return"",errors.New("crypto/cipher:inputnotfullblocks")}forlen(src)>0{block.Decrypt(dst,src[:bs])src=src[bs:]dst=dst[bs:]}out=ZeroUnPadding(out)returnstring(out),nil}

测试.在这里,DES中使用的密钥key只能为8位.

funcmain(){key:=[]byte("2fa6c1e9")str:="Ilovethisbeautifulworld!"strEncrypted,err:=Encrypt(str,key)iferr!=nil{log.Fatal(err)}fmt.Println("Encrypted:",strEncrypted)strDecrypted,err:=Decrypt(strEncrypted,key)iferr!=nil{log.Fatal(err)}fmt.Println("Decrypted:",strDecrypted)}//Output://Encrypted:5d2333b9fbbe5892379e6bcc25ffd1f3a51b6ffe4dc7af62beb28e1270d5daa1//Decrypted:Ilovethisbeautifulworld!

4. RSA

首先使用openssl生成公私钥,使用RSA的时候需要提供公钥和私钥 , 可以通过openss来生成对应的pem格式的公钥和私钥匙

import("crypto/rand""crypto/rsa""crypto/x509""encoding/base64""encoding/pem""errors""fmt")//私钥生成//opensslgenrsa-outrsa_private_key.pem1024varprivateKey=[]byte(`-----BEGINRSAPRIVATEKEY-----MIICWwIBAAKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQABAoGAeWAZvz1HZExca5k/hpbeqV+0+VtobMgwMs96+U53BpO/VRzl8Cu3CpNyb7HY64L9YQ+J5QgpPhqkgIO0dMu/0RIXsmhvr2gcxmKObcqT3JQ6S4rjHTln49I2sYTz7JEH4TcplKjSjHyq5MhHfA+CV2/AB2BO6G8limu7SheXuvECQQDwOpZrZDeTOOBkz1vercawd+J9ll/FZYttnrWYTI1sSF1sNfZ7dUXPyYPQFZ0LQ1bhZGmWBZ6a6wd9R+PKlmJvAkEA6o32c/WEXxW2zeh18sOO4wqUiBYq3L3hFObhcsUAY8jfykQefW8qyPuuL02jLIajFWd0itjvIrzWnVmoUuXydwJAXGLrvllIVkIlah+lATprkypH3GycYFnxCTNkOzIVoXMjGp6WMFylgIfLPZdSUiaPnxby1FNM7987fh7Lp/m12QJAK9iL2JNtwkSR3p305oOuAz0oFORn8MnB+KFMRaMT9pNHWk0vke0lB1sc7ZTKyvkEJW0oeQgic9DvIYzwDUcU8wJAIkKROzuzLi9AvLnLUrSdI6998lmeYO9x7pwZPukz3erazncjRK3pbVkv0KrKfczuJiRlZ7dUzVO0b6QJr8TRAA==-----ENDRSAPRIVATEKEY-----`)//公钥:根据私钥生成//opensslrsa-inrsa_private_key.pem-pubout-outrsa_public_key.pemvarpublicKey=[]byte(`-----BEGINPUBLICKEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQAB-----ENDPUBLICKEY-----`)//加密funcRsaEncrypt(origData[]byte)([]byte,error){//解密pem格式的公钥block,_:=pem.Decode(publicKey)ifblock==nil{returnnil,errors.New("publickeyerror")}//解析公钥pubInterface,err:=x509.ParsePKIXPublicKey(block.Bytes)iferr!=nil{returnnil,err}//类型断言pub:=pubInterface.(*rsa.PublicKey)//加密returnrsa.EncryptPKCS1v15(rand.Reader,pub,origData)}//解密funcRsaDecrypt(ciphertext[]byte)([]byte,error){//解密block,_:=pem.Decode(privateKey)ifblock==nil{returnnil,errors.New("privatekeyerror!")}//解析PKCS1格式的私钥priv,err:=x509.ParsePKCS1PrivateKey(block.Bytes)iferr!=nil{returnnil,err}//解密returnrsa.DecryptPKCS1v15(rand.Reader,priv,ciphertext)}funcmain(){data,_:=RsaEncrypt([]byte("helloworld"))fmt.Println(base64.StdEncoding.EncodeToString(data))origData,_:=RsaDecrypt(data)fmt.Println(string(origData))}

5. 使用golang标准库ecdsa生成非对称(ES256,ES384,ES521)加密密钥对

import("crypto/ecdsa""crypto/elliptic""crypto/rand""crypto/x509""encoding/pem""github.com/spf13/cobra""log""os")//ecdsaCmdrepresentsthedoccommandfunckeyPairs(keyNamestring){//elliptic.P256(),elliptic.P384(),elliptic.P521()privateKey,err:=ecdsa.GenerateKey(elliptic.P256(),rand.Reader)iferr!=nil{log.Fatal(err)}x509Encoded,_:=x509.MarshalECPrivateKey(privateKey)privateBs:=pem.EncodeToMemory(&pem.Block{Type:"PRIVATEKEY",Bytes:x509Encoded})privateFile,err:=os.Create(keyName+".private.pem")iferr!=nil{log.Fatal(err)}_,err=privateFile.Write(privateBs)iferr!=nil{log.Fatal(err)}x509EncodedPub,_:=x509.MarshalPKIXPublicKey(privateKey.Public())publicBs:=pem.EncodeToMemory(&pem.Block{Type:"PUBLICKEY",Bytes:x509EncodedPub})publicKeyFile,err:=os.Create(keyName+".public.pem")iferr!=nil{log.Fatal(err)}_,err=publicKeyFile.Write(publicBs)iferr!=nil{log.Fatal(err)}}

6. MD5

MD5的全称是Message-DigestAlgorithm 5,它可以把一个任意长度的字节数组转换成一个定长的整数,并且这种转换是不可逆的.对于任意长度的数据,转换后的MD5值长度是固定的,而且MD5的转换操作很容易,只要原数据有一点点改动,转换后结果就会有很大的差异.正是由于MD5算法的这些特性,它经常用于对于一段信息产生信息摘要,以防止其被篡改.其还广泛就于操作系统的登录过程中的安全验证,比如Unix操作系统的密码就是经过MD5加密后存储到文件系统中,当用户登录时输入密码后, 对用户输入的数据经过MD5加密后与原来存储的密文信息比对,如果相同说明密码正确,否则输入的密码就是错误的. MD5以512位为一个计算单位对数据进行分组,每一分组又被划分为16个32位的小组,经过一系列处理后,输出4个32位的小组,最后组成一个128位的哈希值.对处理的数据进行512求余得到N和一个余数,如果余数不为448,填充1和若干个0直到448位为止,最后再加上一个64位用来保存数据的长度,这样经过预处理后,数据变成(N+1)x 512位. 加密.Encode 函数用来加密数据,Check函数传入一个未加密的字符串和与加密后的数据,进行对比,如果正确就返回true.

funcCheck(content,encryptedstring)bool{returnstrings.EqualFold(Encode(content),encrypted)}funcEncode(datastring)string{h:=md5.New()h.Write([]byte(data))returnhex.EncodeToString(h.Sum(nil))}

测试.

funcmain(){strTest:="Ilovethisbeautifulworld!"strEncrypted:="98b4fc4538115c4980a8b859ff3d27e1"fmt.Println(Check(strTest,strEncrypted))}//Output://trueSha1packagemainimport("crypto/sha1""fmt")funcmain(){s:="sha1thisstring"//产生一个散列值得方式是sha1.New(),sha1.Write(bytes),然后sha1.Sum([]byte{}).这里我们从一个新的散列开始.h:=sha1.New()//写入要处理的字节.如果是一个字符串,需要使用[]byte(s)来强制转换成字节数组.h.Write([]byte(s))//这个用来得到最终的散列值的字符切片.Sum的参数可以用来都现有的字符切片追加额外的字节切片:一般不需要要.bs:=h.Sum(nil)//SHA1值经常以16进制输出,例如在gitcommit中.使用%x来将散列结果格式化为16进制字符串.fmt.Println(s)fmt.Printf("%x\n",bs)}

7. SHA

SHA1

packagemainimport("crypto/sha1""fmt")funcmain(){s:="sha1thisstring"h:=sha1.New()h.Write([]byte(s))bs:=h.Sum(nil)fmt.Println(s)fmt.Printf("%x\n",bs)}

SHA256

funcZeroPadding(ciphertext[]byte,blockSizeint)[]byte{padding:=blockSize-len(ciphertext)%blockSizepadtext:=bytes.Repeat([]byte{0},padding)returnappend(ciphertext,padtext...)}funcZeroUnPadding(origData[]byte)[]byte{returnbytes.TrimFunc(origData,func(rrune)bool{returnr==rune(0)})}0

8. Base64

Base64是一种任意二进制到文本字符串的编码方法,常用于在URL,Cookie,网页中传输少量二进制数据. 首先使用Base64编码需要一个含有64个字符的表,这个表由大小写字母,数字,+和/组成.采用Base64编码处理数据时,会把每三个字节共24位作为一个处理单元,再分为四组,每组6位,查表后获得相应的字符即编码后的字符串.编码后的字符串长32位,这样,经Base64编码后,原字符串增长1/3.如果要编码的数据不是3的倍数,最后会剩下一到两个字节,Base64编码中会采用\x00在处理单元后补全,编码后的字符串最后会加上一到两个 = 表示补了几个字节.

funcZeroPadding(ciphertext[]byte,blockSizeint)[]byte{padding:=blockSize-len(ciphertext)%blockSizepadtext:=bytes.Repeat([]byte{0},padding)returnappend(ciphertext,padtext...)}funcZeroUnPadding(origData[]byte)[]byte{returnbytes.TrimFunc(origData,func(rrune)bool{returnr==rune(0)})}1


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/5843.html