Go Lang NACL Cryptography

by Anish

Posted on Monday December 17 , 2018

go lang nacl

This sample chapter extracted from the book, Go Lang Cryptography for Developers . The Book theme isCryptography is for EveryOne. Learn from Crypto Principle to Applied Cryptography With Practical Example


NaCl (pronounced "salt") is a new easy-to-use high-speed software library for network communication, encryption, decryption, signatures, etc. NaCl's goal is to provide all of the core operations needed to build higher-level cryptographic tools.

Nacl Box

The Nacl Box uses the given public and private (secret) keys to derive a shared key, which is used with the nonce given to encrypt the given messages and to decrypt the given ciphertexts.

The same shared key will be generated from both pairing of keys, so given two keypairs belonging to Alice (pkalice, skalice) and Bob (pkbob, skbob), the key derived from (pkalice, skbob) will equal that from (pkbob, skalice).

golang.org/x/crypto/nacl/box authenticates and encrypts small messages using public-key cryptography.

Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate messages. The length of messages is not hidden.

func Seal appends an encrypted and authenticated copy of message to out, which will be Overhead bytes longer than the original and must not overlap it. The nonce must be unique for each distinct message for a given pair of keys.

func Seal(out, message []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) []byte

func Open Open authenticates and decrypts a box produced by Seal and appends the message to out, which must not overlap box. The output will be Overhead bytes smaller than box

func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) ([]byte, bool)

func GenerateKey GenerateKey generates a new public/private key pair suitable for use with Seal and Open

func GenerateKey(rand io.Reader) (publicKey, privateKey *[32]byte, err error)

The following example will show how to use NACL box, to secretly send encrypted and authenticated copy of message from Alice to Bob

  • Public Cryptography requires Key Pair, So first generate. In real world the receiver private key is not known to the sender, only the public key is known.
  • Nonce is appended to encrypted message and then send to the receiver.
  • Use the same nonce you used to encrypt the message, this is usually done by storing nonce alongside the encrypted message
package main  
  
import (  
   crypto_rand "crypto/rand"  
  "fmt"  
  "golang.org/x/crypto/nacl/box" 
  "io"
  )  
func main() {  
   plaintext := "Hello 8gwifi.org using go lang Box Example"  
   pkalice, skalice, err := box.GenerateKey(crypto_rand.Reader)  
   if err != nil {  
      panic(err)  
   }  
   
   pkbob, skbob, err := box.GenerateKey(crypto_rand.Reader)  
   if err != nil {  
      panic(err)  
   }  
   fmt.Printf("Original Text:  %s\n", plaintext)  
   fmt.Println("====NACL Box Seal/ Open====")  
  
   // You must use a different nonce for each message you encrypt with the  
   // same key. Since the nonce here is 192 bits long, a random value 
   // provides a sufficiently small probability of repeats.  var nonce [24]byte  
   if _, err := io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {  
      panic(err)  
   }  
  
   // This encrypts msg and appends the result to the nonce.  
   encrypted := box.Seal(nonce[:], []byte(plaintext), &nonce, pkbob, skalice)  
   fmt.Printf("Alice Send Encrypted Message to Bob  %x\n", encrypted)  
  
   // The recipient can decrypt the message using their private key and the  
   // sender's public key. When you decrypt, you must use the same nonce you 
   // used to encrypt   the message. One way to achieve this is to store the 
   // nonce alongside the encrypted message. Above, we stored the nonce in the 
   // first 24 bytes of the encrypted text. 
   var decryptNonce [24]byte  
   copy(decryptNonce[:], encrypted[:24])  
   decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, pkalice, skbob)  
   if !ok {  
      panic("decryption error")  
   }  
  
   fmt.Println("Bob Read Message[", string(decrypted), "]")  
  
}

The output

