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 }