Skip to content

Commit 2bb181e

Browse files
committed
feat: extend ChaCha20 and XChaCha20 to encrypt any file
1 parent 46606a7 commit 2bb181e

File tree

5 files changed

+174
-40
lines changed

5 files changed

+174
-40
lines changed

_example/xchacha20poly1305/dummy.pdf

25.5 KB
Binary file not shown.

_example/xchacha20poly1305/main.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package main
44
import (
55
"crypto/rand"
66
"fmt"
7+
"os"
78

89
"golang.org/x/crypto/argon2"
910

@@ -61,4 +62,68 @@ func main() {
6162
return
6263
}
6364
fmt.Println("plaintext:", plaintext)
65+
66+
// ============================================================================
67+
// encrypt a file (dummy.pdf) using XChaCha20-Poly1305
68+
// the encrypted file will be saved as dummy.pdf.enc
69+
// ============================================================================
70+
filename := "dummy.pdf"
71+
encryptedFilename := filename + ".enc"
72+
decryptedFilename := filename
73+
74+
// read the file
75+
pdfBytes, err := os.ReadFile(filename)
76+
if err != nil {
77+
fmt.Println(err)
78+
return
79+
}
80+
81+
// encrypt the data
82+
ciphertext, err = crypt.EncryptByteXChacha20poly1305WithNonceAppended(key, pdfBytes)
83+
if err != nil {
84+
fmt.Println(err)
85+
return
86+
}
87+
88+
// save the encrypted data to a file
89+
err = os.WriteFile(encryptedFilename, ciphertext, 0644)
90+
if err != nil {
91+
fmt.Println(err)
92+
return
93+
}
94+
fmt.Println("encrypted file:", encryptedFilename)
95+
96+
// delete the original file
97+
err = os.Remove(filename)
98+
if err != nil {
99+
fmt.Println(err)
100+
return
101+
}
102+
fmt.Println("original file deleted:", filename)
103+
104+
// ============================================================================
105+
// decrypt the encrypted file (dummy.pdf.enc) using XChaCha20-Poly1305
106+
// the decrypted file will be saved as dummy.pdf
107+
// ============================================================================
108+
// read the encrypted file
109+
encryptedPdfBytes, err := os.ReadFile(encryptedFilename)
110+
if err != nil {
111+
fmt.Println(err)
112+
return
113+
}
114+
115+
// decrypt the data
116+
decryptedPdfBytes, err := crypt.DecryptByteXChacha20poly1305WithNonceAppended(key, encryptedPdfBytes)
117+
if err != nil {
118+
fmt.Println(err)
119+
return
120+
}
121+
122+
// save the decrypted data to a file
123+
err = os.WriteFile(decryptedFilename, decryptedPdfBytes, 0644)
124+
if err != nil {
125+
fmt.Println(err)
126+
return
127+
}
128+
fmt.Println("decrypted file:", decryptedFilename)
64129
}

chaCha20.go

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"golang.org/x/crypto/chacha20poly1305"
99
)
1010

11-
// EncryptChacha20poly1305 encrypts and authenticates the given message with
11+
// EncryptByteChacha20poly1305 encrypts and authenticates the given message (bytes) with
1212
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
13-
func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) {
13+
func EncryptByteChacha20poly1305(key []byte, input []byte) (ciphertext []byte, nonce []byte, err error) {
1414
// create a new ChaCha20-Poly1305 AEAD using the given 256-bit key
1515
aead, err := chacha20poly1305.New(key)
1616
if err != nil {
@@ -26,18 +26,20 @@ func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce
2626
return
2727
}
2828

29-
// data to be encrypted
30-
data := []byte(text)
31-
3229
// encrypt the data
33-
ciphertext = aead.Seal(nil, nonce, data, nil)
34-
30+
ciphertext = aead.Seal(nil, nonce, input, nil)
3531
return
3632
}
3733

38-
// DecryptChacha20poly1305 decrypts and authenticates the given message with
34+
// EncryptChacha20poly1305 encrypts and authenticates the given message (string) with
3935
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
40-
func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) {
36+
func EncryptChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) {
37+
return EncryptByteChacha20poly1305(key, []byte(text))
38+
}
39+
40+
// DecryptByteChacha20poly1305 decrypts and authenticates the given ciphertext with
41+
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
42+
func DecryptByteChacha20poly1305(key, nonce, ciphertext []byte) (plaintext []byte, err error) {
4143
// create a new ChaCha20-Poly1305 AEAD using the given 256-bit key
4244
aead, err := chacha20poly1305.New(key)
4345
if err != nil {
@@ -46,45 +48,78 @@ func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err er
4648
}
4749

4850
// decrypt the data
49-
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
51+
plaintext, err = aead.Open(nil, nonce, ciphertext, nil)
5052
if err != nil {
5153
err = fmt.Errorf("error decrypting data: %v", err)
5254
return
5355
}
54-
text = string(plaintext)
5556

5657
return
5758
}
5859

