C#、Golang、Python、Java(Android)之間Des、Rsa加解密互通系列之Golang

前言

Golang比較強大,之前筆者在研究區塊鏈的時間總結過加解密,這篇博文裏的代碼在其基礎上進行了整理。筆者下面提供的代碼是經過多語言環境驗證,可以與其他語言互通。

  1. C#、Golang、Python、Java(Android)之間Des、Rsa加解密互通系列之前言
  2. C#、Golang、Python、Java(Android)之間Des、Rsa加解密互通系列之C#
  3. C#、Golang、Python、Java(Android)之間Des、Rsa加解密互通系列之Golang
  4. C#、Golang、Python、Java(Android)之間Des、Rsa加解密互通系列之Python
  5. C#、Golang、Python、Java(Android)之間Des、Rsa加解密互通系列之Java(Android)

代碼

Des對稱加密工具類

package sddes

import (
	"bytes"
	"crypto/cipher"
	"crypto/des"
)

func Encrypt(origData, key []byte, iv []byte) ([]byte, error) {
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}
	origData = PKCS5Padding(origData, block.BlockSize())
	// origData = ZeroPadding(origData, block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block, iv)
	crypted := make([]byte, len(origData))
	// 根據CryptBlocks方法的說明,如下方式初始化crypted也可以
	// crypted := origData
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

func Decrypt(crypted, key []byte, iv []byte) ([]byte, error) {
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockMode := cipher.NewCBCDecrypter(block, iv)
	origData := make([]byte, len(crypted))
	// origData := crypted
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS5UnPadding(origData)
	// origData = ZeroUnPadding(origData)
	return origData, nil
}

// 3DES加密
func TripleEncrypt(origData, key []byte, iv []byte) ([]byte, error) {
	block, err := des.NewTripleDESCipher(key)
	if err != nil {
		return nil, err
	}
	origData = PKCS5Padding(origData, block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block, iv)
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

// 3DES解密
func TripleDecrypt(crypted, key []byte, iv []byte) ([]byte, error) {
	block, err := des.NewTripleDESCipher(key)
	if err != nil {
		return nil, err
	}
	blockMode := cipher.NewCBCDecrypter(block, iv)
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS5UnPadding(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 {
	return bytes.TrimRightFunc(origData, func(r rune) bool {
		return r == rune(0)
	})
}

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)]
}

Rsa密鑰對生成工具類

//生成公鑰和私鑰 pem文件

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/asn1"
	"encoding/pem"
	"flag"
	"log"
	"os"
)

func main() {
	var bits int
	flag.IntVar(&bits, "b", 1024, "祕鑰長度,默認爲1024")
	if err := GenRsaKey(bits); err != nil {
		log.Fatal("祕鑰文件生成失敗")
	}
	log.Println("祕鑰文件生成成功")
}

//生成 PKCS1私鑰、PKCS8私鑰和公鑰文件
func GenRsaKey(bits int) error {
	//生成私鑰文件
	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return err
	}
	derStream := x509.MarshalPKCS1PrivateKey(privateKey)
	block := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: derStream,
	}
	file, err := os.Create("private_key.pem")
	if err != nil {
		return err
	}
	err = pem.Encode(file, block)
	if err != nil {
		return err
	}

	//生成PKCS8私鑰
	pk8Stream := MarshalPKCS8PrivateKey(derStream)
	block = &pem.Block{
		Type:  "PRIVATE KEY",
		Bytes: pk8Stream,
	}
	file, err = os.Create("pkcs8_private_key.pem")
	if err != nil {
		return err
	}
	err = pem.Encode(file, block)
	if err != nil {
		return err
	}

	//生成公鑰文件
	publicKey := &privateKey.PublicKey
	defPkix, err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		return err
	}
	block = &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: defPkix,
	}
	file, err = os.Create("public_key.pem")
	if err != nil {
		return err
	}
	err = pem.Encode(file, block)
	if err != nil {
		return err
	}
	return nil
}

