...

Source file src/github.com/decred/dcrd/dcrec/secp256k1/v4/example_test.go

Documentation: github.com/decred/dcrd/dcrec/secp256k1/v4

     1  // Copyright (c) 2014 The btcsuite developers
     2  // Copyright (c) 2015-2020 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package secp256k1_test
     7  
     8  import (
     9  	"crypto/aes"
    10  	"crypto/cipher"
    11  	"crypto/sha256"
    12  	"encoding/binary"
    13  	"encoding/hex"
    14  	"fmt"
    15  
    16  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    17  )
    18  
    19  // This example demonstrates use of GenerateSharedSecret to encrypt a message
    20  // for a recipient's public key, and subsequently decrypt the message using the
    21  // recipient's private key.
    22  func Example_encryptDecryptMessage() {
    23  	newAEAD := func(key []byte) (cipher.AEAD, error) {
    24  		block, err := aes.NewCipher(key)
    25  		if err != nil {
    26  			return nil, err
    27  		}
    28  		return cipher.NewGCM(block)
    29  	}
    30  
    31  	// Decode the hex-encoded pubkey of the recipient.
    32  	pubKeyBytes, err := hex.DecodeString("04115c42e757b2efb7671c578530ec191a1" +
    33  		"359381e6a71127a9d37c486fd30dae57e76dc58f693bd7e7010358ce6b165e483a29" +
    34  		"21010db67ac11b1b51b651953d2") // uncompressed pubkey
    35  	if err != nil {
    36  		fmt.Println(err)
    37  		return
    38  	}
    39  	pubKey, err := secp256k1.ParsePubKey(pubKeyBytes)
    40  	if err != nil {
    41  		fmt.Println(err)
    42  		return
    43  	}
    44  
    45  	// Derive an ephemeral public/private keypair for performing ECDHE with
    46  	// the recipient.
    47  	ephemeralPrivKey, err := secp256k1.GeneratePrivateKey()
    48  	if err != nil {
    49  		fmt.Println(err)
    50  		return
    51  	}
    52  	ephemeralPubKey := ephemeralPrivKey.PubKey().SerializeCompressed()
    53  
    54  	// Using ECDHE, derive a shared symmetric key for encryption of the plaintext.
    55  	cipherKey := sha256.Sum256(secp256k1.GenerateSharedSecret(ephemeralPrivKey, pubKey))
    56  
    57  	// Seal the message using an AEAD.  Here we use AES-256-GCM.
    58  	// The ephemeral public key must be included in this message, and becomes
    59  	// the authenticated data for the AEAD.
    60  	//
    61  	// Note that unless a unique nonce can be guaranteed, the ephemeral
    62  	// and/or shared keys must not be reused to encrypt different messages.
    63  	// Doing so destroys the security of the scheme.  Random nonces may be
    64  	// used if XChaCha20-Poly1305 is used instead, but the message must then
    65  	// also encode the nonce (which we don't do here).
    66  	//
    67  	// Since a new ephemeral key is generated for every message ensuring there
    68  	// is no key reuse and AES-GCM permits the nonce to be used as a counter,
    69  	// the nonce is intentionally initialized to all zeros so it acts like the
    70  	// first (and only) use of a counter.
    71  	plaintext := []byte("test message")
    72  	aead, err := newAEAD(cipherKey[:])
    73  	if err != nil {
    74  		fmt.Println(err)
    75  		return
    76  	}
    77  	nonce := make([]byte, aead.NonceSize())
    78  	ciphertext := make([]byte, 4+len(ephemeralPubKey))
    79  	binary.LittleEndian.PutUint32(ciphertext, uint32(len(ephemeralPubKey)))
    80  	copy(ciphertext[4:], ephemeralPubKey)
    81  	ciphertext = aead.Seal(ciphertext, nonce, plaintext, ephemeralPubKey)
    82  
    83  	// The remainder of this example is performed by the recipient on the
    84  	// ciphertext shared by the sender.
    85  
    86  	// Decode the hex-encoded private key.
    87  	pkBytes, err := hex.DecodeString("a11b0a4e1a132305652ee7a8eb7848f6ad" +
    88  		"5ea381e3ce20a2c086a2e388230811")
    89  	if err != nil {
    90  		fmt.Println(err)
    91  		return
    92  	}
    93  	privKey := secp256k1.PrivKeyFromBytes(pkBytes)
    94  
    95  	// Read the sender's ephemeral public key from the start of the message.
    96  	// Error handling for inappropriate pubkey lengths is elided here for
    97  	// brevity.
    98  	pubKeyLen := binary.LittleEndian.Uint32(ciphertext[:4])
    99  	senderPubKeyBytes := ciphertext[4 : 4+pubKeyLen]
   100  	senderPubKey, err := secp256k1.ParsePubKey(senderPubKeyBytes)
   101  	if err != nil {
   102  		fmt.Println(err)
   103  		return
   104  	}
   105  
   106  	// Derive the key used to seal the message, this time from the
   107  	// recipient's private key and the sender's public key.
   108  	recoveredCipherKey := sha256.Sum256(secp256k1.GenerateSharedSecret(privKey, senderPubKey))
   109  
   110  	// Open the sealed message.
   111  	aead, err = newAEAD(recoveredCipherKey[:])
   112  	if err != nil {
   113  		fmt.Println(err)
   114  		return
   115  	}
   116  	nonce = make([]byte, aead.NonceSize())
   117  	recoveredPlaintext, err := aead.Open(nil, nonce, ciphertext[4+pubKeyLen:], senderPubKeyBytes)
   118  	if err != nil {
   119  		fmt.Println(err)
   120  		return
   121  	}
   122  
   123  	fmt.Println(string(recoveredPlaintext))
   124  
   125  	// Output:
   126  	// test message
   127  }
   128  

View as plain text