59-
// EncryptChacha20poly1305WithNonceAppended encrypts and authenticates the given message with
60+
// DecryptChacha20poly1305 decrypts and authenticates the given ciphertext with
61+
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
62+
func DecryptChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) {
63+
// decrypt the data
64+
plaintext, err := DecryptByteChacha20poly1305(key, nonce, ciphertext)
65+
if err != nil {
66+
return
67+
}
68+
69+
text = string(plaintext)
70+
return
71+
}
72+
73+
// EncryptByteChacha20poly1305WithNonceAppended encrypts and authenticates the given message (bytes) with
6074
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
6175
// It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext].
62-
func EncryptChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) {
63-
ciphertext, nonce, err := EncryptChacha20poly1305(key, text)
76+
func EncryptByteChacha20poly1305WithNonceAppended(key []byte, input []byte) (ciphertext []byte, err error) {
77+
ciphertext, nonce, err := EncryptByteChacha20poly1305(key, input)
6478
if err != nil {
6579
return
6680
}
81+
6782
ciphertext = append(nonce, ciphertext...)
6883
return
6984
}
7085

71-
// DecryptChacha20poly1305WithNonceAppended decrypts and authenticates the given message with
86+
// EncryptChacha20poly1305WithNonceAppended encrypts and authenticates the given message (string) with
87+
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
88+
// It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext].
89+
func EncryptChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) {
90+
return EncryptByteChacha20poly1305WithNonceAppended(key, []byte(text))
91+
}
92+
93+
// DecryptByteChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with
7294
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
7395
// It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext].
74-
func DecryptChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) {
96+
func DecryptByteChacha20poly1305WithNonceAppended(key, ciphertext []byte) (plaintext []byte, err error) {
7597
nonceSize := chacha20poly1305.NonceSize
7698
if len(ciphertext) < nonceSize {
7799
err = errors.New("ciphertext is too short")
78100
return
79101
}
102+
80103
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
81-
text, err = DecryptChacha20poly1305(key, nonce, ciphertext)
104+
return DecryptByteChacha20poly1305(key, nonce, ciphertext)
105+
}
106+
107+
// DecryptChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with
108+
// ChaCha20-Poly1305 AEAD using the given 256-bit key and 96-bit nonce.
109+
// It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext].
110+
func DecryptChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) {
111+
plaintext, err := DecryptByteChacha20poly1305WithNonceAppended(key, ciphertext)
112+
if err != nil {
113+
return
114+
}
115+
116+
text = string(plaintext)
82117
return
83118
}
84119

