diff --git a/pkcs/cipher.go b/pkcs/cipher.go index 2e03d01..a206c03 100644 --- a/pkcs/cipher.go +++ b/pkcs/cipher.go @@ -33,8 +33,16 @@ func RegisterCipher(oid asn1.ObjectIdentifier, cipher func() Cipher) { ciphers[oid.String()] = cipher } -func GetCipher(oid asn1.ObjectIdentifier) (Cipher, error) { - newCipher, ok := ciphers[oid.String()] +func GetCipher(alg pkix.AlgorithmIdentifier) (Cipher, error) { + oid := alg.Algorithm.String() + if oid == oidSM4.String() { + if len(alg.Parameters.Bytes) != 0 { + return SM4CBC, nil + } else { + return SM4ECB, nil + } + } + newCipher, ok := ciphers[oid] if !ok { return nil, fmt.Errorf("pkcs: unsupported cipher (OID: %s)", oid) } @@ -65,6 +73,8 @@ func (ecb *ecbBlockCipher) Encrypt(key, plaintext []byte) (*pkix.AlgorithmIdenti return nil, nil, err } mode := smcipher.NewECBEncrypter(block) + pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize())) + plaintext = pkcs7.Pad(plaintext) ciphertext := make([]byte, len(plaintext)) mode.CryptBlocks(ciphertext, plaintext) @@ -83,10 +93,14 @@ func (ecb *ecbBlockCipher) Decrypt(key []byte, parameters *asn1.RawValue, cipher mode := smcipher.NewECBDecrypter(block) plaintext := make([]byte, len(ciphertext)) mode.CryptBlocks(plaintext, ciphertext) - return plaintext, nil + pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize())) + unpadded, err := pkcs7.Unpad(plaintext) + if err != nil { // In order to be compatible with some implementations without padding + return plaintext, nil + } + return unpadded, nil } - type cbcBlockCipher struct { baseBlockCipher ivSize int diff --git a/pkcs/cipher_sm4.go b/pkcs/cipher_sm4.go index 45c2de1..159d90e 100644 --- a/pkcs/cipher_sm4.go +++ b/pkcs/cipher_sm4.go @@ -20,23 +20,11 @@ func init() { RegisterCipher(oidSM4GCM, func() Cipher { return SM4GCM }) - RegisterCipher(oidSM4, func() Cipher { - return SM4 - }) RegisterCipher(oidSM4ECB, func() Cipher { return SM4ECB }) } -// SM4 is the 128-bit key SM4 cipher in ECB mode. -var SM4 = &ecbBlockCipher{ - baseBlockCipher: baseBlockCipher{ - keySize: 16, - newBlock: sm4.NewCipher, - oid: oidSM4, - }, -} - // SM4ECB is the 128-bit key SM4 cipher in ECB mode. var SM4ECB = &ecbBlockCipher{ baseBlockCipher: baseBlockCipher{ diff --git a/pkcs7/decrypt.go b/pkcs7/decrypt.go index d21b0b9..4478c9f 100644 --- a/pkcs7/decrypt.go +++ b/pkcs7/decrypt.go @@ -79,8 +79,7 @@ func (eci encryptedContentInfo) getCiphertext() (ciphertext []byte) { } func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) { - alg := eci.ContentEncryptionAlgorithm.Algorithm - cipher, err := pkcs.GetCipher(alg) + cipher, err := pkcs.GetCipher(eci.ContentEncryptionAlgorithm) if err != nil { return nil, ErrUnsupportedAlgorithm } diff --git a/pkcs7/sign_enveloped_test.go b/pkcs7/sign_enveloped_test.go index e28ccbf..f9ccaf3 100644 --- a/pkcs7/sign_enveloped_test.go +++ b/pkcs7/sign_enveloped_test.go @@ -169,7 +169,7 @@ func TestCreateSignedEvnvelopedDataSM(t *testing.T) { } sm2Key.D.FillBytes(privKey) - testCipers := []pkcs.Cipher{pkcs.SM4, pkcs.SM4ECB, pkcs.SM4CBC, pkcs.SM4GCM} + testCipers := []pkcs.Cipher{pkcs.SM4ECB, pkcs.SM4CBC, pkcs.SM4GCM} for _, cipher := range testCipers { saed, err := NewSMSignedAndEnvelopedData(privKey, cipher) if err != nil { diff --git a/pkcs8/pkcs8.go b/pkcs8/pkcs8.go index 6f43152..474e2ec 100644 --- a/pkcs8/pkcs8.go +++ b/pkcs8/pkcs8.go @@ -167,7 +167,7 @@ func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, e return nil, nil, errors.New("pkcs8: invalid PBES2 parameters") } - cipher, err := pkcs.GetCipher(params.EncryptionScheme.Algorithm) + cipher, err := pkcs.GetCipher(params.EncryptionScheme) if err != nil { return nil, nil, err } diff --git a/sm2/sm2_envelopedkey.go b/sm2/sm2_envelopedkey.go index 0a76786..ca22c63 100644 --- a/sm2/sm2_envelopedkey.go +++ b/sm2/sm2_envelopedkey.go @@ -31,6 +31,7 @@ var ( // } // // This implementation follows GB/T 35276-2017, uses SM4 cipher to encrypt sm2 private key. +// Please note the standard did NOT clarify if the ECB mode requires padding or not. func MarshalEnvelopedPrivateKey(rand io.Reader, pub *ecdsa.PublicKey, tobeEnveloped *PrivateKey) ([]byte, error) { // encrypt sm2 private key size := (tobeEnveloped.Curve.Params().N.BitLen() + 7) / 8 @@ -61,7 +62,7 @@ func MarshalEnvelopedPrivateKey(rand io.Reader, pub *ecdsa.PublicKey, tobeEnvelo // marshal the result var b cryptobyte.Builder b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { - b.AddASN1ObjectIdentifier(oidSM4) // use oidSM4ECB? + b.AddASN1ObjectIdentifier(oidSM4ECB) // use oidSM4? b.AddBytes(encryptedKey) b.AddASN1BitString(elliptic.Marshal(tobeEnveloped.Curve, tobeEnveloped.X, tobeEnveloped.Y)) b.AddASN1BitString(encryptedPrivateKey) @@ -114,6 +115,7 @@ func ParseEnvelopedPrivateKey(priv *PrivateKey, enveloped []byte) (*PrivateKey, bytes := encryptedPrivateKey.RightAlign() plaintext := make([]byte, len(bytes)) mode.CryptBlocks(plaintext, bytes) + // Do we need to check length in order to be compatible with some implementations with padding? sm2Key := new(PrivateKey) sm2Key.D = new(big.Int).SetBytes(plaintext) sm2Key.Curve = P256()