$ go run naclbox.go
Original Text:  Hello 8gwifi.org using go lang Box Example
====NACL Box Seal/ Open====
Alice Send Encrypted Message to Bob  420d83bc6d773bd0597002edc430ae44452d60ba7fa3402b3cdd827343b10a9c0c0a783a1aeb81829a52c3ed15b58568620fc4c807abbfbb48cafe9370567b6201bc33f5289a8d2cf227cd57d512177e22fa
Bob Read Message[ Hello 8gwifi.org using go lang Box Example ]

Nacl Box Faster Computing with Shared Key

The shared key can be used to speed up processing when using the same, pair of keys repeatedly. To achieve this use the go lang functions

func SealAfterPrecomputation performs the same actions as Seal, but takes a shared key as generated by Precompute.

func SealAfterPrecomputation(out, message []byte, nonce *[24]byte, sharedKey *[32]byte) []byte

func OpenAfterPrecomputation n performs the same actions as Open, but takes a shared key as generated by Precompute.

func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool)

NACL Box Precompute Example

package main  
  
import (  
   crypto_rand "crypto/rand" // Custom so it's clear which rand we're using.  
  "fmt"  
  "golang.org/x/crypto/nacl/box" 
  "io"
  )  
  
func main() {  
   plaintext := "Hello 8gwifi.org using go lang Box Example"  
   pkalice, skalice, err := box.GenerateKey(crypto_rand.Reader)  
   if err != nil {  
      panic(err)  
   }  
   pkbob, skbob, err := box.GenerateKey(crypto_rand.Reader)  
   if err != nil {  
      panic(err)  
   }  
   fmt.Printf("Original Text:  %s\n", plaintext)  
   fmt.Println("====NACL Box SealAfterPrecomputation/ OpenAfterPrecomputation====")  
  
   // You must use a different nonce for each message you encrypt with the  
   // same key. Since the nonce here is 192 bits long, a random value 
   // provides a sufficiently small probability of repeats.  
   var nonce [24]byte  
   if _, err := io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {  
      panic(err)  
   }  
   // The shared key can be used to speed up processing when using the same  
   // pair of keys repeatedly.  sharedEncryptKey := new([32]byte)  
   box.Precompute(sharedEncryptKey, pkbob, skalice)  
   fmt.Printf("Shared Key [%x\n", *sharedEncryptKey, "]")  
  
   // This encrypts msg and appends the result to the nonce.  
   encrypted := box.SealAfterPrecomputation(nonce[:], []byte(plaintext), &nonce, sharedEncryptKey)  
  
   fmt.Printf("Alice Send Encrypted Message to Bob  %x\n", &encrypted)  
   // The shared key can be used to speed up processing when using the same  
   // pair of keys repeatedly.  var sharedDecryptKey [32]byte  
   box.Precompute(&sharedDecryptKey, pkalice, skbob)  
   // The recipient can decrypt the message using their private key and the  
   // sender's public key. When you decrypt, you must use the same nonce you 
   // used to encrypt the message. One way to achieve this is to store the 
   // nonce alongside the encrypted message. Above, we stored the nonce in the 
   // first 24 bytes of the encrypted text.  var decryptNonce [24]byte  
   copy(decryptNonce[:], encrypted[:24])  
   decrypted, ok := box.OpenAfterPrecomputation(nil, encrypted[24:], &decryptNonce, &sharedDecryptKey)  
   if !ok {  
      panic("decryption error")  
   }  
   fmt.Println("Bob Read Message[", string(decrypted), "]")  
}

The output

