主流加密方式

2019-05-26 16:19:13 浏览数 (1)

  • cipher
  • aes
  • des
  • md5
  • sha256
  • dsa
  • ecdsa
  • elliptic
  • hmac
  • rand
  • rc4
  • rsa

aes

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),对称加密

如美国联邦信息处理标准出版物197中所定义的,aes实现 AES 加密(以前称为 Rijndael)。 这个包中的 AES 操作不是使用恒定时间算法实现的。在支持 AES 的硬件支持的系统上运行时会有一个例外,这些操作会使这些操作保持恒定时间。例子包括使用 AES-NI 扩展的 amd64 系统和使用 Message-Security-Assist 扩展的 s390x 系统。在这样的系统中,当 NewCipher 的结果传递给 cipher.NewGCM 时,GCM 使用的 GHASH 操作也是恒定的

我们来演示一下加密解密过程

代码语言:javascript复制
package main

import (
  "bytes"
  "crypto/aes"
  "crypto/cipher"
  "encoding/base64"
  "fmt"
)

func main() {
  testAes()
}

func testAes() {
  // AES-128。key长度:16, 24, 32 bytes 对应 AES-128, AES-192, AES-256
  key := []byte("1234560123456789")
  result, err := AesEncrypt([]byte("123"), key)
  if err != nil {
    panic(err)
  }
  fmt.Println(base64.StdEncoding.EncodeToString(result))
  origData, err := AesDecrypt(result, key)
  if err != nil {
    panic(err)
  }
  fmt.Println(string(origData))
}

// 加密
func AesEncrypt(origData, key []byte) ([]byte, error) {
  // 1.创建密文变量

  block, err := aes.NewCipher(key)
  if err != nil {
    return nil, err
  }
  // 2.获取块的大小
  blockSize := block.BlockSize()
  // 3.使用算法填充数据使其程度成为key的整数倍
  origData = PKCS5Padding(origData, blockSize)
  // origData = ZeroPadding(origData, block.BlockSize())

  // 4.创建加密类型变量
  blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])

  // 5.
  crypted := make([]byte, len(origData))
  // 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
  // crypted := origData

  // 6.开始加密
  blockMode.CryptBlocks(crypted, origData)
  return crypted, nil
}


// 解密
func AesDecrypt(crypted, key []byte) ([]byte, error) {
  // 1.创建密文变量
  block, err := aes.NewCipher(key)
  if err != nil {
    return nil, err
  }
  // 2.获取加密块长度
  blockSize := block.BlockSize()
  
  //3.创建解密数据
  blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
  
  // 4.创建解密后存放数据的变量
  origData := make([]byte, len(crypted))
  // origData := crypted
  
  // 5.解密数据
  blockMode.CryptBlocks(origData, crypted)
  
  // 6.去掉填充
  origData = PKCS5UnPadding(origData)
  // origData = ZeroUnPadding(origData)
  return origData, nil
}

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 {
  length := len(origData)
  unpadding := int(origData[length-1])
  return origData[:(length - unpadding)]
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
  padding := blockSize - len(ciphertext)%blockSize
  padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  return append(ciphertext, padtext...)
}

func PKCS5UnPadding(origData []byte) []byte {
  length := len(origData)
  // 去掉最后一个字节 unpadding 次
  unpadding := int(origData[length-1])
  return origData[:(length - unpadding)]
}

image.png

上面演示把‘123’通过一个秘钥key加密和解密的过程1234560123456789

des

DES算法的入口参数有三个:Key、Data、Mode。其中Key为7个字节共56位,是DES算法的工作密钥;Data为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密

代码语言:javascript复制
package main

import (
"bytes"
"crypto/cipher" //cipher密码
"crypto/des"
"encoding/base64" //将对象转换成字符串
"fmt"
)

/**
 * DES加密方法
 */
func MyDesEncrypt(orig, key string) string{

// 1.将加密内容和秘钥转成字节数组
origData := []byte(orig)
k := []byte(key)

// 2.创建一个加密器
block, _ := des.NewCipher(k)

//3.将明文按秘钥的长度做补全操作
origData = PKCS5Padding(origData, block.BlockSize())

//4.返回一个解密接口-CBC
blockMode := cipher.NewCBCEncrypter(block, k)

//5.创建明文长度的字节数组
crypted := make([]byte, len(origData))

// 6.加密明文
blockMode.CryptBlocks(crypted, origData)

//将字节数组转换成字符串,base64编码
return base64.StdEncoding.EncodeToString(crypted)

}

/**
 * DES解密方法
 */
func MyDESDecrypt(data string, key string) string {

k := []byte(key)

//将加密字符串用base64转换成字节数组
crypted, _ := base64.StdEncoding.DecodeString(data)

//将字节秘钥转换成block快
block, _ := des.NewCipher(k)

//设置解密方式-CBC
blockMode := cipher.NewCBCDecrypter(block, k)

//创建密文大小的数组变量
origData := make([]byte, len(crypted))

//解密密文到数组origData中
blockMode.CryptBlocks(origData, crypted)

//去掉加密时补全的部分
origData = PKCS5UnPadding(origData)

return string(origData)
}

/**
 * 实现明文的补全
 * 如果ciphertext的长度为blockSize的整数倍,则不需要补全
 * 否则差几个则被几个,例:差5个则补5个5
 */
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}

/**
 * 实现去补码,PKCS5Padding的反函数
 */
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}