85-
// EncryptXChacha20poly1305 encrypts and authenticates the given message with
120+
// EncryptByteXChacha20poly1305 encrypts and authenticates the given message (bytes) with
86121
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
87-
func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) {
122+
func EncryptByteXChacha20poly1305(key []byte, input []byte) (ciphertext []byte, nonce []byte, err error) {
88123
// create a new XChaCha20-Poly1305 AEAD using the given 256-bit key
89124
aead, err := chacha20poly1305.NewX(key)
90125
if err != nil {
@@ -100,18 +135,20 @@ func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce
100135
return
101136
}
102137

103-
// data to be encrypted
104-
data := []byte(text)
105-
106138
// encrypt the data
107-
ciphertext = aead.Seal(nil, nonce, data, nil)
108-
139+
ciphertext = aead.Seal(nil, nonce, input, nil)
109140
return
110141
}
111142

112-
// DecryptXChacha20poly1305 decrypts and authenticates the given message with
143+
// EncryptXChacha20poly1305 encrypts and authenticates the given message (string) with
113144
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
114-
func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) {
145+
func EncryptXChacha20poly1305(key []byte, text string) (ciphertext []byte, nonce []byte, err error) {
146+
return EncryptByteXChacha20poly1305(key, []byte(text))
147+
}
148+
149+
// DecryptByteXChacha20poly1305 decrypts and authenticates the given ciphertext with
150+
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
151+
func DecryptByteXChacha20poly1305(key, nonce, ciphertext []byte) (plaintext []byte, err error) {
115152
// create a new XChaCha20-Poly1305 AEAD using the given 256-bit key
116153
aead, err := chacha20poly1305.NewX(key)
117154
if err != nil {
@@ -120,38 +157,70 @@ func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err e
120157
}
121158

122159
// decrypt the data
123-
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
160+
plaintext, err = aead.Open(nil, nonce, ciphertext, nil)
124161
if err != nil {
125162
err = fmt.Errorf("error decrypting data: %v", err)
126163
return
127164
}
128-
text = string(plaintext)
129165

130166
return
131167
}
132168

133-
// EncryptXChacha20poly1305WithNonceAppended encrypts and authenticates the given message with
169+
// DecryptXChacha20poly1305 decrypts and authenticates the given ciphertext with
170+
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
171+
func DecryptXChacha20poly1305(key, nonce, ciphertext []byte) (text string, err error) {
172+
// decrypt the data
173+
plaintext, err := DecryptByteXChacha20poly1305(key, nonce, ciphertext)
174+
if err != nil {
175+
return
176+
}
177+
178+
text = string(plaintext)
179+
return
180+
}
181+
182+
// EncryptByteXChacha20poly1305WithNonceAppended encrypts and authenticates the given message (bytes) with
134183
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
135184
// It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext].
136-
func EncryptXChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) {
137-
ciphertext, nonce, err := EncryptXChacha20poly1305(key, text)
185+
func EncryptByteXChacha20poly1305WithNonceAppended(key []byte, input []byte) (ciphertext []byte, err error) {
186+
ciphertext, nonce, err := EncryptByteXChacha20poly1305(key, input)
138187
if err != nil {
139188
return
140189
}
141190
ciphertext = append(nonce, ciphertext...)
142191
return
143192
}
144193

145-
// DecryptXChacha20poly1305WithNonceAppended decrypts and authenticates the given message with
194+
// EncryptXChacha20poly1305WithNonceAppended encrypts and authenticates the given message (string) with
195+
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
196+
// It appends the ciphertext to the nonce [ciphertext = nonce + ciphertext].
197+
func EncryptXChacha20poly1305WithNonceAppended(key []byte, text string) (ciphertext []byte, err error) {
198+
return EncryptByteXChacha20poly1305WithNonceAppended(key, []byte(text))
199+
}
200+
201+
// DecryptByteXChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with
146202
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
147203
// It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext].
148-
func DecryptXChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) {
204+
func DecryptByteXChacha20poly1305WithNonceAppended(key, ciphertext []byte) (plaintext []byte, err error) {
149205
nonceSize := chacha20poly1305.NonceSizeX
150206
if len(ciphertext) < nonceSize {
151207
err = errors.New("ciphertext is too short")
152208
return
153209
}
210+
154211
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
155-
text, err = DecryptXChacha20poly1305(key, nonce, ciphertext)
212+
return DecryptByteXChacha20poly1305(key, nonce, ciphertext)
213+
}
214+
215+
// DecryptXChacha20poly1305WithNonceAppended decrypts and authenticates the given ciphertext with
216+
// XChaCha20-Poly1305 AEAD using the given 256-bit key and 192-bit nonce.
217+
// It expects the ciphertext along with the nonce [ciphertext = nonce + ciphertext].
218+
func DecryptXChacha20poly1305WithNonceAppended(key, ciphertext []byte) (text string, err error) {
219+
plaintext, err := DecryptByteXChacha20poly1305WithNonceAppended(key, ciphertext)
220+
if err != nil {
221+
return
222+
}
223+
224+
text = string(plaintext)
156225
return
157226
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ module github.com/pilinux/crypt
22

33
go 1.20
44

5-
require golang.org/x/crypto v0.27.0
5+
require golang.org/x/crypto v0.28.0
66

7-
require golang.org/x/sys v0.25.0 // indirect
7+
require golang.org/x/sys v0.26.0 // indirect

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
2-
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
3-
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
4-
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1+
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
2+
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
3+
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
4+
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

0 commit comments

Comments
 (0)