1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
22 "github.com/apache/arrow/go/v6/arrow/memory"
23 "github.com/apache/arrow/go/v6/parquet"
26 // FileEncryptor is the interface for constructing encryptors for the different
27 // sections of a parquet file.
28 type FileEncryptor interface {
29 // GetFooterEncryptor returns an encryptor for the footer metadata
30 GetFooterEncryptor() Encryptor
31 // GetFooterSigningEncryptor returns an encryptor for creating the signature
32 // for the footer as opposed to encrypting the footer bytes directly.
33 GetFooterSigningEncryptor() Encryptor
34 // GetColumnMetaEncryptor returns an encryptor for the metadata only of the requested
35 // column path string.
36 GetColumnMetaEncryptor(columnPath string) Encryptor
37 // GetColumnDataEncryptor returns an encryptor for the column data ONLY of
38 // the requested column path string.
39 GetColumnDataEncryptor(columnPath string) Encryptor
40 // WipeOutEncryptionKeys deletes the keys that were used for encryption,
41 // called after every successfully encrypted file to ensure against accidental
43 WipeOutEncryptionKeys()
46 type fileEncryptor struct {
47 props *parquet.FileEncryptionProperties
48 columnDataMap map[string]Encryptor
49 columnMetaDataMap map[string]Encryptor
50 footerSigningEncryptor Encryptor
51 footerEncryptor Encryptor
53 // Key must be 16, 24, or 32 bytes in length thus there could be up to
54 // three types of meta_encryptors and data_encryptors
55 metaEncryptor *aesEncryptor
56 dataEncryptor *aesEncryptor
61 // NewFileEncryptor returns a new encryptor using the given encryption properties.
63 // Panics if the properties passed have already been used to construct an encryptor
64 // ie: props.IsUtilized returns true. If mem is nil, will default to memory.DefaultAllocator
65 func NewFileEncryptor(props *parquet.FileEncryptionProperties, mem memory.Allocator) FileEncryptor {
66 if props.IsUtilized() {
67 panic("re-using encryption properties for another file")
72 mem = memory.DefaultAllocator
75 return &fileEncryptor{
78 columnDataMap: make(map[string]Encryptor),
79 columnMetaDataMap: make(map[string]Encryptor),
83 func (e *fileEncryptor) WipeOutEncryptionKeys() {
84 e.props.WipeOutEncryptionKeys()
87 func (e *fileEncryptor) GetFooterEncryptor() Encryptor {
88 if e.footerEncryptor == nil {
89 alg := e.props.Algorithm().Algo
90 footerAad := CreateFooterAad(e.props.FileAad())
91 footerKey := e.props.FooterKey()
92 enc := e.getMetaAesEncryptor(alg)
93 e.footerEncryptor = &encryptor{
95 key: []byte(footerKey),
96 fileAad: e.props.FileAad(),
101 return e.footerEncryptor
104 func (e *fileEncryptor) GetFooterSigningEncryptor() Encryptor {
105 if e.footerSigningEncryptor == nil {
106 alg := e.props.Algorithm().Algo
107 footerAad := CreateFooterAad(e.props.FileAad())
108 footerKey := e.props.FooterKey()
109 enc := e.getMetaAesEncryptor(alg)
110 e.footerSigningEncryptor = &encryptor{
112 key: []byte(footerKey),
113 fileAad: e.props.FileAad(),
118 return e.footerSigningEncryptor
121 func (e *fileEncryptor) getMetaAesEncryptor(alg parquet.Cipher) *aesEncryptor {
122 if e.metaEncryptor == nil {
123 e.metaEncryptor = NewAesEncryptor(alg, true)
125 return e.metaEncryptor
128 func (e *fileEncryptor) getDataAesEncryptor(alg parquet.Cipher) *aesEncryptor {
129 if e.dataEncryptor == nil {
130 e.dataEncryptor = NewAesEncryptor(alg, false)
132 return e.dataEncryptor
135 func (e *fileEncryptor) GetColumnMetaEncryptor(columnPath string) Encryptor {
136 return e.getColumnEncryptor(columnPath, true)
139 func (e *fileEncryptor) GetColumnDataEncryptor(columnPath string) Encryptor {
140 return e.getColumnEncryptor(columnPath, false)
143 func (e *fileEncryptor) getColumnEncryptor(columnPath string, metadata bool) Encryptor {
145 if enc, ok := e.columnMetaDataMap[columnPath]; ok {
149 if enc, ok := e.columnDataMap[columnPath]; ok {
154 columnProp := e.props.ColumnEncryptionProperties(columnPath)
155 if columnProp == nil {
160 if columnProp.IsEncryptedWithFooterKey() {
161 key = e.props.FooterKey()
163 key = columnProp.Key()
166 alg := e.props.Algorithm().Algo
167 var enc *aesEncryptor
169 enc = e.getMetaAesEncryptor(alg)
171 enc = e.getDataAesEncryptor(alg)
174 fileAad := e.props.FileAad()
183 e.columnMetaDataMap[columnPath] = ret
185 e.columnDataMap[columnPath] = ret
190 // Encryptor is the basic interface for encryptors, for now there's only the single
191 // aes encryptor implementation, but having it as an interface allows easy addition
192 // manipulation of encryptor implementations in the future.
193 type Encryptor interface {
194 // FileAad returns the file level AAD bytes for this encryptor
196 // UpdateAad sets the aad bytes for encryption to the provided string
198 // Allocator returns the allocator that was used to construct the encryptor
199 Allocator() memory.Allocator
200 // CiphertextSizeDelta returns the extra bytes that will be added to the ciphertext
201 // for a total size of len(plaintext) + CiphertextSizeDelta bytes
202 CiphertextSizeDelta() int
203 // Encrypt writes the encrypted ciphertext for src to w and returns the total
204 // number of bytes written.
205 Encrypt(w io.Writer, src []byte) int
206 // EncryptColumnMetaData returns true if the column metadata should be encrypted based on the
207 // column encryption settings and footer encryption setting.
208 EncryptColumnMetaData(encryptFooter bool, properties *parquet.ColumnEncryptionProperties) bool
211 type encryptor struct {
212 aesEncryptor *aesEncryptor
219 func (e *encryptor) FileAad() string { return e.fileAad }
220 func (e *encryptor) UpdateAad(aad string) { e.aad = aad }
221 func (e *encryptor) Allocator() memory.Allocator { return e.mem }
222 func (e *encryptor) CiphertextSizeDelta() int { return e.aesEncryptor.CiphertextSizeDelta() }
224 func (e *encryptor) EncryptColumnMetaData(encryptFooter bool, properties *parquet.ColumnEncryptionProperties) bool {
225 if properties == nil || !properties.IsEncrypted() {
231 // if not encrypted with footer key then encrypt the metadata
232 return !properties.IsEncryptedWithFooterKey()
235 func (e *encryptor) Encrypt(w io.Writer, src []byte) int {
236 return e.aesEncryptor.Encrypt(w, src, e.key, []byte(e.aad))