package sdf

import (
	"crypto/cipher"
	"hash"
	"io"

	"xdx.jelly/xgcl/api/common"
	"xdx.jelly/xgcl/grand"
	"xdx.jelly/xgcl/identifier"
	"xdx.jelly/xgcl/mac"
	"xdx.jelly/xgcl/mac/cbcmac"
	"xdx.jelly/xgcl/rsa"
	"xdx.jelly/xgcl/sm/sm1"
	"xdx.jelly/xgcl/sm/sm2"
	"xdx.jelly/xgcl/sm/sm3"
	"xdx.jelly/xgcl/sm/sm4"
)

type Handle uint32
type KeyType int

const (
	// internal use
	KeyTypeUnknow        KeyType = 0
	KeyTypeBlock         KeyType = 0x10 // 对称密钥，SM1 or SM4
	KeyTypeSm1           KeyType = 0x11
	KeyTypeSm4           KeyType = 0x14
	KeyTypeSm2Sign       KeyType = 0x21
	KeyTypeSm2Enc        KeyType = 0x22
	KeyTypeSm9MasterSign KeyType = 0x90
	KeyTypeSm9MasterEnc  KeyType = 0x91
	KeyTypeSm9UserSign   KeyType = 0x92
	KeyTypeSm9UserEnc    KeyType = 0x93

	KeyTypeRsa KeyType = 0x100
)

func (k KeyType) String() string {
	switch k {
	case KeyTypeBlock:
		return "BlockKey"
	case KeyTypeSm1:
		return "Sm1Key"
	case KeyTypeSm2Sign:
		return "Sm2SignKey"
	case KeyTypeSm2Enc:
		return "Sm2EncKey"
	case KeyTypeSm4:
		return "Sm4Key"
	case KeyTypeSm9MasterSign:
		return "Sm9MasterSignKey"
	case KeyTypeSm9MasterEnc:
		return "Sm9MasterEncKey"
	case KeyTypeSm9UserSign:
		return "Sm9UserSignKey"
	case KeyTypeSm9UserEnc:
		return "Sm9UserEncKey"
	case KeyTypeRsa:
		return "RsaKey"
	default:
		// Panic?
		return "unknown"
	}
}

func GetKeyType(s string) KeyType {
	switch {
	case s == "BlockKey":
		return KeyTypeBlock
	case s == "Sm1Key":
		return KeyTypeSm1
	case s == "Sm2SignKey":
		return KeyTypeSm2Sign
	case s == "Sm2EncKey":
		return KeyTypeSm2Enc
	case s == "Sm4Key":
		return KeyTypeSm4
	case s == "Sm9MasterSignKey":
		return KeyTypeSm9MasterSign
	case s == "Sm9MasterEncKey":
		return KeyTypeSm9MasterEnc
	case s == "Sm9UserSignKey":
		return KeyTypeSm9UserSign
	case s == "Sm9UserEncKey":
		return KeyTypeSm9UserEnc
	case s == "RsaKey":
		return KeyTypeRsa
	default:
		return KeyTypeUnknow
	}
}

type SymKey struct {
	keyType KeyType
	key     []byte
}

type Sm2Key struct {
	signKey *sm2.PrivateKey
	encKey  *sm2.PrivateKey
}

func (k *Sm2Key) Key(tpe KeyType) *sm2.PrivateKey {
	if tpe == KeyTypeSm2Sign {
		return k.signKey
	}
	return k.encKey
}

type RsaKey struct {
	signKey *rsa.PrivateKey
	encKey  *rsa.PrivateKey
}

type Sm2Agreement struct {
	param     *sm2.ExchgParameters
	sk        *sm2.PrivateKey
	keyBits   int
	sponsorID []byte
}

var _ Sdfable = &SdfNoLock{}

// SdfNoLock 无锁的SDFable实现。
// GCL作为软算法实例，应看做是一个device。需要进行加锁同步，可多线程共用一个实例。
// 这里的SdfNoLock，避免加锁，适用于单线程中调用。
//
// 若是密码卡的SdfNoLock实例，则看做session，不需加锁，不能多线程共用一个实例。
type SdfNoLock struct {
	rand io.Reader //随机数发生器

	RsaKey map[uint32]*RsaKey // RSAKey -- TODO
	Sm2Key map[uint32]*Sm2Key // SM2Key
	SymKey map[uint32]*SymKey // KEK

	SessionKey   map[Handle]*SymKey
	Sm2Agreement map[Handle]*Sm2Agreement // Sm2密钥交换句柄

	hash hash.Hash
}

var reader = grand.Reader

func (s *SdfNoLock) Marshal() []byte {

	return nil
}

func (s *SdfNoLock) Unmarshal(data []byte) {

}

// //////////////////////////////////////////////////////////////////////////
//
//	Helper function to use gcl with Sdfable interface
//
// /////////////////////////////////////////////////////////////////////////
const (
	minIndex  uint32 = 1000
	maxIndex  uint32 = 10000
	NilIndex  uint32 = ^uint32(0)
	minHandle Handle = 1000
	maxHandle Handle = 10000
	NilHandle Handle = ^Handle(0)
)