// 由私鑰獲取PKCS8公鑰 這種方式生成的PKCS8與OpenSSL轉成的不一樣,但是BouncyCastle裏可用
func MarshalPKCS8PrivateKey(key []byte) []byte {
	info := struct {
		Version             int
		PrivateKeyAlgorithm []asn1.ObjectIdentifier
		PrivateKey          []byte
	}{}
	info.Version = 0
	info.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
	info.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
	info.PrivateKey = key

	k, err := asn1.Marshal(info)
	if err != nil {
		log.Panic(err.Error())
	}
	return k
}

// 由私鑰獲取PKCS8公鑰
func MarshalPKCS8PrivateKey1(key *rsa.PrivateKey) []byte {
	info := struct {
		Version             int
		PrivateKeyAlgorithm []asn1.ObjectIdentifier
		PrivateKey          []byte
	}{}
	info.Version = 0
	info.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
	info.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
	info.PrivateKey = x509.MarshalPKCS1PrivateKey(key)

	k, err := asn1.Marshal(info)
	if err != nil {
		log.Panic(err.Error())
	}
	return k
}

Rsa加密、解密、簽名、驗籤工具類

//公鑰加密私鑰解密  私鑰簽名公鑰驗證
package sdrsa

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"errors"
)

type PriKeyType uint

const (
	PKCS1 PriKeyType = iota
	PKCS8
)

//私鑰簽名
func Sign(data, privateKey []byte, keyType PriKeyType) ([]byte, error) {
	h := sha256.New()
	h.Write(data)
	hashed := h.Sum(nil)
	priv, err := getPriKey(privateKey, keyType)
	if err != nil {
		return nil, err
	}
	return rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed)
}

//公鑰驗證
func SignVer(data, signature, publicKey []byte) error {
	hashed := sha256.Sum256(data)
	//獲取公鑰
	pub, err := getPubKey(publicKey)
	if err != nil {
		return err
	}
	//驗證簽名
	return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed[:], signature)
}

// 公鑰加密
func Encrypt(data, publicKey []byte) ([]byte, error) {
	//獲取公鑰
	pub, err := getPubKey(publicKey)
	if err != nil {
		return nil, err
	}
	//加密
	return rsa.EncryptPKCS1v15(rand.Reader, pub, data)
}

// 私鑰解密,privateKey爲pem文件裏的字符
func Decrypt(encData, privateKey []byte, keyType PriKeyType) ([]byte, error) {
	//解析PKCS1a或者PKCS8格式的私鑰
	priv, err := getPriKey(privateKey, keyType)
	if err != nil {
		return nil, err
	}
	// 解密
	return rsa.DecryptPKCS1v15(rand.Reader, priv, encData)
}

func getPubKey(publicKey []byte) (*rsa.PublicKey, 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
	}
	// 類型斷言
	if pub, ok := pubInterface.(*rsa.PublicKey); ok {
		return pub, nil
	} else {
		return nil, errors.New("public key error")
	}
}

func getPriKey(privateKey []byte, keyType PriKeyType) (*rsa.PrivateKey, error) {
	//獲取私鑰
	block, _ := pem.Decode(privateKey)
	if block == nil {
		return nil, errors.New("private key error!")
	}
	var priKey *rsa.PrivateKey
	var err error
	switch keyType {
	case PKCS1:
		{
			priKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
			if err != nil {
				return nil, err
			}
		}
	case PKCS8:
		{
			prkI, err := x509.ParsePKCS8PrivateKey(block.Bytes)
			if err != nil {
				return nil, err
			}
			priKey = prkI.(*rsa.PrivateKey)
		}
	default:
		{
			return nil, errors.New("unsupport private key type")
		}
	}
	return priKey, nil
}

github工程源碼

https://github.com/lhtzbj12/go_encryption

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章