2023-01-31 13:50:14 +08:00
|
|
|
// Package sm9 implements ShangMi(SM) sm9 digital signature, encryption and key exchange algorithms.
|
2022-07-15 16:42:39 +08:00
|
|
|
package sm9
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto"
|
2022-08-18 14:49:35 +08:00
|
|
|
goSubtle "crypto/subtle"
|
2022-07-15 16:42:39 +08:00
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"math/big"
|
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
"github.com/emmansun/gmsm/internal/sm9"
|
2022-07-15 16:42:39 +08:00
|
|
|
"github.com/emmansun/gmsm/sm3"
|
|
|
|
"golang.org/x/crypto/cryptobyte"
|
|
|
|
"golang.org/x/crypto/cryptobyte/asn1"
|
|
|
|
)
|
|
|
|
|
|
|
|
// SM9 ASN.1 format reference: Information security technology - SM9 cryptographic algorithm application specification
|
|
|
|
type encryptType byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
ENC_TYPE_XOR encryptType = 0
|
|
|
|
ENC_TYPE_ECB encryptType = 1
|
|
|
|
ENC_TYPE_CBC encryptType = 2
|
|
|
|
ENC_TYPE_OFB encryptType = 4
|
|
|
|
ENC_TYPE_CFB encryptType = 8
|
|
|
|
)
|
|
|
|
|
|
|
|
// Sign signs a hash (which should be the result of hashing a larger message)
|
|
|
|
// using the user dsa key. It returns the signature as a pair of h and s.
|
2022-11-28 10:32:17 +08:00
|
|
|
// Please use SignASN1 instead.
|
2023-06-27 08:57:31 +08:00
|
|
|
//
|
|
|
|
// The signature is randomized. Most applications should use [crypto/rand.Reader]
|
|
|
|
// as rand. Note that the returned signature does not depend deterministically on
|
|
|
|
// the bytes read from rand, and may change between calls and/or between versions.
|
2025-03-13 13:46:14 +08:00
|
|
|
func Sign(rand io.Reader, priv *SignPrivateKey, hash []byte) (*big.Int, []byte, error) {
|
|
|
|
h, s, err := priv.privateKey.Sign(rand, hash, nil)
|
2022-11-28 10:32:17 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
return new(big.Int).SetBytes(h), s, nil
|
|
|
|
|
2022-11-28 10:32:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sign signs digest with user's DSA key, reading randomness from rand. The opts argument
|
|
|
|
// is not currently used but, in keeping with the crypto.Signer interface.
|
|
|
|
// The result is SM9Signature ASN.1 format.
|
2023-06-27 08:57:31 +08:00
|
|
|
//
|
|
|
|
// The signature is randomized. Most applications should use [crypto/rand.Reader]
|
|
|
|
// as rand. Note that the returned signature does not depend deterministically on
|
|
|
|
// the bytes read from rand, and may change between calls and/or between versions.
|
2022-11-28 10:32:17 +08:00
|
|
|
func (priv *SignPrivateKey) Sign(rand io.Reader, hash []byte, opts crypto.SignerOpts) ([]byte, error) {
|
2025-03-13 13:46:14 +08:00
|
|
|
h, s, err := priv.privateKey.Sign(rand, hash, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return encodeSignature(h, s)
|
2022-11-28 10:32:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// SignASN1 signs a hash (which should be the result of hashing a larger message)
|
|
|
|
// using the private key, priv. It returns the ASN.1 encoded signature of type SM9Signature.
|
2023-06-27 08:57:31 +08:00
|
|
|
//
|
|
|
|
// The signature is randomized. Most applications should use [crypto/rand.Reader]
|
|
|
|
// as rand. Note that the returned signature does not depend deterministically on
|
|
|
|
// the bytes read from rand, and may change between calls and/or between versions.
|
2022-11-28 10:32:17 +08:00
|
|
|
func SignASN1(rand io.Reader, priv *SignPrivateKey, hash []byte) ([]byte, error) {
|
2025-03-13 13:46:14 +08:00
|
|
|
return priv.Sign(rand, hash, nil)
|
2022-11-28 10:32:17 +08:00
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
2022-11-28 10:32:17 +08:00
|
|
|
// Verify verifies the signature in h, s of hash using the master dsa public key and user id, uid and hid.
|
|
|
|
// Its return value records whether the signature is valid. Please use VerifyASN1 instead.
|
2025-03-13 13:46:14 +08:00
|
|
|
func Verify(pub *SignMasterPublicKey, uid []byte, hid byte, hash []byte, h *big.Int, s []byte) bool {
|
2022-12-02 14:33:54 +08:00
|
|
|
if h.Sign() <= 0 {
|
|
|
|
return false
|
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
return pub.publicKey.Verify(uid, hid, hash, h.Bytes(), s)
|
2022-11-28 10:32:17 +08:00
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
func encodeSignature(h, s []byte) ([]byte, error) {
|
2022-07-15 16:42:39 +08:00
|
|
|
var b cryptobyte.Builder
|
|
|
|
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
2025-03-13 13:46:14 +08:00
|
|
|
b.AddASN1OctetString(h)
|
|
|
|
b.AddASN1BitString(s)
|
2022-07-15 16:42:39 +08:00
|
|
|
})
|
|
|
|
return b.Bytes()
|
|
|
|
}
|
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
func parseSignature(sig []byte) ([]byte, []byte, error) {
|
2022-11-28 10:32:17 +08:00
|
|
|
var (
|
|
|
|
hBytes []byte
|
|
|
|
sBytes []byte
|
|
|
|
inner cryptobyte.String
|
|
|
|
)
|
|
|
|
input := cryptobyte.String(sig)
|
|
|
|
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
|
|
|
!input.Empty() ||
|
|
|
|
!inner.ReadASN1Bytes(&hBytes, asn1.OCTET_STRING) ||
|
|
|
|
!inner.ReadASN1BitStringAsBytes(&sBytes) ||
|
|
|
|
!inner.Empty() {
|
|
|
|
return nil, nil, errors.New("invalid ASN.1")
|
|
|
|
}
|
|
|
|
if sBytes[0] != 4 {
|
|
|
|
return nil, nil, errors.New("sm9: invalid point format")
|
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
return hBytes, sBytes, nil
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2022-11-28 10:32:17 +08:00
|
|
|
// VerifyASN1 verifies the ASN.1 encoded signature of type SM9Signature, sig, of hash using the
|
|
|
|
// public key, pub. Its return value records whether the signature is valid.
|
|
|
|
func VerifyASN1(pub *SignMasterPublicKey, uid []byte, hid byte, hash, sig []byte) bool {
|
|
|
|
h, s, err := parseSignature(sig)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
return pub.publicKey.Verify(uid, hid, hash, h, s)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Verify verifies the ASN.1 encoded signature, sig, of hash using the
|
|
|
|
// public key, pub. Its return value records whether the signature is valid.
|
|
|
|
func (pub *SignMasterPublicKey) Verify(uid []byte, hid byte, hash, sig []byte) bool {
|
|
|
|
return VerifyASN1(pub, uid, hid, hash, sig)
|
|
|
|
}
|
|
|
|
|
2023-02-10 17:19:50 +08:00
|
|
|
// WrapKey generates and wraps key with reciever's uid and system hid, returns generated key and cipher.
|
2023-06-27 08:57:31 +08:00
|
|
|
//
|
|
|
|
// The rand parameter is used as a source of entropy to ensure that
|
|
|
|
// calls this function twice doesn't result in the same key.
|
|
|
|
// Most applications should use [crypto/rand.Reader] as random.
|
2025-03-13 13:46:14 +08:00
|
|
|
func WrapKey(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, kLen int) ([]byte, []byte, error) {
|
|
|
|
return pub.publicKey.WrapKey(rand, uid, hid, kLen)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// WrapKey wraps key and converts the cipher as ASN1 format, SM9PublicKey1 definition.
|
2023-06-27 08:57:31 +08:00
|
|
|
//
|
|
|
|
// The rand parameter is used as a source of entropy to ensure that
|
|
|
|
// calls this function twice doesn't result in the same key.
|
|
|
|
// Most applications should use [crypto/rand.Reader] as random.
|
2022-07-15 16:42:39 +08:00
|
|
|
func (pub *EncryptMasterPublicKey) WrapKey(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, []byte, error) {
|
|
|
|
key, cipher, err := WrapKey(rand, pub, uid, hid, kLen)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
var b cryptobyte.Builder
|
2025-03-13 13:46:14 +08:00
|
|
|
b.AddASN1BitString(cipher)
|
2022-07-15 16:42:39 +08:00
|
|
|
cipherASN1, err := b.Bytes()
|
|
|
|
|
|
|
|
return key, cipherASN1, err
|
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// WrapKeyASN1 wraps key and converts the result of SM9KeyPackage as ASN1 format. according
|
2022-07-15 16:42:39 +08:00
|
|
|
// SM9 cryptographic algorithm application specification, SM9KeyPackage defnition.
|
2023-06-27 08:57:31 +08:00
|
|
|
//
|
|
|
|
// The rand parameter is used as a source of entropy to ensure that
|
|
|
|
// calls this function twice doesn't result in the same key.
|
|
|
|
// Most applications should use [crypto/rand.Reader] as random.
|
2022-07-15 16:42:39 +08:00
|
|
|
func (pub *EncryptMasterPublicKey) WrapKeyASN1(rand io.Reader, uid []byte, hid byte, kLen int) ([]byte, error) {
|
|
|
|
key, cipher, err := WrapKey(rand, pub, uid, hid, kLen)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var b cryptobyte.Builder
|
|
|
|
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
|
|
|
b.AddASN1OctetString(key)
|
2025-03-13 13:46:14 +08:00
|
|
|
b.AddASN1BitString(cipher)
|
2022-07-15 16:42:39 +08:00
|
|
|
})
|
|
|
|
return b.Bytes()
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalSM9KeyPackage is an utility to unmarshal SM9KeyPackage
|
2025-03-13 13:46:14 +08:00
|
|
|
func UnmarshalSM9KeyPackage(der []byte) (key []byte, cipher []byte, err error) {
|
2022-07-15 16:42:39 +08:00
|
|
|
input := cryptobyte.String(der)
|
|
|
|
var (
|
2025-03-13 13:46:14 +08:00
|
|
|
inner cryptobyte.String
|
2022-07-15 16:42:39 +08:00
|
|
|
)
|
|
|
|
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
|
|
|
!input.Empty() ||
|
|
|
|
!inner.ReadASN1Bytes(&key, asn1.OCTET_STRING) ||
|
2025-03-13 13:46:14 +08:00
|
|
|
!inner.ReadASN1BitStringAsBytes(&cipher) ||
|
2022-07-15 16:42:39 +08:00
|
|
|
!inner.Empty() {
|
|
|
|
return nil, nil, errors.New("sm9: invalid SM9KeyPackage asn.1 data")
|
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
return
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2022-12-06 08:54:53 +08:00
|
|
|
// ErrDecryption represents a failure to decrypt a message.
|
|
|
|
// It is deliberately vague to avoid adaptive attacks.
|
|
|
|
var ErrDecryption = errors.New("sm9: decryption error")
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// ErrEmptyPlaintext represents a failure to encrypt an empty message.
|
|
|
|
var ErrEmptyPlaintext = errors.New("sm9: empty plaintext")
|
|
|
|
|
|
|
|
// UnwrapKey unwraps key from cipher, user id and aligned key length
|
2025-03-13 13:46:14 +08:00
|
|
|
func UnwrapKey(priv *EncryptPrivateKey, uid, cipher []byte, kLen int) ([]byte, error) {
|
|
|
|
return priv.privateKey.UnwrapKey(uid, cipher, kLen)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// UnwrapKey unwraps key from cipherDer, user id and aligned key length.
|
2022-07-15 16:42:39 +08:00
|
|
|
// cipherDer is SM9PublicKey1 format according SM9 cryptographic algorithm application specification.
|
|
|
|
func (priv *EncryptPrivateKey) UnwrapKey(uid, cipherDer []byte, kLen int) ([]byte, error) {
|
|
|
|
var bytes []byte
|
|
|
|
input := cryptobyte.String(cipherDer)
|
|
|
|
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
|
2022-12-06 08:54:53 +08:00
|
|
|
return nil, ErrDecryption
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
return UnwrapKey(priv, uid, bytes, kLen)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// Encrypt encrypts plaintext, returns ciphertext with format C1||C3||C2.
|
2023-02-13 14:36:34 +08:00
|
|
|
func Encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) ([]byte, error) {
|
2023-02-10 17:19:50 +08:00
|
|
|
c1, c2, c3, err := encrypt(rand, pub, uid, hid, plaintext, opts)
|
2022-07-15 16:42:39 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2025-03-13 13:46:14 +08:00
|
|
|
ciphertext := append(c1[1:], c3...)
|
2023-02-10 17:19:50 +08:00
|
|
|
ciphertext = append(ciphertext, c2...)
|
|
|
|
return ciphertext, nil
|
|
|
|
}
|
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) (c1, c2, c3 []byte, err error) {
|
2023-02-10 17:19:50 +08:00
|
|
|
if opts == nil {
|
|
|
|
opts = DefaultEncrypterOpts
|
|
|
|
}
|
2023-02-14 10:45:02 +08:00
|
|
|
if len(plaintext) == 0 {
|
|
|
|
return nil, nil, nil, ErrEmptyPlaintext
|
|
|
|
}
|
2023-02-13 14:36:34 +08:00
|
|
|
key1Len := opts.GetKeySize(plaintext)
|
2023-02-10 17:19:50 +08:00
|
|
|
key, c1, err := WrapKey(rand, pub, uid, hid, key1Len+sm3.Size)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
2023-02-13 14:36:34 +08:00
|
|
|
c2, err = opts.Encrypt(rand, key[:key1Len], plaintext)
|
2023-02-10 17:19:50 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
|
|
|
hash := sm3.New()
|
2023-02-10 17:19:50 +08:00
|
|
|
hash.Write(c2)
|
|
|
|
hash.Write(key[key1Len:])
|
|
|
|
c3 = hash.Sum(nil)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
2023-02-10 17:19:50 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// EncryptASN1 encrypts plaintext and returns ciphertext with ASN.1 format according
|
2022-07-15 16:42:39 +08:00
|
|
|
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
2023-02-13 14:36:34 +08:00
|
|
|
func EncryptASN1(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) ([]byte, error) {
|
2023-02-10 17:19:50 +08:00
|
|
|
return pub.Encrypt(rand, uid, hid, plaintext, opts)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// Encrypt encrypts plaintext and returns ciphertext with ASN.1 format according
|
2022-07-15 16:42:39 +08:00
|
|
|
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
2023-02-13 14:36:34 +08:00
|
|
|
func (pub *EncryptMasterPublicKey) Encrypt(rand io.Reader, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) ([]byte, error) {
|
2023-02-10 17:19:50 +08:00
|
|
|
if opts == nil {
|
|
|
|
opts = DefaultEncrypterOpts
|
|
|
|
}
|
|
|
|
c1, c2, c3, err := encrypt(rand, pub, uid, hid, plaintext, opts)
|
2022-07-15 16:42:39 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var b cryptobyte.Builder
|
|
|
|
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
2023-02-13 14:36:34 +08:00
|
|
|
b.AddASN1Int64(int64(opts.GetEncryptType()))
|
2025-03-13 13:46:14 +08:00
|
|
|
b.AddASN1BitString(c1)
|
2022-07-15 16:42:39 +08:00
|
|
|
b.AddASN1OctetString(c3)
|
2023-02-10 17:19:50 +08:00
|
|
|
b.AddASN1OctetString(c2)
|
2022-07-15 16:42:39 +08:00
|
|
|
})
|
|
|
|
return b.Bytes()
|
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// Decrypt decrypts chipher, the ciphertext should be with format C1||C3||C2
|
2023-02-13 14:36:34 +08:00
|
|
|
func Decrypt(priv *EncryptPrivateKey, uid, ciphertext []byte, opts EncrypterOpts) ([]byte, error) {
|
2023-02-10 17:19:50 +08:00
|
|
|
if opts == nil {
|
|
|
|
opts = DefaultEncrypterOpts
|
|
|
|
}
|
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
c1 := ciphertext[:64]
|
|
|
|
c3c2 := ciphertext[64:]
|
2023-06-16 16:06:38 +08:00
|
|
|
c3 := c3c2[:sm3.Size]
|
2023-02-10 17:19:50 +08:00
|
|
|
c2 := c3c2[sm3.Size:]
|
2023-02-13 14:36:34 +08:00
|
|
|
key1Len := opts.GetKeySize(c2)
|
2023-02-10 17:19:50 +08:00
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
key, err := UnwrapKey(priv, uid, c1, key1Len+sm3.Size)
|
2022-07-15 16:42:39 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-06-16 16:06:38 +08:00
|
|
|
_ = key[key1Len] // bounds check elimination hint
|
2025-03-13 13:46:14 +08:00
|
|
|
return decrypt(key[:key1Len], key[key1Len:], c2, c3, opts)
|
2023-02-10 17:19:50 +08:00
|
|
|
}
|
2022-07-15 16:42:39 +08:00
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
func decrypt(key1, key2, c2, c3 []byte, opts EncrypterOpts) ([]byte, error) {
|
2022-07-15 16:42:39 +08:00
|
|
|
hash := sm3.New()
|
|
|
|
hash.Write(c2)
|
2023-02-10 17:19:50 +08:00
|
|
|
hash.Write(key2)
|
2022-07-15 16:42:39 +08:00
|
|
|
c32 := hash.Sum(nil)
|
|
|
|
|
2023-02-10 17:19:50 +08:00
|
|
|
if goSubtle.ConstantTimeCompare(c3, c32) != 1 {
|
2022-12-06 08:54:53 +08:00
|
|
|
return nil, ErrDecryption
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-13 14:36:34 +08:00
|
|
|
return opts.Decrypt(key1, c2)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// DecryptASN1 decrypts chipher, the ciphertext should be with ASN.1 format according
|
2022-07-15 16:42:39 +08:00
|
|
|
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
|
|
|
func DecryptASN1(priv *EncryptPrivateKey, uid, ciphertext []byte) ([]byte, error) {
|
|
|
|
if len(ciphertext) <= 32+65 {
|
2022-12-06 08:54:53 +08:00
|
|
|
return nil, errors.New("sm9: ciphertext too short")
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
var (
|
|
|
|
encType int
|
|
|
|
c3Bytes []byte
|
|
|
|
c1Bytes []byte
|
|
|
|
c2Bytes []byte
|
|
|
|
inner cryptobyte.String
|
|
|
|
)
|
|
|
|
input := cryptobyte.String(ciphertext)
|
|
|
|
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
2022-10-30 09:46:09 +08:00
|
|
|
!input.Empty() ||
|
2022-07-15 16:42:39 +08:00
|
|
|
!inner.ReadASN1Integer(&encType) ||
|
|
|
|
!inner.ReadASN1BitStringAsBytes(&c1Bytes) ||
|
|
|
|
!inner.ReadASN1Bytes(&c3Bytes, asn1.OCTET_STRING) ||
|
|
|
|
!inner.ReadASN1Bytes(&c2Bytes, asn1.OCTET_STRING) ||
|
|
|
|
!inner.Empty() {
|
|
|
|
return nil, errors.New("sm9: invalid ciphertext asn.1 data")
|
|
|
|
}
|
2023-02-10 17:19:50 +08:00
|
|
|
// We just make assumption block cipher is SM4 and padding scheme is pkcs7
|
2023-02-13 14:36:34 +08:00
|
|
|
opts := shangMiEncrypterOpts(encryptType(encType))
|
|
|
|
if opts == nil {
|
|
|
|
return nil, ErrDecryption
|
|
|
|
}
|
|
|
|
key1Len := opts.GetKeySize(c2Bytes)
|
2025-03-13 13:46:14 +08:00
|
|
|
key, err := UnwrapKey(priv, uid, c1Bytes, key1Len+sm3.Size)
|
2022-07-15 16:42:39 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-06-16 16:06:38 +08:00
|
|
|
_ = key[key1Len] // bounds check elimination hint
|
2025-03-13 13:46:14 +08:00
|
|
|
return decrypt(key[:key1Len], key[key1Len:], c2Bytes, c3Bytes, opts)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// Decrypt decrypts chipher, the ciphertext should be with format C1||C3||C2
|
2023-02-13 14:36:34 +08:00
|
|
|
func (priv *EncryptPrivateKey) Decrypt(uid, ciphertext []byte, opts EncrypterOpts) ([]byte, error) {
|
2023-02-10 17:19:50 +08:00
|
|
|
return Decrypt(priv, uid, ciphertext, opts)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// DecryptASN1 decrypts chipher, the ciphertext should be with ASN.1 format according
|
2023-02-13 15:36:04 +08:00
|
|
|
// SM9 cryptographic algorithm application specification, SM9Cipher definition.
|
|
|
|
func (priv *EncryptPrivateKey) DecryptASN1(uid, ciphertext []byte) ([]byte, error) {
|
|
|
|
return DecryptASN1(priv, uid, ciphertext)
|
|
|
|
}
|
|
|
|
|
2025-03-13 16:50:28 +08:00
|
|
|
// KeyExchange defines an interface for key exchange protocols.
|
|
|
|
// It provides methods for initializing, responding, and confirming key exchanges.
|
|
|
|
//
|
|
|
|
// InitKeyExchange initializes the key exchange process.
|
|
|
|
// It takes a random number generator and a byte identifier as input, and returns
|
|
|
|
// the initial data for the key exchange and an error, if any.
|
|
|
|
//
|
|
|
|
// RespondKeyExchange responds to an initiated key exchange.
|
|
|
|
// It takes a random number generator, a byte identifier, and the peer's initial data
|
|
|
|
// as input, and returns the response data, additional data for confirmation, and an error, if any.
|
|
|
|
//
|
|
|
|
// ConfirmResponder confirms the key exchange from the responder's side.
|
|
|
|
// It takes the responder's response data and additional data as input, and returns
|
|
|
|
// the confirmation data and an error, if any.
|
|
|
|
//
|
|
|
|
// ConfirmInitiator confirms the key exchange from the initiator's side.
|
|
|
|
// It takes the peer's confirmation data as input, and returns the final confirmation data
|
|
|
|
// and an error, if any.
|
|
|
|
// KeyExchange defines an interface for key exchange operations.
|
|
|
|
// It provides methods to initialize, respond, and confirm key exchanges,
|
|
|
|
// as well as a method to destroy the key exchange instance.
|
|
|
|
type KeyExchange interface {
|
|
|
|
// Destroy cleans up any resources associated with the key exchange instance.
|
|
|
|
Destroy()
|
|
|
|
|
|
|
|
// InitKeyExchange initializes the key exchange process.
|
|
|
|
// It takes a random number generator and a byte identifier as input,
|
|
|
|
// and returns the initial data for the key exchange or an error.
|
|
|
|
InitKeyExchange(rand io.Reader, hid byte) ([]byte, error)
|
|
|
|
|
|
|
|
// RespondKeyExchange responds to an initiated key exchange.
|
|
|
|
// It takes a random number generator, a byte identifier, and the peer's initial data as input,
|
|
|
|
// and returns the response data, additional data, or an error.
|
|
|
|
RespondKeyExchange(rand io.Reader, hid byte, peerData []byte) ([]byte, []byte, error)
|
|
|
|
|
|
|
|
// ConfirmResponder confirms the responder's part of the key exchange.
|
|
|
|
// It takes the responder's response data and additional data as input,
|
|
|
|
// and returns the confirmation data or an error.
|
|
|
|
ConfirmResponder(rB, sB []byte) ([]byte, []byte, error)
|
|
|
|
|
|
|
|
// ConfirmInitiator confirms the initiator's part of the key exchange.
|
|
|
|
// It takes the peer's data as input and returns the confirmation data or an error.
|
|
|
|
ConfirmInitiator(peerData []byte) ([]byte, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// keyExchange represents key exchange struct, include internal stat in whole key exchange flow.
|
2022-07-15 16:42:39 +08:00
|
|
|
// Initiator's flow will be: NewKeyExchange -> InitKeyExchange -> transmission -> ConfirmResponder
|
|
|
|
// Responder's flow will be: NewKeyExchange -> waiting ... -> RepondKeyExchange -> transmission -> ConfirmInitiator
|
2025-03-13 16:50:28 +08:00
|
|
|
type keyExchange struct {
|
2025-03-13 13:46:14 +08:00
|
|
|
ke *sm9.KeyExchange
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2025-03-13 16:50:28 +08:00
|
|
|
func (priv *EncryptPrivateKey) NewKeyExchange(uid, peerUID []byte, keyLen int, genSignature bool) *keyExchange {
|
|
|
|
return &keyExchange{ke: priv.privateKey.NewKeyExchange(uid, peerUID, keyLen, genSignature)}
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2025-03-13 16:50:28 +08:00
|
|
|
func (ke *keyExchange) Destroy() {
|
2025-03-13 13:46:14 +08:00
|
|
|
ke.ke.Destroy()
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2023-02-14 10:45:02 +08:00
|
|
|
// InitKeyExchange generates random with responder uid, for initiator's step A1-A4
|
2025-03-13 16:50:28 +08:00
|
|
|
func (ke *keyExchange) InitKeyExchange(rand io.Reader, hid byte) ([]byte, error) {
|
2025-03-13 13:46:14 +08:00
|
|
|
return ke.ke.InitKeyExchange(rand, hid)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
2025-03-13 13:46:14 +08:00
|
|
|
// RespondKeyExchange when responder receive rA, for responder's step B1-B7
|
2025-03-13 16:50:28 +08:00
|
|
|
func (ke *keyExchange) RespondKeyExchange(rand io.Reader, hid byte, peerData []byte) ([]byte, []byte, error) {
|
2025-03-13 13:46:14 +08:00
|
|
|
return ke.ke.RespondKeyExchange(rand, hid, peerData)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// ConfirmResponder for initiator's step A5-A7
|
2025-03-13 16:50:28 +08:00
|
|
|
func (ke *keyExchange) ConfirmResponder(rB, sB []byte) ([]byte, []byte, error) {
|
2025-03-13 13:46:14 +08:00
|
|
|
return ke.ke.ConfirmResponder(rB, sB)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// ConfirmInitiator for responder's step B8
|
2025-03-13 16:50:28 +08:00
|
|
|
func (ke *keyExchange) ConfirmInitiator(peerData []byte) ([]byte, error) {
|
2025-03-13 13:46:14 +08:00
|
|
|
return ke.ke.ConfirmInitiator(peerData)
|
2022-07-15 16:42:39 +08:00
|
|
|
}
|