@@ -62,8 +62,8 @@ func (wo *aeadCrypter) incrementIndex() error {
62
62
type aeadDecrypter struct {
63
63
aeadCrypter // Embedded ciphertext opener
64
64
reader io.Reader // 'reader' is a partialLengthReader
65
+ chunkBytes []byte
65
66
peekedBytes []byte // Used to detect last chunk
66
- eof bool
67
67
}
68
68
69
69
// Read decrypts bytes and reads them into dst. It decrypts when necessary and
@@ -75,22 +75,18 @@ func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) {
75
75
return ar .buffer .Read (dst )
76
76
}
77
77
78
- // Return EOF if we've previously validated the final tag
79
- if ar .eof {
80
- return 0 , io .EOF
81
- }
82
-
83
78
// Read a chunk
84
79
tagLen := ar .aead .Overhead ()
85
- cipherChunkBuf := new (bytes.Buffer )
86
- _ , errRead := io .CopyN (cipherChunkBuf , ar .reader , int64 (ar .chunkSize + tagLen ))
87
- cipherChunk := cipherChunkBuf .Bytes ()
88
- if errRead != nil && errRead != io .EOF {
80
+ copy (ar .chunkBytes , ar .peekedBytes ) // Copy bytes peeked in previous chunk or in initialization
81
+ bytesRead , errRead := io .ReadFull (ar .reader , ar .chunkBytes [tagLen :])
82
+ if errRead != nil && errRead != io .EOF && errRead != io .ErrUnexpectedEOF {
89
83
return 0 , errRead
90
84
}
91
85
92
- if len (cipherChunk ) > 0 {
93
- decrypted , errChunk := ar .openChunk (cipherChunk )
86
+ if bytesRead > 0 {
87
+ ar .peekedBytes = ar .chunkBytes [bytesRead :bytesRead + tagLen ]
88
+
89
+ decrypted , errChunk := ar .openChunk (ar .chunkBytes [:bytesRead ])
94
90
if errChunk != nil {
95
91
return 0 , errChunk
96
92
}
@@ -102,28 +98,19 @@ func (ar *aeadDecrypter) Read(dst []byte) (n int, err error) {
102
98
} else {
103
99
n = copy (dst , decrypted )
104
100
}
101
+ return
105
102
}
106
103
107
- // Check final authentication tag
108
- if errRead == io .EOF {
109
- errChunk := ar .validateFinalTag (ar .peekedBytes )
110
- if errChunk != nil {
111
- return n , errChunk
112
- }
113
- ar .eof = true // Mark EOF for when we've returned all buffered data
114
- }
115
- return
104
+ return 0 , io .EOF
116
105
}
117
106
118
- // Close is noOp. The final authentication tag of the stream was already
119
- // checked in the last Read call. In the future, this function could be used to
120
- // wipe the reader and peeked, decrypted bytes, if necessary.
107
+ // Close checks the final authentication tag of the stream.
108
+ // In the future, this function could also be used to wipe the reader
109
+ // and peeked & decrypted bytes, if necessary.
121
110
func (ar * aeadDecrypter ) Close () (err error ) {
122
- if ! ar .eof {
123
- errChunk := ar .validateFinalTag (ar .peekedBytes )
124
- if errChunk != nil {
125
- return errChunk
126
- }
111
+ errChunk := ar .validateFinalTag (ar .peekedBytes )
112
+ if errChunk != nil {
113
+ return errChunk
127
114
}
128
115
return nil
129
116
}
@@ -132,20 +119,13 @@ func (ar *aeadDecrypter) Close() (err error) {
132
119
// the underlying plaintext and an error. It accesses peeked bytes from next
133
120
// chunk, to identify the last chunk and decrypt/validate accordingly.
134
121
func (ar * aeadDecrypter ) openChunk (data []byte ) ([]byte , error ) {
135
- tagLen := ar .aead .Overhead ()
136
- // Restore carried bytes from last call
137
- chunkExtra := append (ar .peekedBytes , data ... )
138
- // 'chunk' contains encrypted bytes, followed by an authentication tag.
139
- chunk := chunkExtra [:len (chunkExtra )- tagLen ]
140
- ar .peekedBytes = chunkExtra [len (chunkExtra )- tagLen :]
141
-
142
122
adata := ar .associatedData
143
123
if ar .aeadCrypter .packetTag == packetTypeAEADEncrypted {
144
124
adata = append (ar .associatedData , ar .chunkIndex ... )
145
125
}
146
126
147
127
nonce := ar .computeNextNonce ()
148
- plainChunk , err := ar .aead .Open (nil , nonce , chunk , adata )
128
+ plainChunk , err := ar .aead .Open (nil , nonce , data , adata )
149
129
if err != nil {
150
130
return nil , errors .ErrAEADTagVerification
151
131
}
0 commit comments