前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >时代新秀golang--golang加密算法之DES

时代新秀golang--golang加密算法之DES

作者头像
糖果
发布2019-11-20 20:35:08
1.7K0
发布2019-11-20 20:35:08
举报
文章被收录于专栏:糖果的实验室糖果的实验室

Go语言的DES加密(CBC模式, ECB模式) ---- 与java加密互通

问题场景:

业务需要对接接口, 采用DES加密方式加密, 于是google一下go的DES加密方式,

go的DES的默认隐藏了ECB模式, 因为go认为ECB不安全, 所以不建议使用,就隐藏了,

然而由于历史遗留问题接口却需要采用ECB模式。

ECB

  • 概念

ECB(电子密本方式)就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

  • 特点
  1. 简单,有利于并行计算,误差不会被传送;
  2. 不能隐藏明文的模式;在密文中出现明文消息的重复
  3. 可能对明文进行主动攻击;加密消息块相互独立成为被攻击的弱点

CBC

  • 概念

CBC(密文分组链接方式)有向量的概念, 它的实现机制使加密的各段数据之间有了联系。

  • 加密步骤:
  1. 首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
  2. 第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)
  3. 第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
  4. 之后的数据以此类推,得到Cn
  5. 按顺序连为C1C2C3......Cn即为加密结果。
  • 解密是加密的逆过程:
  1. 首先将数据按照8个字节一组进行分组得到C1C2C3......Cn
  2. 将第一组数据进行解密后与初始化向量I进行异或得到第一组明文D1(注意:一定是先解密再异或)
  3. 将第二组数据C2进行解密后与第一组密文数据进行异或得到第二组数据D2
  4. 之后依此类推,得到Dn
  5. 按顺序连为D1D2D3......Dn即为解密结果。
  • 特点
  1. 不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