func (s *SdfNoLock) GenerateKekAtIndex(keyIndex uint32) error {
	if s.SymKey == nil {
		s.SymKey = make(map[uint32]*SymKey)
	}

	k := &SymKey{
		keyType: KeyTypeBlock,
		key:     make([]byte, sm4.BlockSize),
	}
	s.reader().Read(k.key)
	s.SymKey[keyIndex] = k
	return nil
}

func (s *SdfNoLock) ImportSm2KeyAtIndex(index uint32, tpe KeyType, key *common.ECCrefPrivateKey) (err error) {
	if s.Sm2Key == nil {
		s.Sm2Key = make(map[uint32]*Sm2Key)
	}

	k := &sm2.PrivateKey{}
	if err = k.UnmarshalSDF(key); err != nil {
		return err
	}
	sm2Key, ok := s.Sm2Key[index]
	if !ok {
		sm2Key = new(Sm2Key)
	}
	switch tpe {
	case KeyTypeSm2Sign:
		sm2Key.signKey = k
	case KeyTypeSm2Enc:
		sm2Key.encKey = k
	default:
		return common.SDR_INARGERR
	}
	s.Sm2Key[index] = sm2Key
	return
}

func (s *SdfNoLock) ImportSm2Key(tpe KeyType, key *common.ECCrefPrivateKey) (index uint32, err error) {
	if s.Sm2Key == nil {
		s.Sm2Key = make(map[uint32]*Sm2Key)
	}

	index = minIndex
	var sm2Key *Sm2Key
	var ok bool
	for index < maxIndex {
		if sm2Key, ok = s.Sm2Key[index]; !ok {
			sm2Key = new(Sm2Key)
			break
		} else if sm2Key.Key(tpe) == nil {
			break
		}
		index++
	}
	if index == maxIndex {
		return NilIndex, common.SDR_NOBUFFER
	}

	k := &sm2.PrivateKey{}
	if err = k.UnmarshalSDF(key); err != nil {
		return NilIndex, err
	}
	switch tpe {
	case KeyTypeSm2Sign:
		sm2Key.signKey = k
	case KeyTypeSm2Enc:
		sm2Key.encKey = k
	default:
		return NilIndex, common.SDR_INARGERR
	}
	s.Sm2Key[index] = sm2Key
	return
}

// ImportSessionKey 将key存入s中
// movable, key是否可移动
func (s *SdfNoLock) ImportSessionKey(tpe KeyType, key []byte, movable bool) (handle Handle, err error) {
	if s.SessionKey == nil {
		s.SessionKey = make(map[Handle]*SymKey)
	}
	handle = minHandle
	var ok bool
	for handle < maxHandle {
		if _, ok = s.SessionKey[handle]; !ok {
			break
		}
		handle++
	}
	if handle == maxHandle {
		return NilHandle, common.SDR_NOBUFFER
	}
	if movable {
		s.SessionKey[handle] = &SymKey{
			keyType: tpe,
			key:     key,
		}
	} else {
		s.SessionKey[handle] = &SymKey{
			keyType: tpe,
			key:     append([]byte{}, key...), // make a new one
		}
	}
	return handle, nil
}

// ImportSm2Agreement 将agreement存入s中
func (s *SdfNoLock) ImportSm2Agreement(agreement *Sm2Agreement) (handle Handle, err error) {
	if s.Sm2Agreement == nil {
		s.Sm2Agreement = make(map[Handle]*Sm2Agreement)
	}
	handle = minHandle
	var ok bool
	for handle < maxHandle {
		if _, ok = s.Sm2Agreement[handle]; !ok {
			break
		}
		handle++
	}

	s.Sm2Agreement[handle] = agreement
	return handle, nil
}

func (s *SdfNoLock) reader() io.Reader {
	if s.rand == nil {
		s.rand = reader
	}
	return s.rand
}

func (s *SdfNoLock) getSm2KeyWith(tpe KeyType, index uint32) (*sm2.PrivateKey, bool) {
	if s.Sm2Key == nil {
		return nil, false
	}
	sm2Key, ok := s.Sm2Key[index]
	if !ok {
		return nil, ok
	}
	switch tpe {
	case KeyTypeSm2Sign:
		if sm2Key.signKey != nil {
			return sm2Key.signKey, true
		}
	case KeyTypeSm2Enc:
		if sm2Key.encKey != nil {
			return sm2Key.encKey, true
		}
	}
	return nil, false
}

func (s *SdfNoLock) getKEKWith(index uint32) ([]byte, bool) {
	if s.SymKey == nil {
		return nil, false
	}
	key, ok := s.SymKey[index]
	return key.key, ok
}

func (s *SdfNoLock) getSessionKeyWith(handle Handle) ([]byte, bool) {
	if s.SessionKey == nil {
		return nil, false
	}

	key, ok := s.SessionKey[handle]
	return key.key, ok
}

// //////////////////////////////////////////////////////////////////////////
//
//	Implements of Sdfable functions
//
// /////////////////////////////////////////////////////////////////////////
func (s *SdfNoLock) SDF_OpenSession() error {
	return nil
}

func (s *SdfNoLock) SDF_CloseSession() error {
	return nil
}

func (s *SdfNoLock) SDF_GetDeviceInfo() (*DeviceInfo, error) {
	return devInfo, nil
}

// To be simple, no password
func (s *SdfNoLock) SDF_GetPrivateKeyAccessRight(keyIndex uint32, password []byte) error {
	return nil
}

