cfca: extract encrypt/decrypt functions with SM4CBC and SM3 KDF

This commit is contained in:
Sun Yimin 2024-12-11 17:51:31 +08:00 committed by GitHub
parent 65532624e8
commit 6a98350f2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 67 additions and 30 deletions

57
cfca/encrypt.go Normal file
View File

@ -0,0 +1,57 @@
// Copyright 2024 Sun Yimin. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cfca
import (
"crypto/cipher"
"errors"
"github.com/emmansun/gmsm/padding"
"github.com/emmansun/gmsm/sm3"
"github.com/emmansun/gmsm/sm4"
)
// NewSM4CBCBlockMode creates a new SM4-CBC block mode with the password.
func NewSM4CBCBlockMode(password []byte, isEncrypter bool) (cipher.BlockMode, error) {
if len(password) == 0 {
return nil, errors.New("cfca: invalid password")
}
ivkey := sm3.Kdf(password, 32)
block, err := sm4.NewCipher(ivkey[16:])
if err != nil {
return nil, err
}
if isEncrypter {
return cipher.NewCBCEncrypter(block, ivkey[:16]), nil
}
return cipher.NewCBCDecrypter(block, ivkey[:16]), nil
}
// EncryptBySM4CBC encrypts the data with the password using SM4-CBC algorithm.
// Corresponds to the cfca.sadk.util.encryptMessageBySM4 method.
func EncryptBySM4CBC(plaintext, password []byte) ([]byte, error) {
mode, err := NewSM4CBCBlockMode(password, true)
if err != nil {
return nil, err
}
pkcs7 := padding.NewPKCS7Padding(uint(mode.BlockSize()))
plaintext = pkcs7.Pad(plaintext)
ciphertext := make([]byte, len(plaintext))
mode.CryptBlocks(ciphertext, plaintext)
return ciphertext, nil
}
// DecryptBySM4CBC decrypts the data with the password using SM4-CBC algorithm.
// Corresponds to the cfca.sadk.util.decryptMessageBySM4 method.
func DecryptBySM4CBC(ciphertext, password []byte) ([]byte, error) {
mode, err := NewSM4CBCBlockMode(password, false)
if err != nil {
return nil, err
}
plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, ciphertext)
pkcs7 := padding.NewPKCS7Padding(uint(mode.BlockSize()))
return pkcs7.Unpad(plaintext)
}

View File

@ -2,18 +2,14 @@
package cfca package cfca
import ( import (
"crypto/cipher"
"encoding/asn1" "encoding/asn1"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"github.com/emmansun/gmsm/padding"
"github.com/emmansun/gmsm/pkcs" "github.com/emmansun/gmsm/pkcs"
"github.com/emmansun/gmsm/pkcs7" "github.com/emmansun/gmsm/pkcs7"
"github.com/emmansun/gmsm/sm2" "github.com/emmansun/gmsm/sm2"
"github.com/emmansun/gmsm/sm3"
"github.com/emmansun/gmsm/sm4"
"github.com/emmansun/gmsm/smx509" "github.com/emmansun/gmsm/smx509"
) )
@ -59,18 +55,11 @@ func ParseSM2(password, data []byte) (*sm2.PrivateKey, *smx509.Certificate, erro
if !keys.EncryptedKey.Algorithm.Equal(oidSM4) && !keys.EncryptedKey.Algorithm.Equal(oidSM4CBC) { if !keys.EncryptedKey.Algorithm.Equal(oidSM4) && !keys.EncryptedKey.Algorithm.Equal(oidSM4CBC) {
return nil, nil, fmt.Errorf("cfca: unsupported algorithm <%v>", keys.EncryptedKey.Algorithm) return nil, nil, fmt.Errorf("cfca: unsupported algorithm <%v>", keys.EncryptedKey.Algorithm)
} }
ivkey := sm3.Kdf(password, 32) pk, err := DecryptBySM4CBC(keys.EncryptedKey.EncryptedContent.Bytes, password)
marshalledIV, err := asn1.Marshal(ivkey[:16])
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pk, err := pkcs.SM4CBC.Decrypt(ivkey[16:], &asn1.RawValue{FullBytes: marshalledIV}, keys.EncryptedKey.EncryptedContent.Bytes) prvKey, err := sm2.NewPrivateKeyFromInt(new(big.Int).SetBytes(pk))
if err != nil {
return nil, nil, err
}
d := new(big.Int).SetBytes(pk) // here we do NOT check if the d is in (0, N) or not
// Create private key from *big.Int
prvKey, err := sm2.NewPrivateKeyFromInt(d)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -87,22 +76,12 @@ func ParseSM2(password, data []byte) (*sm2.PrivateKey, *smx509.Certificate, erro
// MarshalSM2 encodes sm2 private key and related certificate to cfca defined format // MarshalSM2 encodes sm2 private key and related certificate to cfca defined format
func MarshalSM2(password []byte, key *sm2.PrivateKey, cert *smx509.Certificate) ([]byte, error) { func MarshalSM2(password []byte, key *sm2.PrivateKey, cert *smx509.Certificate) ([]byte, error) {
if len(password) == 0 { var err error
return nil, errors.New("cfca: invalid password") var ciphertext []byte
} if ciphertext, err = EncryptBySM4CBC(key.D.Bytes(), password); err != nil {
ivkey := sm3.Kdf(password, 32)
block, err := sm4.NewCipher(ivkey[16:])
if err != nil {
return nil, err return nil, err
} }
mode := cipher.NewCBCEncrypter(block, ivkey[:16]) if ciphertext, err = asn1.Marshal(ciphertext); err != nil {
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
plainText := pkcs7.Pad(key.D.Bytes())
ciphertext := make([]byte, len(plainText))
mode.CryptBlocks(ciphertext, plainText)
ciphertext, err = asn1.Marshal(ciphertext)
if err != nil {
return nil, err return nil, err
} }

View File

@ -100,8 +100,9 @@ SADK 3.2之后的版本支持下列SM2密文格式(encryptedType)
* 0x04 - C1为非压缩点格式具体是C1C3C2还是C1C2C3取决于解密时的选项参数默认为C1C3C2。 * 0x04 - C1为非压缩点格式具体是C1C3C2还是C1C2C3取决于解密时的选项参数默认为C1C3C2。
* 0x02/0x03 - C1为压缩点格式具体是C1C3C2还是C1C2C3取决于解密时的选项参数默认为C1C3C2。 * 0x02/0x03 - C1为压缩点格式具体是C1C3C2还是C1C2C3取决于解密时的选项参数默认为C1C3C2。
### 生成双密钥CSR v0.29.6+
`cfca.CreateCertificateRequest`和CFCA SADK不同调用者需要自行先生成两对密钥对一对用于签名证书一对用于加解密CFCA生成的加密用私钥文件CFCA加密申请者解密
使用`cfca.ParseEscrowPrivateKey`解析CFCA返回的加密用私钥。
### SM2私钥、证书的解析 ### SM2私钥、证书的解析
这个是CFCA自定义的未见相关标准可以通过```cfca.ParseSM2```来解析。 这个是CFCA自定义的未见相关标准可以通过```cfca.ParseSM2```来解析。
### 生成双密钥CSR
`cfca.CreateCertificateRequest`和CFCA SADK不同调用者需要自行先生成两对密钥对一对用于签名证书一对用于加解密CFCA生成的加密用私钥文件CFCA加密申请者解密