Golang中应用DES加解密

1 DES算法简介

DES算法是由IBM公司在20世纪70年代发展起来的,于1976年11月被美国政府采用,随后被美国国家标准局和美国国家标准协会承认,同时也成为全球范围内事实上的工业标准。 DES是一种对称加密算法,使用的密钥只有一个,发信方和收信方预先知道密钥,使用同一个密钥进行加密和解密。它也是一种可逆加密算法,由加密结果和密钥可以解密出原始数据。

实际应用中,DES是根据其加密算法所定义的明文分组的大小(64bits),将数据割成若干64bits的加密区块,再以加密区块为单位,分别进行加密处理。根据数据加密时每个加密区块间的关联方式,可以分为4种加密模式,包括ECB,CBC,CFB及OFB。 

具体算法原理、安全性以及工作模式请参考论文1

2 Golang中应用DES加解密(ECB和CBC模式)

需引用包 <crypto/des> <crypto/cipher>

首先需要指出的是,由于ECB模式加密算法较简单,Golang中的cipher没有提供ECB模式的加密类。具体实现可参考下面代码。

工具代码<des.go>

import (
    "bytes"
    "crypto/des"
    "encoding/base64"
    "errors"
    "fmt"
)
func DESECBEncrypt(data, key []byte) ([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    bs := block.BlockSize()
    data = PKCS5Padding(data, bs)
    if len(data)%bs != 0 {
        return nil, errors.New("Need a multiple of the blocksize")
    }
    out := make([]byte, len(data))
    dst := out
    for len(data) > 0 {
        block.Encrypt(dst, data[:bs])
        data = data[bs:]
        dst = dst[bs:]
    }
    return out, nil
}
func DESECBDecrypt(data []byte, key []byte) ([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    bs := block.BlockSize()
    if len(data)%bs != 0 {
        return nil, errors.New("crypto/cipher: input not full blocks")
    }
    out := make([]byte, len(data))
    dst := out
    for len(data) > 0 {
        block.Decrypt(dst, data[:bs])
        data = data[bs:]
        dst = dst[bs:]
    }
    out = PKCS5UnPadding(out)
    return out, nil
}

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 encodeBase64(b []byte) string {
    return base64.StdEncoding.EncodeToString(b)
}

func decodeBase64(s string) []byte {
    data, err := base64.StdEncoding.DecodeString(s)
    if err != nil {
        panic(err)
    }
    return data
}

测试代码 <des_test.go>

package crypto

import (
    "testing"
    "time"
)

func Test_desECB(t *testing.T) {
    oridate := "hello world"
    key := time.Now().Format("20060102")

    encryptedbyte, _ := DesECBEncrypt([]byte(oridate), []byte(key))
    encryptedstr := encodeBase64(encryptedbyte)

    t.Logf("data=%s,key=%s,encrypted=%s \n", oridate, key, encryptedstr)

    decryptedbyte, _ := DesECBDecrypt(decodeBase64(encryptedstr), []byte(key))
    decryptedstr := string(decryptedbyte)

    if decryptedstr == oridate {
        t.Log("decrpted ok!")
    } else {
        t.Fail()
    }
}

func Test_desCBC(t *testing.T) {
    oridate := "hello world"
    key := time.Now().Format("20060102")

    encryptedbyte, _ := DesCBCEncrypt([]byte(oridate), []byte(key))
    encryptedstr := encodeBase64(encryptedbyte)

    t.Logf("data=%s,key=%s,encrypted=%s \n", oridate, key, encryptedstr)

    decryptedbyte, _ := DesCBCDecrypt(decodeBase64(encryptedstr), []byte(key))
    decryptedstr := string(decryptedbyte)

    if decryptedstr == oridate {
        t.Log("decrpted ok!")
    } else {
        t.Fail()
    }
}

3 C#中应用DES加解密(ECB模式)

直接贴代码 <des.cs>

using System.Globalization;
using System.Collections.Generic;
using System.Security.Cryptography;  
using System.IO;

public static string Encrypt2(string sourceString, string key)
{
    byte[] btKey = Encoding.Default.GetBytes(key);
    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
    des.Key = btKey;
    des.Mode = CipherMode.ECB;
    using (MemoryStream ms = new MemoryStream())
    {
        byte[] inData = Encoding.Default.GetBytes(sourceString);
        try
        {
            using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(inData, 0, inData.Length);
                cs.FlushFinalBlock();
            }
            return Convert.ToBase64String(ms.ToArray());
        }
        catch
        {
            throw;
        }
    }
}

public static string Decrypt2(string encryptedString, string key)
{
    byte[] btKey = Encoding.Default.GetBytes(key);
    DESCryptoServiceProvider des = new DESCryptoServiceProvider();
    des.Key = btKey;
    des.Mode = CipherMode.ECB;
    using (MemoryStream ms = new MemoryStream())
    {
        byte[] inData = Convert.FromBase64String(encryptedString);
        try
        {
            using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(inData, 0, inData.Length);
                cs.FlushFinalBlock();
            }
            return Encoding.Default.GetString(ms.ToArray());
        }
        catch
        {
            throw;
        }
    }
}

#4 总结 作者对安全领域中的加解密算法原理没有深入研究。本文重点从应用角度探索了一下DES加解密的Golang代码实现。

以上Golang和C#代码中实现的ECB模式加密,经过实际验证,结果是相等的,可以实现跨语言对接。

另有网文2介绍了Golang和Java代码的DES ECB模式加密结果互换。

参考文献:


  1. 褚慧丽. DES算法及其工作模式分析[J]. 商情, 2012(31):194-195. [return]
  2. http://blog.csdn.net/scybs/article/details/38279159 [return]