func (s *SdfNoLock) SDF_ReleasePrivateKeyAccessRight(keyIndex uint32) error {
	return nil
}

func (s *SdfNoLock) SDF_GenerateRandom(buffer []byte) (n uint32, err error) {
	if uint32(len(buffer)) > devInfo.BufferSize {
		return 0, common.SDR_INARGERR
	}
	m, err := io.ReadAtLeast(s.reader(), buffer, int(len(buffer)))
	return uint32(m), err
}

func (s *SdfNoLock) SDF_ExportSignPublicKey_RSA(uiKeyIndex uint32) (*rsa.PublicKey, error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_ExportEncPublicKey_RSA(uiKeyIndex uint32) (*rsa.PublicKey, error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeyPair_RSA(uiKeyBits uint32) (*rsa.PublicKey, *rsa.PrivateKey, error) {
	return nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeyWithIPK_RSA(uiIPKIndex uint32, uiKeyBits uint32) (pucKey []byte, phKeyHandle interface{}, err error) {
	return nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeyWithEPK_RSA(uiKeyBits uint32, pucPublicKey *rsa.PublicKey) (Key []byte, phKeyHandle interface{}, err error) {
	return nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_ImportKeyWithISK_RSA(uiISKIndex uint32, pucKey []byte) (phKeyHandle interface{}, err error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_ExchangeDigitEnvelopeBaseOnRSA(uiKeyIndex uint32, pucPublicKey *rsa.PublicKey, pucDEInput []byte) (pucDEOutput []byte, err error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_DecryptPublicKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error) {
	return nil, common.SDR_NOTSUPPORT
}
func (s *SdfNoLock) SDF_ExportSignPublicKey_ECC(keyIndex uint32) (*sm2.PublicKey, error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Sign, keyIndex)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}
	return &sk.PublicKey, nil
}

func (s *SdfNoLock) SDF_ExportEncPublicKey_ECC(keyIndex uint32) (*sm2.PublicKey, error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, keyIndex)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}
	return &sk.PublicKey, nil
}

func (s *SdfNoLock) SDF_GenerateKeyPair_ECC(algID, keyBits uint32) (*sm2.PublicKey, *sm2.PrivateKey, error) {
	// we do not check the params
	sk, err := sm2.GenerateKey(sm2.Curve(), s.reader())
	if err != nil {
		return nil, nil, common.SDR_RANDERR
	}
	return &sk.PublicKey, sk, nil
}

func (s *SdfNoLock) SDF_GenerateKeyWithIPK_ECC(uiIPKIndex uint32, uiKeyBits uint32) (pucKey *sm2.Cipher, phKeyHandle interface{}, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, uiIPKIndex)
	if !ok {
		return nil, nil, common.SDR_KEYNOTEXIST
	}

	return s.SDF_GenerateKeyWithEPK_ECC(uiKeyBits, identifier.SGDSM23, &sk.PublicKey)
}

func (s *SdfNoLock) SDF_GenerateKeyWithEPK_ECC(uiKeyBits uint32, uiAlgID uint32, pucPublicKey *sm2.PublicKey) (pucKey *sm2.Cipher, phKeyHandle interface{}, err error) {
	keyBytes := (uiKeyBits + 7) / 8
	buf := make([]byte, sm2.ByteSize())
	if n, err := s.SDF_GenerateRandom(buf); err != nil || n != uint32(len(buf)) {
		return nil, nil, common.SDR_RANDERR
	}
	key := make([]byte, keyBytes)
	if n, err := s.SDF_GenerateRandom(key); err != nil || n != keyBytes {
		return nil, nil, common.SDR_RANDERR
	}

	handle, err := s.ImportSessionKey(KeyTypeBlock, key, true)
	if err != nil {
		return nil, nil, err
	}

	pucKey, err = sm2.Encrypt(pucPublicKey, key, buf[keyBytes:])
	if err != nil {
		delete(s.SessionKey, handle)
		if !pucPublicKey.IsValid() {
			return nil, nil, common.SDR_KEYERR
		}
		return nil, nil, common.SDR_INARGERR
	}

	return pucKey, handle, nil
}

func (s *SdfNoLock) SDF_ImportKeyWithISK_ECC(uiISKIndex uint32, pucKey *sm2.Cipher) (phKeyHandle interface{}, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, uiISKIndex)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}
	key, err := s.SDF_ExternalDecrypt_ECC(identifier.SGDSM23, sk, pucKey)
	if err != nil {
		return nil, err
	}
	return s.ImportSessionKey(KeyTypeBlock, key, true)
}

func (s *SdfNoLock) SDF_GenerateAgreementDataWithECC(uiISKIndex uint32, uiKeyBits uint32, pucSponsorID []byte) (pucSponsorPublicKey *sm2.PublicKey, pucSponsorTmpPublicKey *sm2.PublicKey, phAgreementHandle interface{}, err error) {
	return s.SDFEXT_GenerateAgreementDataWithECC(uiISKIndex, uiKeyBits, pucSponsorID)
}

func (s *SdfNoLock) SDF_GenerateKeyWithECC(pucResponseID []byte, pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, hAgreementHandle interface{}) (phKeyHandle interface{}, err error) {
	key, err := s.SDFEXT_GenerateKeyWithECC(pucResponseID, pucResponsePublicKey, pucResponseTmpPublicKey, hAgreementHandle)
	if err != nil {
		return nil, err
	}
	return s.ImportSessionKey(KeyTypeBlock, key, true)
}