每个密文块依赖于所有的信息明文消息中一个改变会影响所有密文块

  1. 发送方和接收方都需要知道初始化向量
  2. 加密过程是串行的,无法被并行化(在解密时,从两个邻接的密文块中即可得到一个平文块。因此,解密过程可以被并行化。

代码:

代码语言:javascript
复制
//des_ecb_pkcs5padding.go
package main
import (
 "bytes"
 "crypto/des"
 "encoding/base64"
 "errors"
)
//明文补码算法
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 := int(origData[length - 1])
 return origData[:(length - unpadding)]
}
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(src, key []byte) ([]byte, error) {
 block, err := des.NewCipher(key)
 if err != nil {
 return nil, err
    }
 bs := block.BlockSize()
 //对明文数据进行补码
 src = PKCS5Padding(src, bs)
 if len(src) % bs != 0 {
 return nil, errors.New("Need a multiple of the blocksize")
    }
 out := make([]byte, len(src))
 dst := out
 //对明文按照blocksize进行分块加密
 //必要时可以使用go关键字进行并行加密
 for len(src) > 0 {
        block.Encrypt(dst, src[:bs])
 src = src[bs:]
 dst = dst[bs:]
    }
 dstBase64 := make([]byte, base64.StdEncoding.EncodedLen(len(out)))
    base64.StdEncoding.Encode(dstBase64, out)
 return dstBase64, nil
}
func DesDecrypt(src, key []byte) ([]byte, error) {
 srcBase64 := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
 n, err := base64.StdEncoding.Decode(srcBase64, src)
 if err != nil {
 return nil, err
    }
 srcUnBase64 := srcBase64[:n]
 block, err := des.NewCipher(key)
 if err != nil {
 return nil, err
    }
 out := make([]byte, len(srcUnBase64))
 dst := out
 bs := block.BlockSize()
 if len(srcUnBase64) % bs != 0 {
 return nil, errors.New("crypto/cipher: input not full blocks")
    }
 for len(srcUnBase64) > 0 {
        block.Decrypt(dst, srcUnBase64[:bs])
 srcUnBase64 = srcUnBase64[bs:]
 dst = dst[bs:]
    }
 out = PKCS5UnPadding(out)
 return out, nil
}
//main.go 使用DES算法来加密电话号码
package main
import (
 "bufio"
 "flag"
 "fmt"
 "io"
 "os"
 "runtime"
 "sync"
)
const (
 GPNUM = 1000
 //key只能是8位,不能少于8位也不能多于8位.
 KEY = "ImDesKey"
)
var (
 inputFile, outputFile string
)
type outputWriter struct {
    file *os.File
    fWriter *bufio.Writer
    rwMutex *sync.RWMutex
ch chan []byte 
wg *sync.WaitGroup
}
func (ow *outputWriter) Write(row []byte) {
    ow.rwMutex.Lock()
    ow.fWriter.Write(row)
    ow.rwMutex.Unlock()
}
func (ow *outputWriter) Flush() {
    ow.rwMutex.Lock()
    ow.fWriter.Flush()
    ow.rwMutex.Unlock()
}
func (ow *outputWriter) Close() {
    ow.file.Close()
}
func NewOutputWriter(dstFile string, gp int) (*outputWriter, error) {
 f, err := os.OpenFile(dstFile,os.O_WRONLY|os.O_CREATE|os.O_TRUNC,0644)
 if err != nil {
 return nil, err
    }
 w := bufio.NewWriter(f)
ch := make(chan []byte, gp)
return &outputWriter{file:f, fWriter:w, rwMutex:&sync.RWMutex{}, ch:ch, wg:&sync.WaitGroup{}}, nil
}
func init() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    flag.StringVar(&inputFile, "srcfile", "tel.txt", "src file")
    flag.StringVar(&outputFile, "dstfile", "tel_en.txt", "dst file")
    flag.Parse()
}
func concurrentProcess(gp int, src string) {
 //ch := make(chan []byte, gp)
//wg := &sync.WaitGroup{}
 fReader, err := os.Open(src)
 if err != nil {
        fmt.Errorf("Error: %v\n", err)
        os.Exit(1)
    }
 //defer fReader.Close()
 reader := bufio.NewReader(fReader)
 writer, err := NewOutputWriter(outputFile, gp)
 if err != nil {
        fmt.Errorf("Error: %v\n", err)
    }
//defer writer.Close()
 for {
lineBytes, _, err := reader.ReadLine()
 if err == io.EOF {
 break
}
 //tab键的ascii码为9
 //lineBytesSlice := bytes.Split(lineBytes, []byte{9})
 //telBytes := lineBytesSlice[0]
 //provBytes := lineBytesSlice[1]
 //cityBytes := lineBytesSlice[2]
        writer.wg.Add(1)
 go func(ch chan []byte) {
lineWriteBytes := make([]byte,0,45)
telBytes := make([]byte,0,11)
for i:=0;i<=10;i++{
telBytes = append(telBytes, lineBytes[i])
}
//注意:这里不能使用telEnBytes, telEnErr := DesEncrypt(lineBytes[:11], []byte(KEY))来加密电话号码,否则会修改lineBytes[11:]中的内容
telEnBytes, telEnErr := DesEncrypt(telBytes, []byte(KEY))
 if telEnErr != nil {
                fmt.Errorf("Error: %v\n", telEnErr)
 //os.Exit(1)
            }
for i:=0;i<=11;i++ {
lineWriteBytes = append(lineWriteBytes,lineBytes[i])
}
for i:=0;i<=23;i++{
lineWriteBytes = append(lineWriteBytes, telEnBytes[i])
}
for i:=11;i<len(lineBytes);i++{
lineWriteBytes = append(lineWriteBytes, lineBytes[i])
}
//换行的ascii码为10lineBytes[:11]
lineWriteBytes = append(lineWriteBytes,10)
 //writer.Write(lineWriteBytes)
 //writer.Flush()
ch <- lineWriteBytes
 defer writer.wg.Done()
        }(writer.ch)
writer.wg.Add(1)
go func(ch chan []byte) {
writer.Write(<-ch)
writer.Flush()
defer writer.wg.Done()
}(writer.ch)
    }
 //writer.Flush()
    writer.wg.Wait()
    fReader.Close()
writer.Close()
}
func main() {
 concurrentProcess(GPNUM, inputFile)
}
//tel.txt 电话号码文件
13615660000    551    0566 
13665660000    551    0566
13615580000    551    0566
13615670000    551    0566
13615680000    551    0566
13615510000    551    0566
13615600000    551    0566
13615690000    551    0566
13645640000    551    0566
13665540000    551    0566
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 糖果的实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
GPU 云服务器
GPU 云服务器(Cloud GPU Service,GPU)是提供 GPU 算力的弹性计算服务,具有超强的并行计算能力,作为 IaaS 层的尖兵利器,服务于深度学习训练、科学计算、图形图像处理、视频编解码等场景。腾讯云随时提供触手可得的算力,有效缓解您的计算压力,提升业务效率与竞争力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档