pkcs: SM4 oid special handling

This commit is contained in:
Sun Yimin 2023-03-27 13:41:45 +08:00 committed by GitHub
parent 1ed0dbb068
commit d814868a47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 24 additions and 21 deletions

View File

@ -33,8 +33,16 @@ func RegisterCipher(oid asn1.ObjectIdentifier, cipher func() Cipher) {
ciphers[oid.String()] = cipher ciphers[oid.String()] = cipher
} }
func GetCipher(oid asn1.ObjectIdentifier) (Cipher, error) { func GetCipher(alg pkix.AlgorithmIdentifier) (Cipher, error) {
newCipher, ok := ciphers[oid.String()] 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 { if !ok {
return nil, fmt.Errorf("pkcs: unsupported cipher (OID: %s)", oid) 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 return nil, nil, err
} }
mode := smcipher.NewECBEncrypter(block) mode := smcipher.NewECBEncrypter(block)
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
plaintext = pkcs7.Pad(plaintext)
ciphertext := make([]byte, len(plaintext)) ciphertext := make([]byte, len(plaintext))
mode.CryptBlocks(ciphertext, plaintext) mode.CryptBlocks(ciphertext, plaintext)
@ -83,10 +93,14 @@ func (ecb *ecbBlockCipher) Decrypt(key []byte, parameters *asn1.RawValue, cipher
mode := smcipher.NewECBDecrypter(block) mode := smcipher.NewECBDecrypter(block)
plaintext := make([]byte, len(ciphertext)) plaintext := make([]byte, len(ciphertext))
mode.CryptBlocks(plaintext, 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 { type cbcBlockCipher struct {
baseBlockCipher baseBlockCipher
ivSize int ivSize int

View File

@ -20,23 +20,11 @@ func init() {
RegisterCipher(oidSM4GCM, func() Cipher { RegisterCipher(oidSM4GCM, func() Cipher {
return SM4GCM return SM4GCM
}) })
RegisterCipher(oidSM4, func() Cipher {
return SM4
})
RegisterCipher(oidSM4ECB, func() Cipher { RegisterCipher(oidSM4ECB, func() Cipher {
return SM4ECB 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. // SM4ECB is the 128-bit key SM4 cipher in ECB mode.
var SM4ECB = &ecbBlockCipher{ var SM4ECB = &ecbBlockCipher{
baseBlockCipher: baseBlockCipher{ baseBlockCipher: baseBlockCipher{

View File

@ -79,8 +79,7 @@ func (eci encryptedContentInfo) getCiphertext() (ciphertext []byte) {
} }
func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) { func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
alg := eci.ContentEncryptionAlgorithm.Algorithm cipher, err := pkcs.GetCipher(eci.ContentEncryptionAlgorithm)
cipher, err := pkcs.GetCipher(alg)
if err != nil { if err != nil {
return nil, ErrUnsupportedAlgorithm return nil, ErrUnsupportedAlgorithm
} }

View File

@ -169,7 +169,7 @@ func TestCreateSignedEvnvelopedDataSM(t *testing.T) {
} }
sm2Key.D.FillBytes(privKey) 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 { for _, cipher := range testCipers {
saed, err := NewSMSignedAndEnvelopedData(privKey, cipher) saed, err := NewSMSignedAndEnvelopedData(privKey, cipher)
if err != nil { if err != nil {

View File

@ -167,7 +167,7 @@ func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, e
return nil, nil, errors.New("pkcs8: invalid PBES2 parameters") 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 { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -31,6 +31,7 @@ var (
// } // }
// //
// This implementation follows GB/T 35276-2017, uses SM4 cipher to encrypt sm2 private key. // 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) { func MarshalEnvelopedPrivateKey(rand io.Reader, pub *ecdsa.PublicKey, tobeEnveloped *PrivateKey) ([]byte, error) {
// encrypt sm2 private key // encrypt sm2 private key
size := (tobeEnveloped.Curve.Params().N.BitLen() + 7) / 8 size := (tobeEnveloped.Curve.Params().N.BitLen() + 7) / 8
@ -61,7 +62,7 @@ func MarshalEnvelopedPrivateKey(rand io.Reader, pub *ecdsa.PublicKey, tobeEnvelo
// marshal the result // marshal the result
var b cryptobyte.Builder var b cryptobyte.Builder
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(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.AddBytes(encryptedKey)
b.AddASN1BitString(elliptic.Marshal(tobeEnveloped.Curve, tobeEnveloped.X, tobeEnveloped.Y)) b.AddASN1BitString(elliptic.Marshal(tobeEnveloped.Curve, tobeEnveloped.X, tobeEnveloped.Y))
b.AddASN1BitString(encryptedPrivateKey) b.AddASN1BitString(encryptedPrivateKey)
@ -114,6 +115,7 @@ func ParseEnvelopedPrivateKey(priv *PrivateKey, enveloped []byte) (*PrivateKey,
bytes := encryptedPrivateKey.RightAlign() bytes := encryptedPrivateKey.RightAlign()
plaintext := make([]byte, len(bytes)) plaintext := make([]byte, len(bytes))
mode.CryptBlocks(plaintext, 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 := new(PrivateKey)
sm2Key.D = new(big.Int).SetBytes(plaintext) sm2Key.D = new(big.Int).SetBytes(plaintext)
sm2Key.Curve = P256() sm2Key.Curve = P256()