1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package encryption
18
19 import (
20 "io"
21
22 "github.com/apache/arrow/go/v15/arrow/memory"
23 "github.com/apache/arrow/go/v15/parquet"
24 )
25
26
27
28 type FileDecryptor interface {
29
30 GetFooterKey() string
31
32 FileAad() string
33
34 Algorithm() parquet.Cipher
35
36 Properties() *parquet.FileDecryptionProperties
37
38
39 WipeOutDecryptionKeys()
40
41
42 GetFooterDecryptor() Decryptor
43
44
45 GetFooterDecryptorForColumnMeta(aad string) Decryptor
46
47
48 GetFooterDecryptorForColumnData(aad string) Decryptor
49
50
51 GetColumnMetaDecryptor(columnPath, columnKeyMetadata, aad string) Decryptor
52
53
54 GetColumnDataDecryptor(columnPath, columnKeyMetadata, aad string) Decryptor
55 }
56
57 type fileDecryptor struct {
58
59
60 props *parquet.FileDecryptionProperties
61
62 fileAad string
63 columnDataMap map[string]Decryptor
64 columnMetaDataMap map[string]Decryptor
65 footerMetadataDecryptor Decryptor
66 footerDataDecryptor Decryptor
67 alg parquet.Cipher
68 footerKeyMetadata string
69 metaDecryptor *aesDecryptor
70 dataDecryptor *aesDecryptor
71 mem memory.Allocator
72 }
73
74
75
76 func NewFileDecryptor(props *parquet.FileDecryptionProperties, fileAad string, alg parquet.Cipher, keymetadata string, mem memory.Allocator) FileDecryptor {
77 if mem == nil {
78 mem = memory.DefaultAllocator
79 }
80 return &fileDecryptor{
81 fileAad: fileAad,
82 props: props,
83 alg: alg,
84 footerKeyMetadata: keymetadata,
85 mem: mem,
86 columnDataMap: make(map[string]Decryptor),
87 columnMetaDataMap: make(map[string]Decryptor),
88 }
89 }
90
91 func (d *fileDecryptor) FileAad() string { return d.fileAad }
92 func (d *fileDecryptor) Properties() *parquet.FileDecryptionProperties { return d.props }
93 func (d *fileDecryptor) Algorithm() parquet.Cipher { return d.alg }
94 func (d *fileDecryptor) GetFooterKey() string {
95 footerKey := d.props.FooterKey()
96 if footerKey == "" {
97 if d.footerKeyMetadata == "" {
98 panic("no footer key or key metadata")
99 }
100 if d.props.KeyRetriever == nil {
101 panic("no footer key or key retriever")
102 }
103 footerKey = d.props.KeyRetriever.GetKey([]byte(d.footerKeyMetadata))
104 }
105 if footerKey == "" {
106 panic("invalid footer encryption key. Could not parse footer metadata")
107 }
108 return footerKey
109 }
110
111 func (d *fileDecryptor) GetFooterDecryptor() Decryptor {
112 aad := CreateFooterAad(d.fileAad)
113 return d.getFooterDecryptor(aad, true)
114 }
115
116 func (d *fileDecryptor) GetFooterDecryptorForColumnMeta(aad string) Decryptor {
117 return d.getFooterDecryptor(aad, true)
118 }
119
120 func (d *fileDecryptor) GetFooterDecryptorForColumnData(aad string) Decryptor {
121 return d.getFooterDecryptor(aad, false)
122 }
123
124 func (d *fileDecryptor) GetColumnMetaDecryptor(columnPath, columnKeyMetadata, aad string) Decryptor {
125 return d.getColumnDecryptor(columnPath, columnKeyMetadata, aad, true)
126 }
127
128 func (d *fileDecryptor) GetColumnDataDecryptor(columnPath, columnKeyMetadata, aad string) Decryptor {
129 return d.getColumnDecryptor(columnPath, columnKeyMetadata, aad, false)
130 }
131
132 func (d *fileDecryptor) WipeOutDecryptionKeys() {
133 d.props.WipeOutDecryptionKeys()
134 }
135
136 func (d *fileDecryptor) getFooterDecryptor(aad string, metadata bool) Decryptor {
137 if metadata {
138 if d.footerMetadataDecryptor != nil {
139 return d.footerMetadataDecryptor
140 }
141 } else {
142 if d.footerDataDecryptor != nil {
143 return d.footerDataDecryptor
144 }
145 }
146
147 footerKey := d.GetFooterKey()
148
149
150
151 aesMetaDecrypt := d.getMetaAesDecryptor()
152 aesDataDecrypt := d.getDataAesDecryptor()
153
154 d.footerMetadataDecryptor = &decryptor{
155 decryptor: aesMetaDecrypt,
156 key: []byte(footerKey),
157 fileAad: []byte(d.fileAad),
158 aad: []byte(aad),
159 mem: d.mem,
160 }
161 d.footerDataDecryptor = &decryptor{
162 decryptor: aesDataDecrypt,
163 key: []byte(footerKey),
164 fileAad: []byte(d.fileAad),
165 aad: []byte(aad),
166 mem: d.mem,
167 }
168
169 if metadata {
170 return d.footerMetadataDecryptor
171 }
172 return d.footerDataDecryptor
173 }
174
175 func (d *fileDecryptor) getColumnDecryptor(columnPath, columnMeta, aad string, metadata bool) Decryptor {
176 if metadata {
177 if res, ok := d.columnMetaDataMap[columnPath]; ok {
178 res.UpdateAad(aad)
179 return res
180 }
181 } else {
182 if res, ok := d.columnDataMap[columnPath]; ok {
183 res.UpdateAad(aad)
184 return res
185 }
186 }
187
188 columnKey := d.props.ColumnKey(columnPath)
189
190 if columnKey == "" && columnMeta != "" && d.props.KeyRetriever != nil {
191 columnKey = d.props.KeyRetriever.GetKey([]byte(columnMeta))
192 }
193 if columnKey == "" {
194 panic("hidden column exception, path=" + columnPath)
195 }
196
197 aesDataDecrypt := d.getDataAesDecryptor()
198 aesMetaDecrypt := d.getMetaAesDecryptor()
199
200 d.columnDataMap[columnPath] = &decryptor{
201 decryptor: aesDataDecrypt,
202 key: []byte(columnKey),
203 fileAad: []byte(d.fileAad),
204 aad: []byte(aad),
205 mem: d.mem,
206 }
207 d.columnMetaDataMap[columnPath] = &decryptor{
208 decryptor: aesMetaDecrypt,
209 key: []byte(columnKey),
210 fileAad: []byte(d.fileAad),
211 aad: []byte(aad),
212 mem: d.mem,
213 }
214
215 if metadata {
216 return d.columnMetaDataMap[columnPath]
217 }
218 return d.columnDataMap[columnPath]
219 }
220
221 func (d *fileDecryptor) getMetaAesDecryptor() *aesDecryptor {
222 if d.metaDecryptor == nil {
223 d.metaDecryptor = newAesDecryptor(d.alg, true)
224 }
225 return d.metaDecryptor
226 }
227
228 func (d *fileDecryptor) getDataAesDecryptor() *aesDecryptor {
229 if d.dataDecryptor == nil {
230 d.dataDecryptor = newAesDecryptor(d.alg, false)
231 }
232 return d.dataDecryptor
233 }
234
235
236 type Decryptor interface {
237
238 FileAad() string
239
240 Allocator() memory.Allocator
241
242 CiphertextSizeDelta() int
243
244 Decrypt(src []byte) []byte
245
246 DecryptFrom(r io.Reader) []byte
247
248 UpdateAad(string)
249 }
250
251 type decryptor struct {
252 decryptor *aesDecryptor
253 key []byte
254 fileAad []byte
255 aad []byte
256 mem memory.Allocator
257 }
258
259 func (d *decryptor) Allocator() memory.Allocator { return d.mem }
260 func (d *decryptor) FileAad() string { return string(d.fileAad) }
261 func (d *decryptor) UpdateAad(aad string) { d.aad = []byte(aad) }
262 func (d *decryptor) CiphertextSizeDelta() int { return d.decryptor.CiphertextSizeDelta() }
263 func (d *decryptor) Decrypt(src []byte) []byte {
264 return d.decryptor.Decrypt(src, d.key, d.aad)
265 }
266 func (d *decryptor) DecryptFrom(r io.Reader) []byte {
267 return d.decryptor.DecryptFrom(r, d.key, d.aad)
268 }
269
View as plain text