$ go run naclbox1.go
Original Text:  Hello 8gwifi.org using go lang Box Example
====NACL Box SealAfterPrecomputation/ OpenAfterPrecomputation====
Shared Key [20e4228e59d552f15ab04a67269b792957d7a71400b353940bcd13b225795ec3
Alice Send Encrypted Message to Bob  &3e6b0011dfcfcd9163f7d3cb68eeadf683f941f7dfca1b3c7637bf9e0fe75563b3db93ef7f357f475b7c4d1c9789c8e396951488b0cc1892668dcf9b3ed10d37feebd059622175071de065394c31478bdb0d
Bob Read Message[ Hello 8gwifi.org using go lang Box Example ]

Nacl SecretBox

Secret key encryption (also called symmetric key encryption) is analogous to a safe. You can store something secret through it and anyone who has the key can open it and view the contents. SecretBox functions as just such a safe, and like any good safe any attempts to tamper with the contents are easily detected.

Go lang Package secretbox uses XSalsa20 and Poly1305 to encrypt and authenticate messages with secret-key cryptography. The length of messages is not hidden.

func Seal appends an encrypted and authenticated copy of message to out, which must not overlap message. The key and nonce pair must be unique for each distinct message and the output will be Overhead bytes longer than message

func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte

func open authenticates and decrypts a box produced by Seal and appends the message to out, which must not overlap box. The output will be Overhead bytes smaller than box.

func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool)

Note: secretbox encrypts and authenticates small messages.

The following example will show how to use NACL secretbox, to perform Secret key encryption.

  • nonce must be 24 bytes
  • secret key must be of 32 bytes
import (  
 "crypto/rand"  
 "fmt" 
 "golang.org/x/crypto/nacl/secretbox" 
 "io"
 )   
func main() {  
   plaintext := "Hello 8gwifi.org using go lang secretbox esample"  
  // Do not Use this Key, This is for Demo Purpose only  
  key := "myverystrongpasswordo32bitlength"  
  var secretKey [32]byte  
  copy(secretKey[:], key)  

  fmt.Printf("Original Text:  %s\n", plaintext)  
  fmt.Println("====NACL secretbox Seal/ Open====")
  
   // You must use a different nonce for each message you encrypt with the  
   // same key. Since the nonce here is 192 bits long, a random value 
   // provides a sufficiently small probability of repeats.  
   var nonce [24]byte  
   if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {  
      panic(err)  
   }  
   encrypted := secretbox.Seal(nonce[:], []byte(plaintext), &nonce, &secretKey)  
   fmt.Printf("Encrypted Message:  %x\n", encrypted)  
  
   // When you decrypt, you must use the same nonce and key you used to  
   // encrypt the message. One way to achieve this is to store the nonce 
   // alongside the encrypted message. Above, we stored the nonce in the first 
   // 24 bytes of the encrypted text.  var decryptNonce [24]byte  
   copy(decryptNonce[:], encrypted[:24])  
   decrypted, ok := secretbox.Open(nil, encrypted[24:], &decryptNonce, &secretKey)  
   if !ok {  
      panic("decryption error")  
   }  
   fmt.Println(string(decrypted))  
}

The output

$ go run naclsecretbox.go
Original Text:  Hello 8gwifi.org using go lang secretbox esample
====NACL secretbox Seal/ Open====
Encrypted Message:  fc62734e5c73ceec5e3dfe75a439bc85d13138e97423e79a7fbb17ceef34cc0f47fe26d330cf83fe3210d2a93815e3706be29dce5a282c764001dd6d471781efdf5568a2cc3220cba7f29a7fa041565010c04a0ed1b76b78
Hello 8gwifi.org using go lang secretbox esample

NaCl Message Authentication

Nacl Message is done with go lang function auth

func sum generates an authenticator for m using a secret key and returns the 32-byte digest.

func Sum(m []byte, key *[KeySize]byte) *[Size]byte

func verify checks that digest is a valid authenticator of message m under the given secret key. Verify does not leak timing information.

func Verify(digest []byte, m []byte, key *[KeySize]byte) bool

The following example will show how to use NACL auth, to perform message authentication of a given message

  • secret key must be of 32 bytes.
package main  
  
import (  
   "fmt"  
   "golang.org/x/crypto/nacl/auth"
   )  