func main() {

orig := "Hello World!"
fmt.Println("原文:", orig)

//声明秘钥,利用此秘钥实现明文的加密和密文的解密,长度必须为8
key := "12345678"

//加密
encyptCode := MyDesEncrypt(orig, key)
fmt.Println("密文:", encyptCode)

//解密
decyptCode := MyDESDecrypt(encyptCode, key)
fmt.Println("解密结果:", decyptCode)
}
md5

image.png

代码语言:javascript复制
package main
import (
"crypto/md5"
  "fmt"
  "encoding/base64"
)

func main() {
s:= []byte("123456789")
result := md5.Sum(s)
fmt.Println(base64.StdEncoding.EncodeToString(result[:]))
}

image.png

sha256
代码语言:javascript复制
package main

import (
"fmt"
  "encoding/base64"
  "crypto/sha256"
)


func main() {
s:= []byte("123456789")
result := sha256.Sum256(s)
fmt.Println(base64.StdEncoding.EncodeToString(result[:]))
}

image.png

rsa

下面我们看一下dsa的签名过程

代码语言:javascript复制
package main
import (
  "crypto/rand"
  "crypto/rsa"
  "crypto/x509"
  "encoding/pem"
  "os"
)

func main() {
  //rsa 密钥文件产生
  GenRsaKey(1024)
}
//RSA公钥私钥产生
func GenRsaKey(bits int) error {

  // 生成私钥文件
  privateKey, err := rsa.GenerateKey(rand.Reader, bits)
  if err != nil {
    return err
  }
  derStream := x509.MarshalPKCS1PrivateKey(privateKey)
  // 构造pem 结构
  block := &pem.Block{
    Type:  "RSA PRIVATE KEY",
    Bytes: derStream,
  }
  file, err := os.Create("private.pem")
  if err != nil {
    return err
  }
  
  // 将block 结构块 写入文件中
  err = pem.Encode(file, block)
  if err != nil {
    return err
  }

  // 生成公钥文件
  publicKey := &privateKey.PublicKey
  
  // 将公钥转换为 DER-encoded PKIX 格式
  derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
  if err != nil {
    return err
  }
  
  // 生成证书格式
  block = &pem.Block{
    Type:  "PUBLIC KEY",
    Bytes: derPkix,
  }
  file, err = os.Create("public.pem")
  if err != nil {
    return err
  }
  // 生成证书文件
  err = pem.Encode(file, block)
  if err != nil {
    return err
  }
  return nil
}
hmac

hmac包实现了U.S. Federal Information Processing Standards Publication 198规定的HMAC(加密哈希信息认证码)。

HMAC是使用key标记信息的加密hash。接收者使用相同的key逆运算来认证hash。

hmac主要应用在身份验证中,它的使用方法是这样的: (1) 客户端发出登录请求(假设是浏览器的GET请求) (2) 服务器返回一个随机值,并在会话中记录这个随机值 (3) 客户端将该随机值作为密钥,用户密码进行hmac运算,然后提交给服务器 (4) 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的hmac运算,然后与用户发送的结果比较,如果结果一致则验证用户合法

代码语言:javascript复制
package main

import (
  "crypto/hmac"
  "crypto/sha256"
  "encoding/json"
  "fmt"
  "encoding/base64"
)

const key = "asdfasdfasdfasdf"
func main() {
   // 1.服务端发送一个token 给客户端
    serverSendKeyToClient(key)
}

func serverSendKeyToClient(key string){
  // 2.服务器将数据进行hmac 运算,
  keyHash := hmac.New(sha256.New,[]byte(key))
  data := map[string]string{"username":"xujie"}
  s,_:= json.Marshal(data)
  keyHash.Write([]byte(string(s)))

  expectedMAC := keyHash.Sum(nil)
  fmt.Println("客户端计算的hmac:")
  fmt.Println(base64.StdEncoding.EncodeToString(expectedMAC))

  // 3.将运算后的hash 值和数据发送给服务端 服务器
  clientSendMessageToServer(string(s),string(expectedMAC))

}

func clientSendMessageToServer(message,messageMac string){

  // 服务端接受数据后进行hmac 运算 如果结果和客户端传递过来的一致 就表示数据没有被篡改
  fmt.Println(CheckMAC([]byte(message),[]byte(messageMac),[]byte(key)))
  data := map[string]string{}
  json.Unmarshal([]byte(message),data)
  fmt.Println(message)
}

// 如果messageMAC是message的合法HMAC标签,函数返回真
func CheckMAC(message, messageMAC, key []byte) bool {
  mac := hmac.New(sha256.New, key)
  mac.Write(message)
  expectedMAC := mac.Sum(nil)
  fmt.Println("服务器计算的hmac:")
  fmt.Println(base64.StdEncoding.EncodeToString(expectedMAC))
  return hmac.Equal(messageMAC, expectedMAC)
}

image.png

rand
  • func Read(b []byte) (n int, err error)
代码语言:javascript复制
package main

import (
    "fmt"
  "crypto/rand"
  "bytes"
)


func main() {

  c := 10
  b := make([]byte, c)
  
  // 生成随机数填满切片b
  _, err := rand.Read(b)
  if err != nil {
    fmt.Println("error:", err)
    return
  }
  fmt.Println(b)
  // 切片现在应该包含随机字节而不是仅包含零。
  fmt.Println(bytes.Equal(b, make([]byte, c)))
}

0 人点赞