blob: ad7a969b83e54d5573d785b82aa4fd96de6bf7f4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.orc.impl.reader;
import org.apache.hadoop.conf.Configuration;
import org.apache.orc.OrcProto;
import org.apache.orc.StripeInformation;
import org.apache.orc.TypeDescription;
import org.apache.orc.impl.BufferChunk;
import org.apache.orc.impl.CryptoUtils;
import org.apache.orc.impl.KeyProvider;
import org.apache.orc.impl.MaskDescriptionImpl;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.List;
public class ReaderEncryption {
private final KeyProvider keyProvider;
private final ReaderEncryptionKey[] keys;
private final MaskDescriptionImpl[] masks;
private final ReaderEncryptionVariant[] variants;
// Mapping from each column to the next variant to try for that column.
// A value of variants.length means no encryption
private final ReaderEncryptionVariant[] columnVariants;
public ReaderEncryption() {
keyProvider = null;
keys = new ReaderEncryptionKey[0];
masks = new MaskDescriptionImpl[0];
variants = new ReaderEncryptionVariant[0];
columnVariants = null;
}
public ReaderEncryption(OrcProto.Footer footer,
TypeDescription schema,
long stripeStatisticsOffset,
BufferChunk serializedTail,
List<StripeInformation> stripes,
KeyProvider provider,
Configuration conf) throws IOException {
if (footer == null || !footer.hasEncryption()) {
keyProvider = null;
keys = new ReaderEncryptionKey[0];
masks = new MaskDescriptionImpl[0];
variants = new ReaderEncryptionVariant[0];
columnVariants = null;
} else {
keyProvider = provider != null ? provider :
CryptoUtils.getKeyProvider(conf, new SecureRandom());
OrcProto.Encryption encrypt = footer.getEncryption();
masks = new MaskDescriptionImpl[encrypt.getMaskCount()];
for(int m=0; m < masks.length; ++m) {
masks[m] = new MaskDescriptionImpl(m, encrypt.getMask(m));
}
keys = new ReaderEncryptionKey[encrypt.getKeyCount()];
for(int k=0; k < keys.length; ++k) {
keys[k] = new ReaderEncryptionKey(encrypt.getKey(k));
}
variants = new ReaderEncryptionVariant[encrypt.getVariantsCount()];
long offset = stripeStatisticsOffset;
for(int v=0; v < variants.length; ++v) {
OrcProto.EncryptionVariant variant = encrypt.getVariants(v);
variants[v] = new ReaderEncryptionVariant(keys[variant.getKey()], v,
variant, schema, stripes, offset, serializedTail, keyProvider);
offset += variants[v].getStripeStatisticsLength();
}
columnVariants = new ReaderEncryptionVariant[schema.getMaximumId() + 1];
for (ReaderEncryptionVariant variant : variants) {
TypeDescription root = variant.getRoot();
for (int c = root.getId(); c <= root.getMaximumId(); ++c) {
// set the variant if it is the first one that we've found
if (columnVariants[c] == null) {
columnVariants[c] = variant;
}
}
}
}
}
public MaskDescriptionImpl[] getMasks() {
return masks;
}
public ReaderEncryptionKey[] getKeys() {
return keys;
}
public ReaderEncryptionVariant[] getVariants() {
return variants;
}
/**
* Find the next possible variant in this file for the given column.
* @param column the column to find a variant for
* @param lastVariant the previous variant that we looked at
* @return the next variant or null if there isn't one
*/
private ReaderEncryptionVariant findNextVariant(int column,
int lastVariant) {
for(int v = lastVariant + 1; v < variants.length; ++v) {
TypeDescription root = variants[v].getRoot();
if (root.getId() <= column && column <= root.getMaximumId()) {
return variants[v];
}
}
return null;
}
/**
* Get the variant for a given column that the user has access to.
* If we haven't tried a given key, try to decrypt this variant's footer key
* to see if the KeyProvider will give it to us. If not, continue to the
* next variant.
* @param column the column id
* @return the encryption variant or null if there isn't one
*/
public ReaderEncryptionVariant getVariant(int column) {
if (columnVariants == null) {
return null;
} else {
while (columnVariants[column] != null &&
!columnVariants[column].getKeyDescription().isAvailable()) {
if (keyProvider != null) {
columnVariants[column] =
findNextVariant(column, columnVariants[column].getVariantId());
}
}
return columnVariants[column];
}
}
}