func (s *SdfNoLock) SDF_GenerateAgreementDataAndKeyWithECC(uiISKIndex uint32, uiKeyBits uint32, pucResponseID []byte, pucSponsorID []byte, pucSponsorPublicKey, pucSponsorTmpPublicKey *sm2.PublicKey) (pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, phKeyHandle interface{}, err error) {
	return s.SDFEXT_GenerateAgreementDataAndKeyWithECC(uiISKIndex, uiKeyBits, pucResponseID, pucSponsorID, pucSponsorPublicKey, pucSponsorTmpPublicKey)
}

func (s *SdfNoLock) SDF_ExchangeDigitEnvelopeBaseOnECC(uiKeyIndex uint32, uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucEncDataIn *sm2.Cipher) (pucEncDataOut *sm2.Cipher, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, uiKeyIndex)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}

	data, err := sm2.Decrypt(sk, pucEncDataIn)
	if err != nil {
		if !pucPublicKey.IsValid() {
			// pucPublicKey 错误
			return nil, common.SDR_KEYERR
		}
		return nil, common.SDR_ENCDATAERR
	}

	rand := make([]byte, sm2.ByteSize())
	if n, err := s.SDF_GenerateRandom(rand); err != nil || n < uint32(len(rand)) {
		return nil, common.SDR_RANDERR
	}
	return sm2.Encrypt(pucPublicKey, data, rand)
}

func (s *SdfNoLock) SDF_GenerateKeyWithKEK(uiKeyBits uint32, uiAlgID uint32, uiKEKIndex uint32) (pucKey []byte, phKeyHandle interface{}, err error) {
	kek, ok := s.getKEKWith(uiKEKIndex)
	if !ok {
		return nil, nil, common.SDR_KEYNOTEXIST
	}

	keyBytes := (uiKeyBits + 7) / 8

	// 必须是16的倍数。要用SM4ECB加密
	if keyBytes&0xf != 0 {
		return nil, nil, common.SDR_INARGERR
	}

	key := make([]byte, keyBytes)

	if n, err := s.SDF_GenerateRandom(key); err != nil || n != keyBytes {
		return nil, nil, common.SDR_RANDERR
	}

	handle, err := s.ImportSessionKey(KeyTypeBlock, key, true)
	pucKey = make([]byte, len(key))

	// kek should always be 16 bytes. so no err will occure here.
	switch uiAlgID {
	case identifier.SGDSM1ECB:
		_, _ = sm1.EncryptECB(pucKey, kek, key)
	case identifier.SGDSM4ECB:
		_, _ = sm4.EncryptECB(pucKey, kek, key)
	default:
		// 算法id错误
		return nil, nil, common.SDR_ALGNOTSUPPORT
	}

	return pucKey, handle, nil

}

func (s *SdfNoLock) SDF_ImportKeyWithKEK(uiAlgID uint32, uiKEKIndex uint32, pucKey []byte) (phKeyHandle interface{}, err error) {
	kek, ok := s.getKEKWith(uiKEKIndex)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}
	if len(pucKey)&0xf != 0 {
		return nil, common.SDR_INARGERR
	}

	key := make([]byte, len(pucKey))
	// kek should always be 16 bytes. so no err will occure here.
	switch uiAlgID {
	case identifier.SGDSM1ECB:
		_, _ = sm1.DecryptECB(key, kek, pucKey)
	case identifier.SGDSM4ECB:
		_, _ = sm4.DecryptECB(key, kek, pucKey)
	default:
		// 算法id错误
		return nil, common.SDR_ALGNOTSUPPORT
	}

	return s.ImportSessionKey(KeyTypeBlock, key, true)

}

