github.com/cosmos/cosmos-sdk@v0.50.1/crypto/xsalsa20symmetric/symmetric.go (about)

     1  package xsalsa20symmetric
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"golang.org/x/crypto/nacl/secretbox"
     9  )
    10  
    11  // TODO, make this into a struct that implements crypto.Symmetric.
    12  
    13  const (
    14  	nonceLen  = 24
    15  	secretLen = 32
    16  )
    17  
    18  var ErrCiphertextDecrypt = errors.New("ciphertext decryption failed")
    19  
    20  // secret must be 32 bytes long. Use something like Sha256(Bcrypt(passphrase))
    21  // The ciphertext is (secretbox.Overhead + 24) bytes longer than the plaintext.
    22  func EncryptSymmetric(plaintext, secret []byte) (ciphertext []byte) {
    23  	if len(secret) != secretLen {
    24  		panic(fmt.Sprintf("Secret must be 32 bytes long, got len %v", len(secret)))
    25  	}
    26  	nonce := randBytes(nonceLen)
    27  	nonceArr := [nonceLen]byte{}
    28  	copy(nonceArr[:], nonce)
    29  	secretArr := [secretLen]byte{}
    30  	copy(secretArr[:], secret)
    31  	ciphertext = make([]byte, nonceLen+secretbox.Overhead+len(plaintext))
    32  	copy(ciphertext, nonce)
    33  	secretbox.Seal(ciphertext[nonceLen:nonceLen], plaintext, &nonceArr, &secretArr)
    34  	return ciphertext
    35  }
    36  
    37  // secret must be 32 bytes long. Use something like Sha256(Bcrypt(passphrase))
    38  // The ciphertext is (secretbox.Overhead + 24) bytes longer than the plaintext.
    39  func DecryptSymmetric(ciphertext, secret []byte) (plaintext []byte, err error) {
    40  	if len(secret) != secretLen {
    41  		panic(fmt.Sprintf("Secret must be 32 bytes long, got len %v", len(secret)))
    42  	}
    43  	if len(ciphertext) <= secretbox.Overhead+nonceLen {
    44  		return nil, errors.New("ciphertext is too short")
    45  	}
    46  	nonce := ciphertext[:nonceLen]
    47  	nonceArr := [nonceLen]byte{}
    48  	copy(nonceArr[:], nonce)
    49  	secretArr := [secretLen]byte{}
    50  	copy(secretArr[:], secret)
    51  	plaintext = make([]byte, len(ciphertext)-nonceLen-secretbox.Overhead)
    52  	_, ok := secretbox.Open(plaintext[:0], ciphertext[nonceLen:], &nonceArr, &secretArr)
    53  	if !ok {
    54  		return nil, ErrCiphertextDecrypt
    55  	}
    56  	return plaintext, nil
    57  }
    58  
    59  // This only uses the OS's randomness
    60  func randBytes(numBytes int) []byte {
    61  	b := make([]byte, numBytes)
    62  	_, err := rand.Read(b)
    63  	if err != nil {
    64  		panic(err)
    65  	}
    66  	return b
    67  }