mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
sm9: refactor encrypter mode
This commit is contained in:
parent
ebf9a74d77
commit
aedef9d00d
266
sm9/enc_mode.go
Normal file
266
sm9/enc_mode.go
Normal file
@ -0,0 +1,266 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"io"
|
||||
|
||||
_cipher "github.com/emmansun/gmsm/cipher"
|
||||
"github.com/emmansun/gmsm/internal/subtle"
|
||||
"github.com/emmansun/gmsm/padding"
|
||||
"github.com/emmansun/gmsm/sm4"
|
||||
)
|
||||
|
||||
// EncrypterOpts is an interface implemented by detail encrypt/decrypt mode.
|
||||
type EncrypterOpts interface {
|
||||
// GetEncryptType returns the encrypt type/mode.
|
||||
GetEncryptType() encryptType
|
||||
// GetKeySize returns key size used by this encrypt mode.
|
||||
GetKeySize(plaintext []byte) int
|
||||
// Encrypt encrypts the plaintext with the key, returns ciphertext.
|
||||
Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error)
|
||||
// Decrypt decrypts the ciphertext with the key, returns plaintext.
|
||||
Decrypt(key, ciphertext []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// XOREncrypterOpts represents XOR encrypt type/mode.
|
||||
type XOREncrypterOpts struct{}
|
||||
|
||||
func (opts *XOREncrypterOpts) GetEncryptType() encryptType {
|
||||
return ENC_TYPE_XOR
|
||||
}
|
||||
|
||||
func (opts *XOREncrypterOpts) GetKeySize(plaintext []byte) int {
|
||||
return len(plaintext)
|
||||
}
|
||||
|
||||
func (opts *XOREncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) {
|
||||
subtle.XORBytes(key, key, plaintext)
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (opts *XOREncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) {
|
||||
subtle.XORBytes(key, ciphertext, key)
|
||||
return key, nil
|
||||
}
|
||||
|
||||
type CipherFactory func(key []byte) (cipher.Block, error)
|
||||
|
||||
type baseBlockEncrypterOpts struct {
|
||||
encryptType encryptType
|
||||
cipherFactory CipherFactory
|
||||
cipherKeySize int
|
||||
}
|
||||
|
||||
func (opts *baseBlockEncrypterOpts) GetEncryptType() encryptType {
|
||||
return opts.encryptType
|
||||
}
|
||||
|
||||
func (opts *baseBlockEncrypterOpts) GetKeySize(plaintext []byte) int {
|
||||
return opts.cipherKeySize
|
||||
}
|
||||
|
||||
type CBCEncrypterOpts struct {
|
||||
baseBlockEncrypterOpts
|
||||
padding padding.Padding
|
||||
}
|
||||
|
||||
func NewCBCEncrypterOpts(padding padding.Padding, cipherFactory CipherFactory, keySize int) EncrypterOpts {
|
||||
opts := new(CBCEncrypterOpts)
|
||||
opts.encryptType = ENC_TYPE_CBC
|
||||
opts.padding = padding
|
||||
opts.cipherFactory = cipherFactory
|
||||
opts.cipherKeySize = keySize
|
||||
return opts
|
||||
}
|
||||
|
||||
func (opts *CBCEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paddedPlainText := opts.padding.Pad(plaintext)
|
||||
blockSize := block.BlockSize()
|
||||
ciphertext := make([]byte, blockSize+len(paddedPlainText))
|
||||
iv := ciphertext[:blockSize]
|
||||
if _, err := io.ReadFull(rand, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext[blockSize:], paddedPlainText)
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func (opts *CBCEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
if len(ciphertext) < blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
iv := ciphertext[:blockSize]
|
||||
ciphertext = ciphertext[blockSize:]
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(plaintext, ciphertext)
|
||||
return opts.padding.Unpad(plaintext)
|
||||
}
|
||||
|
||||
type ECBEncrypterOpts struct {
|
||||
baseBlockEncrypterOpts
|
||||
padding padding.Padding
|
||||
}
|
||||
|
||||
func NewECBEncrypterOpts(padding padding.Padding, cipherFactory CipherFactory, keySize int) EncrypterOpts {
|
||||
opts := new(ECBEncrypterOpts)
|
||||
opts.encryptType = ENC_TYPE_ECB
|
||||
opts.padding = padding
|
||||
opts.cipherFactory = cipherFactory
|
||||
opts.cipherKeySize = keySize
|
||||
return opts
|
||||
}
|
||||
|
||||
func (opts *ECBEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paddedPlainText := opts.padding.Pad(plaintext)
|
||||
ciphertext := make([]byte, len(paddedPlainText))
|
||||
mode := _cipher.NewECBEncrypter(block)
|
||||
mode.CryptBlocks(ciphertext, paddedPlainText)
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func (opts *ECBEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
mode := _cipher.NewECBDecrypter(block)
|
||||
mode.CryptBlocks(plaintext, ciphertext)
|
||||
return opts.padding.Unpad(plaintext)
|
||||
}
|
||||
|
||||
type CFBEncrypterOpts struct {
|
||||
baseBlockEncrypterOpts
|
||||
}
|
||||
|
||||
func NewCFBEncrypterOpts(cipherFactory CipherFactory, keySize int) EncrypterOpts {
|
||||
opts := new(CFBEncrypterOpts)
|
||||
opts.encryptType = ENC_TYPE_CFB
|
||||
opts.cipherFactory = cipherFactory
|
||||
opts.cipherKeySize = keySize
|
||||
return opts
|
||||
}
|
||||
|
||||
func (opts *CFBEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
ciphertext := make([]byte, blockSize+len(plaintext))
|
||||
iv := ciphertext[:blockSize]
|
||||
if _, err := io.ReadFull(rand, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(ciphertext[blockSize:], plaintext)
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func (opts *CFBEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
if len(ciphertext) < blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
iv := ciphertext[:blockSize]
|
||||
ciphertext = ciphertext[blockSize:]
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(plaintext, ciphertext)
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
type OFBEncrypterOpts struct {
|
||||
baseBlockEncrypterOpts
|
||||
}
|
||||
|
||||
func NewOFBEncrypterOpts(cipherFactory CipherFactory, keySize int) EncrypterOpts {
|
||||
opts := new(OFBEncrypterOpts)
|
||||
opts.encryptType = ENC_TYPE_OFB
|
||||
opts.cipherFactory = cipherFactory
|
||||
opts.cipherKeySize = keySize
|
||||
return opts
|
||||
}
|
||||
|
||||
func (opts *OFBEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
ciphertext := make([]byte, blockSize+len(plaintext))
|
||||
iv := ciphertext[:blockSize]
|
||||
if _, err := io.ReadFull(rand, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(ciphertext[blockSize:], plaintext)
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func (opts *OFBEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) {
|
||||
block, err := opts.cipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
if len(ciphertext) < blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
iv := ciphertext[:blockSize]
|
||||
ciphertext = ciphertext[blockSize:]
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(plaintext, ciphertext)
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// DefaultEncrypterOpts default option represents XOR mode
|
||||
var DefaultEncrypterOpts = new(XOREncrypterOpts)
|
||||
|
||||
// SM4ECBEncrypterOpts option represents SM4 ECB mode
|
||||
var SM4ECBEncrypterOpts = NewECBEncrypterOpts(padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// SM4CBCEncrypterOpts option represents SM4 CBC mode
|
||||
var SM4CBCEncrypterOpts = NewCBCEncrypterOpts(padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// SM4CFBEncrypterOpts option represents SM4 CFB mode
|
||||
var SM4CFBEncrypterOpts = NewCFBEncrypterOpts(sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// SM4OFBEncrypterOpts option represents SM4 OFB mode
|
||||
var SM4OFBEncrypterOpts = NewOFBEncrypterOpts(sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
func shangMiEncrypterOpts(encType encryptType) EncrypterOpts {
|
||||
switch encType {
|
||||
case ENC_TYPE_XOR:
|
||||
return DefaultEncrypterOpts
|
||||
case ENC_TYPE_CBC:
|
||||
return SM4CBCEncrypterOpts
|
||||
case ENC_TYPE_ECB:
|
||||
return SM4ECBEncrypterOpts
|
||||
case ENC_TYPE_CFB:
|
||||
return SM4CFBEncrypterOpts
|
||||
case ENC_TYPE_OFB:
|
||||
return SM4OFBEncrypterOpts
|
||||
}
|
||||
return nil
|
||||
}
|
205
sm9/sm9.go
205
sm9/sm9.go
@ -3,21 +3,16 @@ package sm9
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
goSubtle "crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
_cipher "github.com/emmansun/gmsm/cipher"
|
||||
"github.com/emmansun/gmsm/internal/bigmod"
|
||||
"github.com/emmansun/gmsm/internal/subtle"
|
||||
"github.com/emmansun/gmsm/kdf"
|
||||
"github.com/emmansun/gmsm/padding"
|
||||
"github.com/emmansun/gmsm/sm3"
|
||||
"github.com/emmansun/gmsm/sm4"
|
||||
"github.com/emmansun/gmsm/sm9/bn256"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/cryptobyte/asn1"
|
||||
@ -396,52 +391,8 @@ func (priv *EncryptPrivateKey) UnwrapKey(uid, cipherDer []byte, kLen int) ([]byt
|
||||
return UnwrapKey(priv, uid, g, kLen)
|
||||
}
|
||||
|
||||
type CipherFactory func(key []byte) (cipher.Block, error)
|
||||
|
||||
// EncrypterOpts indicate encrypt/decrypt options
|
||||
type EncrypterOpts struct {
|
||||
EncryptType encryptType
|
||||
Padding padding.Padding
|
||||
CipherFactory CipherFactory
|
||||
CipherKeySize int
|
||||
}
|
||||
|
||||
type DecrypterOpts EncrypterOpts
|
||||
|
||||
func (opts *EncrypterOpts) getKeySize(plaintext []byte) int {
|
||||
if opts.EncryptType == ENC_TYPE_XOR {
|
||||
return len(plaintext)
|
||||
}
|
||||
return opts.CipherKeySize
|
||||
}
|
||||
|
||||
// NewEncrypterOpts creates EncrypterOpts with given parameters
|
||||
func NewEncrypterOpts(encType encryptType, padMode padding.Padding, factory CipherFactory, cipherKeySize int) *EncrypterOpts {
|
||||
opts := new(EncrypterOpts)
|
||||
opts.EncryptType = encType
|
||||
opts.Padding = padMode
|
||||
opts.CipherFactory = factory
|
||||
opts.CipherKeySize = cipherKeySize
|
||||
return opts
|
||||
}
|
||||
|
||||
// DefaultEncrypterOpts default option represents XOR mode
|
||||
var DefaultEncrypterOpts = NewEncrypterOpts(ENC_TYPE_XOR, nil, nil, 0)
|
||||
|
||||
// SM4ECBEncrypterOpts option represents SM4 ECB mode
|
||||
var SM4ECBEncrypterOpts = NewEncrypterOpts(ENC_TYPE_ECB, padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// SM4CBCEncrypterOpts option represents SM4 CBC mode
|
||||
var SM4CBCEncrypterOpts = NewEncrypterOpts(ENC_TYPE_CBC, padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// SM4CFBEncrypterOpts option represents SM4 CFB mode
|
||||
var SM4CFBEncrypterOpts = NewEncrypterOpts(ENC_TYPE_CFB, padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// SM4OFBEncrypterOpts option represents SM4 OFB mode
|
||||
var SM4OFBEncrypterOpts = NewEncrypterOpts(ENC_TYPE_OFB, padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
|
||||
// Encrypt encrypt plaintext, output ciphertext with format C1||C3||C2.
|
||||
func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) ([]byte, error) {
|
||||
c1, c2, c3, err := encrypt(rand, pub, uid, hid, plaintext, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -451,16 +402,16 @@ func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte,
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts *EncrypterOpts) (c1 *bn256.G1, c2, c3 []byte, err error) {
|
||||
func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) (c1 *bn256.G1, c2, c3 []byte, err error) {
|
||||
if opts == nil {
|
||||
opts = DefaultEncrypterOpts
|
||||
}
|
||||
key1Len := opts.getKeySize(plaintext)
|
||||
key1Len := opts.GetKeySize(plaintext)
|
||||
key, c1, err := WrapKey(rand, pub, uid, hid, key1Len+sm3.Size)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
c2, err = encryptPlaintext(rand, key[:key1Len], plaintext, opts)
|
||||
c2, err = opts.Encrypt(rand, key[:key1Len], plaintext)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@ -473,77 +424,15 @@ func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte,
|
||||
return
|
||||
}
|
||||
|
||||
func encryptPlaintext(rand io.Reader, key, plaintext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
switch opts.EncryptType {
|
||||
case ENC_TYPE_XOR:
|
||||
subtle.XORBytes(key, key, plaintext)
|
||||
return key, nil
|
||||
case ENC_TYPE_ECB:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paddedPlainText := opts.Padding.Pad(plaintext)
|
||||
ciphertext := make([]byte, len(paddedPlainText))
|
||||
mode := _cipher.NewECBEncrypter(block)
|
||||
mode.CryptBlocks(ciphertext, paddedPlainText)
|
||||
return ciphertext, nil
|
||||
case ENC_TYPE_CBC:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paddedPlainText := opts.Padding.Pad(plaintext)
|
||||
blockSize := block.BlockSize()
|
||||
ciphertext := make([]byte, blockSize+len(paddedPlainText))
|
||||
iv := ciphertext[:blockSize]
|
||||
if _, err := io.ReadFull(rand, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext[blockSize:], paddedPlainText)
|
||||
return ciphertext, nil
|
||||
case ENC_TYPE_CFB:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
ciphertext := make([]byte, blockSize+len(plaintext))
|
||||
iv := ciphertext[:blockSize]
|
||||
if _, err := io.ReadFull(rand, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(ciphertext[blockSize:], plaintext)
|
||||
return ciphertext, nil
|
||||
case ENC_TYPE_OFB:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
ciphertext := make([]byte, blockSize+len(plaintext))
|
||||
iv := ciphertext[:blockSize]
|
||||
if _, err := io.ReadFull(rand, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(ciphertext[blockSize:], plaintext)
|
||||
return ciphertext, nil
|
||||
}
|
||||
return nil, fmt.Errorf("sm9: unsupported encryption type <%v>", opts.EncryptType)
|
||||
}
|
||||
|
||||
// EncryptASN1 encrypt plaintext and output ciphertext with ASN.1 format according
|
||||
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
||||
func EncryptASN1(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
func EncryptASN1(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) ([]byte, error) {
|
||||
return pub.Encrypt(rand, uid, hid, plaintext, opts)
|
||||
}
|
||||
|
||||
// Encrypt encrypt plaintext and output ciphertext with ASN.1 format according
|
||||
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
||||
func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, plaintext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) ([]byte, error) {
|
||||
if opts == nil {
|
||||
opts = DefaultEncrypterOpts
|
||||
}
|
||||
@ -554,7 +443,7 @@ func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte,
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1Int64(int64(opts.EncryptType))
|
||||
b.AddASN1Int64(int64(opts.GetEncryptType()))
|
||||
b.AddASN1BitString(c1.MarshalUncompressed())
|
||||
b.AddASN1OctetString(c3)
|
||||
b.AddASN1OctetString(c2)
|
||||
@ -563,7 +452,7 @@ func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte,
|
||||
}
|
||||
|
||||
// Decrypt decrypt chipher, ciphertext should be with format C1||C3||C2
|
||||
func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte, opts EncrypterOpts) ([]byte, error) {
|
||||
if opts == nil {
|
||||
opts = DefaultEncrypterOpts
|
||||
}
|
||||
@ -575,7 +464,7 @@ func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte, opts *EncrypterOpt
|
||||
}
|
||||
|
||||
c2 := c3c2[sm3.Size:]
|
||||
key1Len := opts.getKeySize(c2)
|
||||
key1Len := opts.GetKeySize(c2)
|
||||
|
||||
key, err := UnwrapKey(priv, uid, c, key1Len+sm3.Size)
|
||||
if err != nil {
|
||||
@ -585,7 +474,7 @@ func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte, opts *EncrypterOpt
|
||||
return decrypt(c, key[:key1Len], key[key1Len:], c2, c3c2[:sm3.Size], opts)
|
||||
}
|
||||
|
||||
func decrypt(cipher *bn256.G1, key1, key2, c2, c3 []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
func decrypt(cipher *bn256.G1, key1, key2, c2, c3 []byte, opts EncrypterOpts) ([]byte, error) {
|
||||
hash := sm3.New()
|
||||
hash.Write(c2)
|
||||
hash.Write(key2)
|
||||
@ -595,70 +484,7 @@ func decrypt(cipher *bn256.G1, key1, key2, c2, c3 []byte, opts *EncrypterOpts) (
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
return decryptCiphertext(key1, c2, opts)
|
||||
}
|
||||
|
||||
func decryptCiphertext(key, ciphertext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
switch opts.EncryptType {
|
||||
case ENC_TYPE_XOR:
|
||||
subtle.XORBytes(key, ciphertext, key)
|
||||
return key, nil
|
||||
case ENC_TYPE_ECB:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
mode := _cipher.NewECBDecrypter(block)
|
||||
mode.CryptBlocks(plaintext, ciphertext)
|
||||
return opts.Padding.Unpad(plaintext)
|
||||
case ENC_TYPE_CBC:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
if len(ciphertext) < blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
iv := ciphertext[:blockSize]
|
||||
ciphertext = ciphertext[blockSize:]
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(plaintext, ciphertext)
|
||||
return opts.Padding.Unpad(plaintext)
|
||||
case ENC_TYPE_CFB:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
if len(ciphertext) < blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
iv := ciphertext[:blockSize]
|
||||
ciphertext = ciphertext[blockSize:]
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(plaintext, ciphertext)
|
||||
return plaintext, nil
|
||||
case ENC_TYPE_OFB:
|
||||
block, err := opts.CipherFactory(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
if len(ciphertext) < blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
iv := ciphertext[:blockSize]
|
||||
ciphertext = ciphertext[blockSize:]
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(plaintext, ciphertext)
|
||||
return plaintext, nil
|
||||
}
|
||||
return nil, fmt.Errorf("sm9: unsupported encryption type <%v>", opts.EncryptType)
|
||||
return opts.Decrypt(key1, c2)
|
||||
}
|
||||
|
||||
// DecryptASN1 decrypt chipher, ciphertext should be with ASN.1 format according
|
||||
@ -685,13 +511,16 @@ func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error
|
||||
return nil, errors.New("sm9: invalid ciphertext asn.1 data")
|
||||
}
|
||||
// We just make assumption block cipher is SM4 and padding scheme is pkcs7
|
||||
opts := NewEncrypterOpts(encryptType(encType), padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize)
|
||||
opts := shangMiEncrypterOpts(encryptType(encType))
|
||||
if opts == nil {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
c, err := unmarshalG1(c1Bytes)
|
||||
if err != nil {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
key1Len := opts.getKeySize(c2Bytes)
|
||||
key1Len := opts.GetKeySize(c2Bytes)
|
||||
key, err := UnwrapKey(priv, uid, c, key1Len+sm3.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -702,7 +531,7 @@ func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error
|
||||
|
||||
// Decrypt decrypt chipher, ciphertext should be with ASN.1 format according
|
||||
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
||||
func (priv *EncryptPrivateKey) Decrypt(uid, ciphertext []byte, opts *EncrypterOpts) ([]byte, error) {
|
||||
func (priv *EncryptPrivateKey) Decrypt(uid, ciphertext []byte, opts EncrypterOpts) ([]byte, error) {
|
||||
if ciphertext[0] == 0x30 { // should be ASN.1 format
|
||||
return DecryptASN1(priv, uid, ciphertext)
|
||||
}
|
||||
|
@ -647,6 +647,78 @@ func TestEncryptSM9Sample(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptSM9SampleBlockMode(t *testing.T) {
|
||||
plaintext := []byte("Chinese IBE standard")
|
||||
expectedMasterPublicKey := "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1"
|
||||
expectedUserPrivateKey := "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1"
|
||||
expectedUserPublicKey := "709d165808b0a43e2574e203fa885abcbab16a240c4c1916552e7c43d09763b8693269a6be2456f43333758274786b6051ff87b7f198da4ba1a2c6e336f51fcc"
|
||||
expectedCipher := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0"
|
||||
expectedKey := "58373260f067ec48667c21c144f8bc33cd3049788651ffd5f738003e51df31174d0e4e402fd87f4581b612f74259db57"
|
||||
expectedCiphertext := "2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0fd3c98dd92c44c68332675a370cceede31e0c5cd209c257601149d12b394a2bee05b6fac6f11b965268c994f00dba7a8bb00fd60583546cbdf4649250863f10a"
|
||||
|
||||
masterKey, err := encryptMasterPrivateKeyFromHex("01EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hex.EncodeToString(masterKey.MasterPublicKey.Marshal()) != expectedMasterPublicKey {
|
||||
t.Errorf("not expected master public key")
|
||||
}
|
||||
|
||||
uid := []byte("Bob")
|
||||
hid := byte(0x03)
|
||||
|
||||
userKey, err := masterKey.GenerateUserKey(uid, hid)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hex.EncodeToString(userKey.PrivateKey.Marshal()) != expectedUserPrivateKey {
|
||||
t.Errorf("not expected user private key")
|
||||
}
|
||||
|
||||
q := masterKey.Public().GenerateUserPublicKey(uid, hid)
|
||||
if hex.EncodeToString(q.Marshal()) != expectedUserPublicKey {
|
||||
t.Errorf("not expected user public key")
|
||||
}
|
||||
|
||||
var r *big.Int = bigFromHex("AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C")
|
||||
cipher, err := new(bn256.G1).ScalarMult(q, bn256.NormalizeScalar(r.Bytes()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hex.EncodeToString(cipher.Marshal()) != expectedCipher {
|
||||
t.Errorf("not expected cipher")
|
||||
}
|
||||
|
||||
g := bn256.Pair(masterKey.Public().MasterPublicKey, bn256.Gen2)
|
||||
w := new(bn256.GT).ScalarMult(g, r)
|
||||
|
||||
var buffer []byte
|
||||
buffer = append(buffer, cipher.Marshal()...)
|
||||
buffer = append(buffer, w.Marshal()...)
|
||||
buffer = append(buffer, uid...)
|
||||
|
||||
key := kdf.Kdf(sm3.New(), buffer, 16+32)
|
||||
|
||||
if hex.EncodeToString(key) != expectedKey {
|
||||
t.Errorf("not expected key, expected %v, got %x\n", expectedKey, key)
|
||||
}
|
||||
|
||||
c2, err := SM4ECBEncrypterOpts.Encrypt(nil, key[:16], plaintext)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hash := sm3.New()
|
||||
hash.Write(c2)
|
||||
hash.Write(key[16:])
|
||||
c3 := hash.Sum(nil)
|
||||
|
||||
ciphertext := append(cipher.Marshal(), c3...)
|
||||
ciphertext = append(ciphertext, c2...)
|
||||
if hex.EncodeToString(ciphertext) != expectedCiphertext {
|
||||
t.Errorf("expected %v, got %v\n", expectedCiphertext, hex.EncodeToString(ciphertext))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
plaintext := []byte("Chinese IBE standard")
|
||||
masterKey, err := GenerateEncryptMasterKey(rand.Reader)
|
||||
@ -659,7 +731,7 @@ func TestEncryptDecrypt(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
encTypes := []*EncrypterOpts{
|
||||
encTypes := []EncrypterOpts{
|
||||
DefaultEncrypterOpts, SM4ECBEncrypterOpts, SM4CBCEncrypterOpts, SM4CFBEncrypterOpts, SM4OFBEncrypterOpts,
|
||||
}
|
||||
for _, opts := range encTypes {
|
||||
@ -699,7 +771,7 @@ func TestEncryptDecryptASN1(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
encTypes := []*EncrypterOpts{
|
||||
encTypes := []EncrypterOpts{
|
||||
DefaultEncrypterOpts, SM4ECBEncrypterOpts, SM4CBCEncrypterOpts, SM4CFBEncrypterOpts, SM4OFBEncrypterOpts,
|
||||
}
|
||||
for _, opts := range encTypes {
|
||||
|
Loading…
x
Reference in New Issue
Block a user