func (s *SdfNoLock) SDF_GenerateKeywithIKE(pucSponsorNonce []byte, pucResponseNonce []byte, pucSponsorCookie []byte, pucResponseCookie []byte, uiPrfAlgID uint32, uiKeyBitsD, uiKeyBitsA, uiKeyBitsE uint32) (phKeyHandleD interface{}, phKeyHandleA interface{}, phKeyHandleE interface{}, err error) {
	return nil, nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeywithEPK_IKE(pucSponsorNonce []byte, pucResponseNonce []byte, pucSponsorCookie []byte, pucResponseCookie []byte, uiPrfAlgID, uiEccAlgID uint32, pucPublicKey sm2.PublicKey, uiKeyBitsD, uiKeyBitsA, uiKeyBitsE uint32) (pucKeyD *sm2.Cipher, phKeyHandleD interface{}, pucKeyA *sm2.Cipher, phKeyHandleA interface{}, pucKeyE *sm2.Cipher, phKeyHandleE interface{}, err error) {
	return nil, nil, nil, nil, nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeywithIPSEC(pucProtocolID []byte, pucSpi []byte, pucSponsorNonce []byte, pucResponseNonce []byte, hKeyHandle interface{}, uiPrfAlgID uint32, uiKeyBitsEnc, uiKeyBitsMac uint32) (phKeyHandleEnc interface{}, phKeyHandleMac interface{}, err error) {
	return nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeywithEPK_IPSEC(pucProtocolID []byte, pucSpi []byte, pucSponsorNonce []byte, pucResponseNonce []byte, hKeyHandle interface{}, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsEnc, uiKeyBitsMac uint32) (pucKeyEnc *sm2.Cipher, phKeyHandleEnc interface{}, pucKeyMac *sm2.Cipher, phKeyHandleMac interface{}, err error) {
	return nil, nil, nil, nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_GenerateKeywithSSL(pucKeyPremaster, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (phKeyHandleClientMac, phKeyHandleServerMac, phKeyHandleClientEnc, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {

	clientMAC, serverMAC, clientKey, serverKey, pucClientIV, pucServerIV := KeysFromPreMasterSecretTLCP(pucKeyPremaster, pucClientRandom, pucServerRandom, sm4.BlockSize, sm4.BlockSize, sm4.BlockSize)

	phKeyHandleClientMac, err = s.ImportSessionKey(KeyTypeBlock, clientMAC, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, err
	}

	phKeyHandleServerMac, err = s.ImportSessionKey(KeyTypeBlock, serverMAC, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, err
	}

	phKeyHandleClientEnc, err = s.ImportSessionKey(KeyTypeBlock, clientKey, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, err
	}

	phKeyHandleServerEnc, err = s.ImportSessionKey(KeyTypeBlock, serverKey, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, err
	}

	return
}

func (s *SdfNoLock) SDF_GenerateKeywithEPK_SSL(pucKeyPremaster, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (pucKeyClientMac *sm2.Cipher, phKeyHandleClientMac interface{}, pucKeyServerMac *sm2.Cipher, phKeyHandleServerMac interface{}, pucKeyClientEnc *sm2.Cipher, phKeyHandleClientEnc interface{}, pucKeyServerEnc *sm2.Cipher, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {

	masterSecret := masterFromPreMasterSecretTLCP(pucKeyPremaster, pucClientRandom, pucServerRandom)
	clientMAC, serverMAC, clientKey, serverKey, pucClientIV, pucServerIV := keysFromMasterSecretTLCP(masterSecret, pucClientRandom, pucServerRandom, sm4.BlockSize, sm4.BlockSize, sm4.BlockSize)

	rnd := make([]byte, sm2.ByteSize())

	if n, err := s.reader().Read(rnd); err != nil || n < len(rnd) {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	pucKeyClientMac, err = sm2.Encrypt(pucPublicKey, clientMAC, rnd)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	phKeyHandleClientMac, err = s.ImportSessionKey(KeyTypeBlock, clientMAC, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}

	if n, err := s.reader().Read(rnd); err != nil || n < len(rnd) {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	pucKeyServerMac, err = sm2.Encrypt(pucPublicKey, serverMAC, rnd)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	phKeyHandleServerMac, err = s.ImportSessionKey(KeyTypeBlock, serverMAC, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}

	if n, err := s.reader().Read(rnd); err != nil || n < len(rnd) {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	pucKeyClientEnc, err = sm2.Encrypt(pucPublicKey, clientKey, rnd)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	phKeyHandleClientEnc, err = s.ImportSessionKey(KeyTypeBlock, clientKey, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}

	if n, err := s.reader().Read(rnd); err != nil || n < len(rnd) {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	pucKeyServerEnc, err = sm2.Encrypt(pucPublicKey, serverKey, rnd)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}
	phKeyHandleServerEnc, err = s.ImportSessionKey(KeyTypeBlock, serverKey, true)
	if err != nil {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
	}

	return
}

func (s *SdfNoLock) SDF_GenerateKeywithECDHE_SSL(phKeyHandlePremaster interface{}, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (phKeyHandleClientMac, phKeyHandleServerMac, phKeyHandleClientEnc, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {
	handle, ok := phKeyHandlePremaster.(Handle)
	if !ok {
		return nil, nil, nil, nil, nil, nil, common.SDR_INARGERR
	}
	preMasterSecret, ok := s.getSessionKeyWith(handle)
	if !ok {
		return nil, nil, nil, nil, nil, nil, common.SDR_KEYNOTEXIST
	}

	return s.SDF_GenerateKeywithSSL(preMasterSecret, pucClientRandom, pucServerRandom, uiPrfAlgID, uiKeyBitsClientEnc, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc)

}

func (s *SdfNoLock) SDF_GenerateKeywithEPK_ECDHE_SSL(phKeyHandlePremaster interface{}, pucClientRandom, pucServerRandom []byte, uiPrfAlgID uint32, uiEccAlgID uint32, pucPublicKey *sm2.PublicKey, uiKeyBitsClientMac, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc uint32) (pucKeyClientMac *sm2.Cipher, phKeyHandleClientMac interface{}, pucKeyServerMac *sm2.Cipher, phKeyHandleServerMac interface{}, pucKeyClientEnc *sm2.Cipher, phKeyHandleClientEnc interface{}, pucKeyServerEnc *sm2.Cipher, phKeyHandleServerEnc interface{}, pucClientIV, pucServerIV []byte, err error) {
	handle, ok := phKeyHandlePremaster.(Handle)
	if !ok {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, common.SDR_INARGERR
	}
	preMasterSecret := [48]byte{1, 1}

	preMasterSecretRandom, ok := s.getSessionKeyWith(handle)
	if !ok {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, common.SDR_KEYNOTEXIST
	}
	if len(preMasterSecretRandom) != 46 {
		return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, common.SDR_KEYERR
	}
	copy(preMasterSecret[2:], preMasterSecretRandom)
	return s.SDF_GenerateKeywithEPK_SSL(preMasterSecret[:], pucClientRandom, pucServerRandom, uiPrfAlgID, uiEccAlgID, pucPublicKey, uiKeyBitsClientEnc, uiKeyBitsServerMac, uiKeyBitsClientEnc, uiKeyBitsServerEnc)
}

func (s *SdfNoLock) SDF_DestroyKey(hKeyHandle interface{}) error {
	handle, ok := hKeyHandle.(Handle)
	if !ok {
		return common.SDR_INARGERR
	}
	if key, ok := s.SessionKey[handle]; ok {
		// 内存置0
		for i := range key.key {
			key.key[i] = 0
		}
		delete(s.SessionKey, handle)
	}
	return nil
}

////////////////////////////////////////////////////////////////////////////
//
//         非对称算法运算类函数
//
///////////////////////////////////////////////////////////////////////////

func (s *SdfNoLock) SDF_ExternalPublicKeyOperation_RSA(pucPublicKey *rsa.PublicKey, pucDataInput []byte) (pucDataOutput []byte, err error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_InternalPublicKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_InternalPrivateKeyOperation_RSA(uiKeyIndex uint32, pucDataInput []byte) (pucDataOutput []byte, err error) {
	return nil, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_ExternalSign_ECC(uiAlgID uint32, pucPrivateKey *sm2.PrivateKey, pucData []byte) (*sm2.Signature, error) {
	if len(pucData) != sm3.Size {
		return nil, common.SDR_INARGERR
	}

	r, S, err := sm2.SignWithReader(s.reader(), pucPrivateKey, pucData)
	return &sm2.Signature{R: r, S: S}, err
}

func (s *SdfNoLock) SDF_ExternalVerify_ECC(uiAlgID uint32,
	pucPublicKey *sm2.PublicKey, pucDataInput []byte,
	pucSignature *sm2.Signature) error {
	if len(pucDataInput) != sm3.Size {
		return common.SDR_INARGERR
	}
	if sm2.Verify(pucDataInput, pucPublicKey, pucSignature) {
		return nil
	} else {
		return common.SDR_VERIFYERR
	}
}

func (s *SdfNoLock) SDF_InternalSign_ECC(iskIndex uint32, data []byte) (signature *sm2.Signature, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Sign, iskIndex)
	if !ok {
		return nil, common.SDR_INARGERR
	}

	r, S, err := sm2.SignWithReader(s.reader(), sk, data)
	return &sm2.Signature{R: r, S: S}, err
}

func (s *SdfNoLock) SDF_InternalVerify_ECC(iskIndex uint32, data []byte, signature *sm2.Signature) error {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Sign, iskIndex)
	if !ok {
		return common.SDR_INARGERR
	}
	ok = sm2.Verify(data, &sk.PublicKey, signature)
	if ok {
		return nil
	} else {
		return common.SDR_SIGNERR
	}
}

func (s *SdfNoLock) SDF_ExternalEncrypt_ECC(
	uiAlgID uint32,
	pucPublicKey *sm2.PublicKey,
	pucData []byte) (pucEncData *sm2.Cipher, err error) {

	// omit the check of uiAlgID
	buf := make([]byte, sm2.ByteSize())
	if n, err := s.SDF_GenerateRandom(buf); err != nil || n < uint32(len(buf)) {
		return nil, common.SDR_RANDERR
	}
	pucEncData, err = sm2.Encrypt(pucPublicKey, pucData, buf)
	if err != nil {
		if !pucPublicKey.IsValid() {
			return nil, common.SDR_KEYERR
		}
		return nil, common.SDR_INARGERR
	}
	return
}

// 外部ECC私钥解密，GMT0018有，36322没有。
func (s *SdfNoLock) SDF_ExternalDecrypt_ECC(uiAlgID uint32, pucPrivateKey *sm2.PrivateKey, pucEncData *sm2.Cipher) (pucData []byte, err error) {
	pucData, err = sm2.Decrypt(pucPrivateKey, pucEncData)
	if err != nil {
		return nil, common.SDR_INARGERR
	}

	return
}

func (s *SdfNoLock) SDF_Encrypt(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte, pucEncData *[]byte) (err error) {
	h, ok := hKeyHandle.(Handle)
	if !ok {
		return common.SDR_KEYERR
	}
	key, ok := s.getSessionKeyWith(h)
	if !ok {
		return common.SDR_KEYNOTEXIST
	}

	if len(pucData)&0xf != 0 {
		return common.SDR_INARGERR
	}

	// expand pucEncData
	for len(pucData) > len(*pucEncData) {
		*pucEncData = append(*pucEncData, 0)
	}

	switch uiAlgID {
	case identifier.SGDSM1ECB:
		sm1.EncryptECB(*pucEncData, key, pucData)

	case identifier.SGDSM1CBC:
		if pucIV == nil || len(pucIV) < sm1.BlockSize {
			return common.SDR_INARGERR
		}
		sm1.EncryptCBC(*pucEncData, pucIV, key, pucData)

	case identifier.SGDSM1CFB:
		if pucIV == nil || len(pucIV) < sm1.BlockSize {
			return common.SDR_INARGERR
		}
		sm1.EncryptCFB(*pucEncData, pucIV, key, pucData)

	case identifier.SGDSM1OFB:
		if pucIV == nil || len(pucIV) < sm1.BlockSize {
			return common.SDR_INARGERR
		}
		sm1.EncryptOFB(*pucEncData, pucIV, key, pucData)

	case identifier.SGDSM4ECB:
		sm4.EncryptECB(*pucEncData, key, pucData)
	case identifier.SGDSM4CBC:
		if pucIV == nil || len(pucIV) < sm4.BlockSize {
			return common.SDR_INARGERR
		}
		sm4.EncryptCBC(*pucEncData, pucIV, key, pucData)

	case identifier.SGDSM4CFB:
		if pucIV == nil || len(pucIV) < sm4.BlockSize {
			return common.SDR_INARGERR
		}
		sm4.EncryptCFB(*pucEncData, pucIV, key, pucData)
	case identifier.SGDSM4OFB:
		if pucIV == nil || len(pucIV) < sm4.BlockSize {
			return common.SDR_INARGERR
		}
		sm4.EncryptOFB(*pucEncData, pucIV, key, pucData)
	default:
		return common.SDR_ALGMODNOTSUPPORT
	}
	return nil
}

func (s *SdfNoLock) SDF_Decrypt(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucEncData []byte, pucData *[]byte) (err error) {
	h, ok := hKeyHandle.(Handle)
	if !ok {
		return common.SDR_KEYERR
	}
	key, ok := s.getSessionKeyWith(h)
	if !ok {
		return common.SDR_KEYNOTEXIST
	}

	if len(pucEncData)&0xf != 0 {
		return common.SDR_INARGERR
	}

	// expand pucEncData
	for len(pucEncData) > len(*pucData) {
		*pucData = append(*pucData, 0)
	}

	switch uiAlgID {
	case identifier.SGDSM1ECB:
		sm1.DecryptECB(*pucData, key, pucEncData)

	case identifier.SGDSM1CBC:
		if pucIV == nil || len(pucIV) < sm1.BlockSize {
			return common.SDR_INARGERR
		}
		sm1.DecryptCBC(*pucData, pucIV, key, pucEncData)

	case identifier.SGDSM1CFB:
		if pucIV == nil || len(pucIV) < sm1.BlockSize {
			return common.SDR_INARGERR
		}
		sm1.DecryptCFB(*pucData, pucIV, key, pucEncData)

	case identifier.SGDSM1OFB:
		if pucIV == nil || len(pucIV) < sm1.BlockSize {
			return common.SDR_INARGERR
		}
		sm1.DecryptOFB(*pucData, pucIV, key, pucEncData)

	case identifier.SGDSM4ECB:
		sm4.DecryptECB(*pucData, key, pucEncData)
	case identifier.SGDSM4CBC:
		if pucIV == nil || len(pucIV) < sm4.BlockSize {
			return common.SDR_INARGERR
		}
		sm4.DecryptCBC(*pucData, pucIV, key, pucEncData)

	case identifier.SGDSM4CFB:
		if pucIV == nil || len(pucIV) < sm4.BlockSize {
			return common.SDR_INARGERR
		}
		sm4.DecryptCFB(*pucData, pucIV, key, pucEncData)
	case identifier.SGDSM4OFB:
		if pucIV == nil || len(pucIV) < sm4.BlockSize {
			return common.SDR_INARGERR
		}
		sm4.DecryptOFB(*pucData, pucIV, key, pucEncData)
	default:
		return common.SDR_ALGMODNOTSUPPORT
	}
	return nil
}

func (s *SdfNoLock) SDF_CalculateMAC(hKeyHandle interface{}, uiAlgID uint32, pucIV []byte, pucData []byte) (pucMAC []byte, err error) {
	h, ok := hKeyHandle.(Handle)
	if !ok {
		return nil, common.SDR_KEYERR
	}
	key, ok := s.getSessionKeyWith(h)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}
	if uiAlgID == identifier.SGDSM3 {
		// SM3-HMAC
		h, err := mac.NewMac(mac.HMAC_SM3, key)
		if err != nil {
			return nil, common.SDR_KEYERR
		}
		pucMAC, err := h.ComputeMAC(pucData)
		if err != nil {
			return nil, common.SDR_KEYERR
		}
		return pucMAC, err
	} else {
		// CBC-MAC
		var block cipher.Block
		switch uiAlgID {
		case identifier.SGDSM1Mac:
			block, err = sm1.NewCipher(key)
		case identifier.SGDSM4Mac:
			block, err = sm4.NewCipher(key)
		default:
			return nil, common.SDR_ALGNOTSUPPORT
		}
		if err != nil {
			return nil, common.SDR_KEYERR
		}

		pucMAC = make([]byte, block.BlockSize())
		err := cbcmac.CalculateMAC(pucData, pucIV, block, pucMAC)
		if err != nil {
			return nil, common.SDR_INARGERR
		}
		return pucMAC, nil
	}
}

func (s *SdfNoLock) SDF_HashInit(uiAlgID uint32, pucPublicKey *sm2.PublicKey, pucID []byte) (err error) {
	if len(pucID) > 0 && pucPublicKey != nil {
		z := sm2.PreComputeWithIdAndPubkey(pucID, pucPublicKey)
		s.hash = sm3.New()
		s.hash.Write(z)
	} else {
		s.hash = sm3.New()
	}
	return nil
}

func (s *SdfNoLock) SDF_HashUpdate(pucData []byte) (err error) {
	if s.hash == nil {
		return common.SDR_STEPERR
	}
	s.hash.Write(pucData)
	return nil
}

func (s *SdfNoLock) SDF_HashFinal() (pucHash []byte, err error) {
	if s.hash == nil {
		return nil, common.SDR_STEPERR
	}
	pucHash = s.hash.Sum(nil)
	s.hash = nil
	return pucHash, nil
}

func (s *SdfNoLock) SDF_CreateFile(pucFileName string, uiFileSize uint32) error {
	return common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_ReadFile(pucFileName string, uiOffset uint32, pucBuffer []byte) (n uint32, err error) {
	return 0, common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_WriteFile(pucFileName string, uiOffset uint32, pucBuffer []byte) error {
	return common.SDR_NOTSUPPORT
}

func (s *SdfNoLock) SDF_DeleteFile(pucFileName string) error {
	return common.SDR_NOTSUPPORT
}

// 内部sm2私钥解密
func (s *SdfNoLock) SDFEXT_InternalDecryptECC(uiKeyIndex uint32, pucEncData *sm2.Cipher) (pucData []byte, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, uiKeyIndex)
	if !ok {
		return nil, common.SDR_KEYNOTEXIST
	}
	pucData, err = sm2.Decrypt(sk, pucEncData)
	if err != nil {
		return nil, common.SDR_INARGERR
	}
	return pucData, nil
}

// 6.3.14   生成密钥协商参数并输出-这个与标准接口一致
// 描述：	使用ECC密钥协商算法, 为计算会话密钥而产生协商参数, 同时返回指定索引位置的ECC公钥、临时ECC密钥对的公钥及协商句柄。
func (s *SdfNoLock) SDFEXT_GenerateAgreementDataWithECC(uiISKIndex uint32, uiKeyBits uint32, pucSponsorID []byte) (pucSponsorPublicKey *sm2.PublicKey, pucSponsorTmpPublicKey *sm2.PublicKey, phAgreementHandle interface{}, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, uiISKIndex)
	if !ok {
		return nil, nil, nil, common.SDR_KEYNOTEXIST
	}

	param, err := sm2.GenerateAgreementData(s.reader())
	if err != nil {
		return nil, nil, nil, common.SDR_RANDERR
	}

	handle, err := s.ImportSm2Agreement(&Sm2Agreement{
		param:     param,
		sk:        sk,
		keyBits:   int(uiKeyBits),
		sponsorID: append([]byte{}, pucSponsorID...), // make a new one
	})
	if err != nil {
		return nil, nil, nil, err
	}

	return &sk.PublicKey, &param.PrivateKey.PublicKey, handle, nil
}

// 6.3.15   计算会话密钥变体
// 描述：	使用ECC密钥协商算法, 使用自身协商句柄和响应方的协商参数计算会话密钥, 同时返回会话密钥。
// 备注：	协商的发起方获得响应方的协商参数后调用本函数, 计算会话密钥。使用SM2算法计算会话密钥的过程见GM/T 0009。
func (s *SdfNoLock) SDFEXT_GenerateKeyWithECC(pucResponseID []byte, pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, hAgreementHandle interface{}) (agreementKey []byte, err error) {
	if s.Sm2Agreement == nil {
		return nil, common.SDR_INARGERR
	}
	handle, ok := hAgreementHandle.(Handle)
	if !ok {
		return nil, common.SDR_INARGERR
	}
	agreement, ok := s.Sm2Agreement[handle]
	if !ok {
		return nil, common.SDR_INARGERR
	}

	key, err := sm2.GenerateSharedKey(agreement.param, agreement.sponsorID, agreement.sk, pucResponseID, pucResponsePublicKey, pucResponseTmpPublicKey, (agreement.keyBits+7)/8)

	if err != nil {
		return nil, common.SDR_INARGERR
	}
	return key, nil
}

// 6.3.16   产生协商数据并计算会话密钥
// 描述：	使用ECC密钥协商算法, 产生协商参数并计算会话密钥, 同时返回产生的协商参数和密钥。
func (s *SdfNoLock) SDFEXT_GenerateAgreementDataAndKeyWithECC(uiISKIndex uint32, uiKeyBits uint32, pucResponseID []byte, pucSponsorID []byte, pucSponsorPublicKey, pucSponsorTmpPublicKey *sm2.PublicKey) (pucResponsePublicKey *sm2.PublicKey, pucResponseTmpPublicKey *sm2.PublicKey, agreementKey []byte, err error) {
	sk, ok := s.getSm2KeyWith(KeyTypeSm2Enc, uiISKIndex)
	if !ok {
		return nil, nil, nil, common.SDR_KEYNOTEXIST
	}

	key, param, err := sm2.GenerateAgreementDataAndKey(pucResponseID, sk, pucSponsorID, pucSponsorPublicKey, pucSponsorTmpPublicKey, int((uiKeyBits+7)/8), s.reader())

	if err != nil {
		return nil, nil, nil, common.SDR_UNKNOWERR
	}

	return &sk.PublicKey, &param.PrivateKey.PublicKey, key, nil
}
