From aedef9d00dded3ae13647fd58941a9297b14b002 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Mon, 13 Feb 2023 14:36:34 +0800 Subject: [PATCH] sm9: refactor encrypter mode --- sm9/enc_mode.go | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ sm9/sm9.go | 205 ++++--------------------------------- sm9/sm9_test.go | 76 +++++++++++++- 3 files changed, 357 insertions(+), 190 deletions(-) create mode 100644 sm9/enc_mode.go diff --git a/sm9/enc_mode.go b/sm9/enc_mode.go new file mode 100644 index 0000000..c0b9b27 --- /dev/null +++ b/sm9/enc_mode.go @@ -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 +} diff --git a/sm9/sm9.go b/sm9/sm9.go index 9ed2043..200b29b 100644 --- a/sm9/sm9.go +++ b/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) } diff --git a/sm9/sm9_test.go b/sm9/sm9_test.go index 271044d..23bb723 100644 --- a/sm9/sm9_test.go +++ b/sm9/sm9_test.go @@ -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 {