gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/sm4soft/utils.go (about)

     1  // Copyright (c) 2022 zhaochun
     2  // gmgo is licensed under Mulan PSL v2.
     3  // You can use this software according to the terms and conditions of the Mulan PSL v2.
     4  // You may obtain a copy of Mulan PSL v2 at:
     5  //          http://license.coscl.org.cn/MulanPSL2
     6  // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
     7  // See the Mulan PSL v2 for more details.
     8  
     9  /*
    10  sm4soft 是sm4的纯软实现,基于tjfoc国密算法库`tjfoc/gmsm`做了少量修改。
    11  对应版权声明: thrid_licenses/github.com/tjfoc/gmsm/版权声明
    12  */
    13  
    14  package sm4soft
    15  
    16  import (
    17  	"crypto/rand"
    18  	"encoding/pem"
    19  	"errors"
    20  	"io/ioutil"
    21  
    22  	gmx509 "gitee.com/zhaochuninhefei/gmgo/x509"
    23  )
    24  
    25  // ReadKeyFromPem will return SM4Key from PEM format data.
    26  func ReadKeyFromPem(data []byte, pwd []byte) (SM4Key, error) {
    27  	block, _ := pem.Decode(data)
    28  	if block == nil {
    29  		return nil, errors.New("SM4: pem decode failed")
    30  	}
    31  	if gmx509.IsEncryptedPEMBlock(block) {
    32  		if block.Type != "SM4 ENCRYPTED KEY" {
    33  			return nil, errors.New("SM4: unknown type")
    34  		}
    35  		if len(pwd) == 0 {
    36  			return nil, errors.New("SM4: need passwd")
    37  		}
    38  		data, err := gmx509.DecryptPEMBlock(block, pwd)
    39  		if err != nil {
    40  			return nil, err
    41  		}
    42  		return data, nil
    43  	}
    44  	if block.Type != "SM4 KEY" {
    45  		return nil, errors.New("SM4: unknown type")
    46  	}
    47  	return block.Bytes, nil
    48  }
    49  
    50  // ReadKeyFromPemFile will return SM4Key from filename that saved PEM format data.
    51  func ReadKeyFromPemFile(FileName string, pwd []byte) (SM4Key, error) {
    52  	data, err := ioutil.ReadFile(FileName)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	return ReadKeyFromPem(data, pwd)
    57  }
    58  
    59  // WriteKeyToPem will convert SM4Key to PEM format data and return it.
    60  //goland:noinspection GoUnusedExportedFunction
    61  func WriteKeyToPem(key SM4Key, pwd []byte) ([]byte, error) {
    62  	if pwd != nil {
    63  		block, err := gmx509.EncryptPEMBlock(rand.Reader,
    64  			"SM4 ENCRYPTED KEY", key, pwd, gmx509.PEMCipherAES256) //Use AES256  algorithms to encrypt SM4KEY
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  		return pem.EncodeToMemory(block), nil
    69  	} else {
    70  		block := &pem.Block{
    71  			Type:  "SM4 KEY",
    72  			Bytes: key,
    73  		}
    74  		return pem.EncodeToMemory(block), nil
    75  	}
    76  }
    77  
    78  // WriteKeyToPemFile will convert SM4Key to PEM format data, then write it
    79  // into the input filename.
    80  func WriteKeyToPemFile(FileName string, key SM4Key, pwd []byte) error {
    81  	var block *pem.Block
    82  	var err error
    83  	if pwd != nil {
    84  		block, err = gmx509.EncryptPEMBlock(rand.Reader,
    85  			"SM4 ENCRYPTED KEY", key, pwd, gmx509.PEMCipherAES256)
    86  		if err != nil {
    87  			return err
    88  		}
    89  	} else {
    90  		block = &pem.Block{
    91  			Type:  "SM4 KEY",
    92  			Bytes: key,
    93  		}
    94  	}
    95  	pemBytes := pem.EncodeToMemory(block)
    96  	err = ioutil.WriteFile(FileName, pemBytes, 0666)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	return nil
   101  }
   102  
   103  // WriteKeytoMem sm4密钥转为pem字节数组
   104  //goland:noinspection GoUnusedExportedFunction
   105  func WriteKeytoMem(key SM4Key, pwd []byte) ([]byte, error) {
   106  	if pwd != nil {
   107  		block, err := gmx509.EncryptPEMBlock(rand.Reader,
   108  			"SM4 ENCRYPTED KEY", key, pwd, gmx509.PEMCipherAES256)
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  		return pem.EncodeToMemory(block), nil
   113  	} else {
   114  		block := &pem.Block{
   115  			Type:  "SM4 KEY",
   116  			Bytes: key,
   117  		}
   118  		return pem.EncodeToMemory(block), nil
   119  	}
   120  }
   121  
   122  // ReadKeyFromMem 将pem字节数组转为sm4密钥
   123  //goland:noinspection GoUnusedExportedFunction
   124  func ReadKeyFromMem(data []byte, pwd []byte) (SM4Key, error) {
   125  	block, _ := pem.Decode(data)
   126  	if gmx509.IsEncryptedPEMBlock(block) {
   127  		if block.Type != "SM4 ENCRYPTED KEY" {
   128  			return nil, errors.New("SM4: unknown type")
   129  		}
   130  		if len(pwd) == 0 {
   131  			return nil, errors.New("SM4: need passwd")
   132  		}
   133  		data, err := gmx509.DecryptPEMBlock(block, pwd)
   134  		if err != nil {
   135  			return nil, err
   136  		}
   137  		return data, nil
   138  	}
   139  	if block.Type != "SM4 KEY" {
   140  		return nil, errors.New("SM4: unknown type")
   141  	}
   142  	return block.Bytes, nil
   143  }