func main() {  
  
    plaintext := "Hello 8gwifi.org using go lang auth esample"  
   // Do not Use this Key, This is for Demo Purpose only  
   key := "myverystrongpasswordo32bitlengt"  
   var secretKey [32]byte  
   copy(secretKey[:], key)  
  
   fmt.Printf("Original Text:  %s\n", plaintext)  
   fmt.Println("====NACL Message Authentication====")  
  
   mac := auth.Sum([]byte(plaintext), &secretKey)  
   fmt.Printf("MAC %x\n", *mac)  
   result := auth.Verify(mac[:], []byte(plaintext), &secretKey)  
   fmt.Println("Verified : ", result)  
  
   badResult := auth.Verify(mac[:], []byte("different message"), &secretKey)  
   fmt.Println("Verified : ", badResult)  
}

The output

$ go run naclauth.go
Original Text:  Hello 8gwifi.org using go lang auth esample
====NACL Message Authentication====
MAC 2a6bb7feb6b2c175219abcc16fb7c472e48752212cebc4aada48a49d767cdbb5
Verified :  true
Verified :  false

Nacl Digital Signature

Digital signatures allow you to publish a public key, and then you can use your private signing key to sign messages. Others who have your public key can then use it to validate that your messages are actually authentic.

Nacl Digital Signature is done with go lang function sign

func GenerateKey generates a new public/private key pair suitable for use with Sign and Open.

func GenerateKey(rand io.Reader) (publicKey *[32]byte, privateKey *[64]byte, err error)

func Open verifies a signed message produced by Sign and appends the message to out, which must not overlap the signed message.

func Open(out, signedMessage []byte, publicKey *[32]byte) ([]byte, bool)

func sign appends a signed copy of message to out

func Sign(out, message []byte, privateKey *[64]byte) []byte

The following example will show how to use NACL digital signature.

  • Private key for producing digital signatures using the Ed25519 algorithm.
  • Message is Signed with private key
  • Signature is verified using public key.
package main  
import (  
   "crypto/rand"  
   "fmt" 
   "golang.org/x/crypto/nacl/sign"  
)  
func main() {  
   plaintext := "Hello 8gwifi.org using go lang nacl signing esample"  
   fmt.Printf("Original Text:  %s\n", plaintext)  
   fmt.Println("====NACL Digital Signature====")  
     
   publicKey, privateKey, _ := sign.GenerateKey(rand.Reader)  
   // Signing of Message is Perfomed with Private Key  
   signedMessage := sign.Sign(nil, []byte(plaintext), privateKey)  
   fmt.Printf("Message Signature %x\n ", signedMessage)  
   // Verification of the Message is performed with Public Key  
  _ , ok := sign.Open(nil, signedMessage, publicKey)  
   
   f !ok {  
      fmt.Printf("failed to verify signed message")  
      return  
  }  
   fmt.Printf("Verification  Passed ")  
  
}

The output

$ go run naclsign.go
Original Text:  Hello 8gwifi.org using go lang nacl signing esample
====NACL Digital Signature====
Message Signature 1020e3901fc37f3c792a3d435ce7abca877c5171971227b6430f778ef8c245764149185abcef409de7e8e221afa723356363c017a1a46273c969b4809d52920e48656c6c6f203867776966692e6f7267207573696e6720676f206c616e67206e61636c207369676e696e67206573616d706c65
 Verifification Passed

{pagebreak}


Thanku for reading !!! Give a Share for Support

Asking for donation sound bad to me, so i'm raising fund from The Modern Cryptography CookBook for Just $9. Leanpub books Discount coupon first 100 reader. No hurry read the sample chapters here then decide.

Alternatively you can buy My all four Cryptography book Just $10.99


Referefce
  • The Modern Cryptography Book.
  • Python Cryptography
  • Cryptography for JavaScript Developer
  • Go lang Cryptography for developers


python Cryptography Topics
Topics
For Coffee/ Beer/ Amazon Bill and further development of the project Support by Purchasing, The Modern Cryptography CookBook for Just $9 Coupon Price

Cryptography for Python Developers

Cryptography for JavaScript Developers

Go lang ryptography for Developers