github.com/incognitochain/go-incognito-sdk@v1.0.1/privacy/hybridencryption.go (about)

     1  package privacy
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"github.com/incognitochain/go-incognito-sdk/common"
     7  	"github.com/incognitochain/go-incognito-sdk/common/base58"
     8  )
     9  
    10  // hybridCipherText_Old represents to hybridCipherText_Old for Hybrid encryption
    11  // Hybrid encryption uses AES scheme to encrypt message with arbitrary size
    12  // and uses Elgamal encryption to encrypt AES key
    13  type HybridCipherText struct {
    14  	msgEncrypted    []byte
    15  	symKeyEncrypted []byte
    16  }
    17  
    18  func (ciphertext HybridCipherText) GetMsgEncrypted() []byte {
    19  	return ciphertext.msgEncrypted
    20  }
    21  
    22  func (ciphertext HybridCipherText) GetSymKeyEncrypted() []byte {
    23  	return ciphertext.symKeyEncrypted
    24  }
    25  
    26  // isNil check whether ciphertext is nil or not
    27  func (ciphertext HybridCipherText) IsNil() bool {
    28  	if len(ciphertext.msgEncrypted) == 0 {
    29  		return true
    30  	}
    31  
    32  	return len(ciphertext.symKeyEncrypted) == 0
    33  }
    34  
    35  func (hybridCipherText HybridCipherText) MarshalJSON() ([]byte, error) {
    36  	data := hybridCipherText.Bytes()
    37  	temp := base58.Base58Check{}.Encode(data, common.ZeroByte)
    38  	return json.Marshal(temp)
    39  }
    40  
    41  func (hybridCipherText *HybridCipherText) UnmarshalJSON(data []byte) error {
    42  	dataStr := ""
    43  	_ = json.Unmarshal(data, &dataStr)
    44  	temp, _, err := base58.Base58Check{}.Decode(dataStr)
    45  	if err != nil {
    46  		return err
    47  	}
    48  	hybridCipherText.SetBytes(temp)
    49  	return nil
    50  }
    51  
    52  // Bytes converts ciphertext to bytes array
    53  // if ciphertext is nil, return empty byte array
    54  func (ciphertext HybridCipherText) Bytes() []byte {
    55  	if ciphertext.IsNil() {
    56  		return []byte{}
    57  	}
    58  
    59  	res := make([]byte, 0)
    60  	res = append(res, ciphertext.symKeyEncrypted...)
    61  	res = append(res, ciphertext.msgEncrypted...)
    62  
    63  	return res
    64  }
    65  
    66  // SetBytes reverts bytes array to hybridCipherText_Old
    67  func (ciphertext *HybridCipherText) SetBytes(bytes []byte) error {
    68  	if len(bytes) == 0 {
    69  		return NewPrivacyErr(InvalidInputToSetBytesErr, nil)
    70  	}
    71  
    72  	if len(bytes) < elGamalCiphertextSize {
    73  		// out of range
    74  		return errors.New("out of range Parse ciphertext")
    75  	}
    76  	ciphertext.symKeyEncrypted = bytes[0:elGamalCiphertextSize]
    77  	ciphertext.msgEncrypted = bytes[elGamalCiphertextSize:]
    78  	return nil
    79  }
    80  
    81  // hybridEncrypt_Old encrypts message with any size, using Publickey to encrypt
    82  // hybridEncrypt_Old generates AES key by randomize an elliptic point aesKeyPoint and get X-coordinate
    83  // using AES key to encrypt message
    84  // After that, using ElGamal encryption encrypt aesKeyPoint using publicKey
    85  func HybridEncrypt(msg []byte, publicKey *Point) (ciphertext *HybridCipherText, err error) {
    86  	ciphertext = new(HybridCipherText)
    87  
    88  	// Generate a AES key bytes
    89  	sKeyPoint := RandomPoint()
    90  	sKeyByte := sKeyPoint.ToBytes()
    91  	// Encrypt msg using aesKeyByte
    92  
    93  	aesKey := sKeyByte[:]
    94  	aesScheme := &common.AES{
    95  		Key: aesKey,
    96  	}
    97  	ciphertext.msgEncrypted, err = aesScheme.Encrypt(msg)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	// Using ElGamal cryptosystem for encrypting AES sym key
   103  	pubKey := new(elGamalPublicKey)
   104  	pubKey.h = publicKey
   105  	ciphertext.symKeyEncrypted = pubKey.encrypt(sKeyPoint).Bytes()
   106  
   107  	return ciphertext, nil
   108  }
   109  
   110  // hybridDecrypt_Old receives a ciphertext and privateKey
   111  // it decrypts aesKeyPoint, using ElGamal encryption with privateKey
   112  // Using X-coordinate of aesKeyPoint to decrypts message
   113  func HybridDecrypt(ciphertext *HybridCipherText, privateKey *Scalar) (msg []byte, err error) {
   114  	// Validate ciphertext
   115  	if ciphertext.IsNil() {
   116  		return []byte{}, errors.New("ciphertext must not be nil")
   117  	}
   118  
   119  	// Get receiving key, which is a private key of ElGamal cryptosystem
   120  	privKey := new(elGamalPrivateKey)
   121  	privKey.set(privateKey)
   122  
   123  	// Parse encrypted AES key encoded as an elliptic point from EncryptedSymKey
   124  	encryptedAESKey := new(elGamalCipherText)
   125  	err = encryptedAESKey.SetBytes(ciphertext.symKeyEncrypted)
   126  	if err != nil {
   127  		return []byte{}, err
   128  	}
   129  
   130  	// Decrypt encryptedAESKey using recipient's receiving key
   131  	aesKeyPoint, err := privKey.decrypt(encryptedAESKey)
   132  	if err != nil {
   133  		return []byte{}, err
   134  	}
   135  
   136  	// Get AES key
   137  	aesKeyByte := aesKeyPoint.ToBytes()
   138  	aesKey := aesKeyByte[:]
   139  	aesScheme := &common.AES{
   140  		Key: aesKey,
   141  	}
   142  
   143  	// Decrypt encrypted coin randomness using AES keysatt
   144  	msg, err = aesScheme.Decrypt(ciphertext.msgEncrypted)
   145  	if err != nil {
   146  		return []byte{}, err
   147  	}
   148  	return msg, nil
   149  }