diff --git a/_example/xchacha20poly1305/dummy.pdf b/_example/xchacha20poly1305/dummy.pdf new file mode 100644 index 0000000..a38ee8d Binary files /dev/null and b/_example/xchacha20poly1305/dummy.pdf differ diff --git a/_example/xchacha20poly1305/main.go b/_example/xchacha20poly1305/main.go index 315ede2..f861634 100644 --- a/_example/xchacha20poly1305/main.go +++ b/_example/xchacha20poly1305/main.go @@ -4,6 +4,7 @@ package main import ( "crypto/rand" "fmt" + "os" "golang.org/x/crypto/argon2" @@ -61,4 +62,68 @@ func main() { return } fmt.Println("plaintext:", plaintext) + + // ============================================================================ + // encrypt a file (dummy.pdf) using XChaCha20-Poly1305 + // the encrypted file will be saved as dummy.pdf.enc + // ============================================================================ + filename := "dummy.pdf" + encryptedFilename := filename + ".enc" + decryptedFilename := filename + + // read the file + pdfBytes, err := os.ReadFile(filename) + if err != nil { + fmt.Println(err) + return + } + + // encrypt the data + ciphertext, err = crypt.EncryptByteXChacha20poly1305WithNonceAppended(key, pdfBytes) + if err != nil { + fmt.Println(err) + return + } + + // save the encrypted data to a file + err = os.WriteFile(encryptedFilename, ciphertext, 0644) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("encrypted file:", encryptedFilename) + + // delete the original file + err = os.Remove(filename) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("original file deleted:", filename) + + // ============================================================================ + // decrypt the encrypted file (dummy.pdf.enc) using XChaCha20-Poly1305 + // the decrypted file will be saved as dummy.pdf + // ============================================================================ + // read the encrypted file + encryptedPdfBytes, err := os.ReadFile(encryptedFilename) + if err != nil { + fmt.Println(err) + return + } + + // decrypt the data + decryptedPdfBytes, err := crypt.DecryptByteXChacha20poly1305WithNonceAppended(key, encryptedPdfBytes) + if err != nil { + fmt.Println(err) + return + } + + // save the decrypted data to a file + err = os.WriteFile(decryptedFilename, decryptedPdfBytes, 0644) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("decrypted file:", decryptedFilename) } diff --git a/chaCha20.go b/chaCha20.go index 02d4206..1d3fec7 100644 --- a/chaCha20.go +++ b/chaCha20.go @@ -8,9 +8,9 @@ import ( "golang.org/x/crypto/chacha20poly1305" ) -// EncryptChacha20poly1305 encrypts and authenticates the given message with +// EncryptByteChacha20poly1305 encrypts and authenticates the given message (bytes) with // ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. -func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) { +func EncryptByteChacha20poly1305(key []byte, input []byte) (ciphertext []byte, nonce []byte, err error) { // create a new ChaCha20-Poly1305 AEAD using the given 256-bit key aead, err := chacha20poly1305.New(key) if err != nil { @@ -26,18 +26,20 @@ func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce return } - // data to be encrypted - data := []byte(text) - // encrypt the data - ciphertext = aead.Seal(nil, nonce, data, nil) - + ciphertext = aead.Seal(nil, nonce, input, nil) return } -// DecryptChacha20poly1305 decrypts and authenticates the given message with +// EncryptChacha20poly1305 encrypts and authenticates the given message (string) with // ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. -func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) { +func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) { + return EncryptByteChacha20poly1305(key, []byte(text)) +} + +// DecryptByteChacha20poly1305 decrypts and authenticates the given ciphertext with +// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. +func DecryptByteChacha20poly1305(key, nonce, ciphertext []byte) (plaintext []byte, err error) { // create a new ChaCha20-Poly1305 AEAD using the given 256-bit key aead, err := chacha20poly1305.New(key) if err != nil { @@ -46,45 +48,78 @@ func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err er } // decrypt the data - plaintext, err := aead.Open(nil, nonce, ciphertext, nil) + plaintext, err = aead.Open(nil, nonce, ciphertext, nil) if err != nil { err = fmt.Errorf("error decrypting data: %v", err) return } - text = string(plaintext) return } -// EncryptChacha20poly1305WithNonceAppended encrypts and authenticates the given message with +// DecryptChacha20poly1305 decrypts and authenticates the given ciphertext with +// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. +func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) { + // decrypt the data + plaintext, err := DecryptByteChacha20poly1305(key, nonce, ciphertext) + if err != nil { + return + } + + text = string(plaintext) + return +} + +// EncryptByteChacha20poly1305WithNonceAppended encrypts and authenticates the given message (bytes) with // ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. // It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext]. -func EncryptChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) { - ciphertext, nonce, err := EncryptChacha20poly1305(key, text) +func EncryptByteChacha20poly1305WithNonceAppended(key []byte, input []byte) (ciphertext []byte, err error) { + ciphertext, nonce, err := EncryptByteChacha20poly1305(key, input) if err != nil { return } + ciphertext = append(nonce, ciphertext...) return } -// DecryptChacha20poly1305WithNonceAppended decrypts and authenticates the given message with +// EncryptChacha20poly1305WithNonceAppended encrypts and authenticates the given message (string) with +// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. +// It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext]. +func EncryptChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) { + return EncryptByteChacha20poly1305WithNonceAppended(key, []byte(text)) +} + +// DecryptByteChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with // ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. // It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext]. -func DecryptChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) { +func DecryptByteChacha20poly1305WithNonceAppended(key, ciphertext []byte) (plaintext []byte, err error) { nonceSize := chacha20poly1305.NonceSize if len(ciphertext) < nonceSize { err = errors.New("ciphertext is too short") return } + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] - text, err = DecryptChacha20poly1305(key, nonce, ciphertext) + return DecryptByteChacha20poly1305(key, nonce, ciphertext) +} + +// DecryptChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with +// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce. +// It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext]. +func DecryptChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) { + plaintext, err := DecryptByteChacha20poly1305WithNonceAppended(key, ciphertext) + if err != nil { + return + } + + text = string(plaintext) return } -// EncryptXChacha20poly1305 encrypts and authenticates the given message with +// EncryptByteXChacha20poly1305 encrypts and authenticates the given message (bytes) with // XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. -func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) { +func EncryptByteXChacha20poly1305(key []byte, input []byte) (ciphertext []byte, nonce []byte, err error) { // create a new XChaCha20-Poly1305 AEAD using the given 256-bit key aead, err := chacha20poly1305.NewX(key) if err != nil { @@ -100,18 +135,20 @@ func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce return } - // data to be encrypted - data := []byte(text) - // encrypt the data - ciphertext = aead.Seal(nil, nonce, data, nil) - + ciphertext = aead.Seal(nil, nonce, input, nil) return } -// DecryptXChacha20poly1305 decrypts and authenticates the given message with +// EncryptXChacha20poly1305 encrypts and authenticates the given message (string) with // XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. -func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) { +func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) { + return EncryptByteXChacha20poly1305(key, []byte(text)) +} + +// DecryptByteXChacha20poly1305 decrypts and authenticates the given ciphertext with +// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. +func DecryptByteXChacha20poly1305(key, nonce, ciphertext []byte) (plaintext []byte, err error) { // create a new XChaCha20-Poly1305 AEAD using the given 256-bit key aead, err := chacha20poly1305.NewX(key) if err != nil { @@ -120,21 +157,33 @@ func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err e } // decrypt the data - plaintext, err := aead.Open(nil, nonce, ciphertext, nil) + plaintext, err = aead.Open(nil, nonce, ciphertext, nil) if err != nil { err = fmt.Errorf("error decrypting data: %v", err) return } - text = string(plaintext) return } -// EncryptXChacha20poly1305WithNonceAppended encrypts and authenticates the given message with +// DecryptXChacha20poly1305 decrypts and authenticates the given ciphertext with +// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. +func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) { + // decrypt the data + plaintext, err := DecryptByteXChacha20poly1305(key, nonce, ciphertext) + if err != nil { + return + } + + text = string(plaintext) + return +} + +// EncryptByteXChacha20poly1305WithNonceAppended encrypts and authenticates the given message (bytes) with // XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. // It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext]. -func EncryptXChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) { - ciphertext, nonce, err := EncryptXChacha20poly1305(key, text) +func EncryptByteXChacha20poly1305WithNonceAppended(key []byte, input []byte) (ciphertext []byte, err error) { + ciphertext, nonce, err := EncryptByteXChacha20poly1305(key, input) if err != nil { return } @@ -142,16 +191,36 @@ func EncryptXChacha20poly1305WithNonceAppended(key []byte, text string) (ciphert return } -// DecryptXChacha20poly1305WithNonceAppended decrypts and authenticates the given message with +// EncryptXChacha20poly1305WithNonceAppended encrypts and authenticates the given message (string) with +// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. +// It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext]. +func EncryptXChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) { + return EncryptByteXChacha20poly1305WithNonceAppended(key, []byte(text)) +} + +// DecryptByteXChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with // XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. // It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext]. -func DecryptXChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) { +func DecryptByteXChacha20poly1305WithNonceAppended(key, ciphertext []byte) (plaintext []byte, err error) { nonceSize := chacha20poly1305.NonceSizeX if len(ciphertext) < nonceSize { err = errors.New("ciphertext is too short") return } + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] - text, err = DecryptXChacha20poly1305(key, nonce, ciphertext) + return DecryptByteXChacha20poly1305(key, nonce, ciphertext) +} + +// DecryptXChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with +// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce. +// It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext]. +func DecryptXChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) { + plaintext, err := DecryptByteXChacha20poly1305WithNonceAppended(key, ciphertext) + if err != nil { + return + } + + text = string(plaintext) return } diff --git a/go.mod b/go.mod index 6294b28..006ae33 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,6 @@ module github.com/pilinux/crypt go 1.20 -require golang.org/x/crypto v0.27.0 +require golang.org/x/crypto v0.28.0 -require golang.org/x/sys v0.25.0 // indirect +require golang.org/x/sys v0.26.0 // indirect diff --git a/go.sum b/go.sum index 16773a1..25fba75 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=