blob: d91fa2dc8f25c1d3635eac6c53612b77dbd55904 [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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.pirk.querier.wideskies;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.UUID;
import org.apache.pirk.encryption.Paillier;
import org.apache.pirk.querier.wideskies.decrypt.DecryptResponse;
import org.apache.pirk.querier.wideskies.encrypt.EncryptQuery;
import org.apache.pirk.query.wideskies.QueryInfo;
import org.apache.pirk.response.wideskies.Response;
import org.apache.pirk.schema.query.QuerySchemaRegistry;
import org.apache.pirk.serialization.LocalFileSystemStore;
import org.apache.pirk.utils.FileIOUtils;
import org.apache.pirk.utils.PIRException;
import org.apache.pirk.utils.SystemConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Driver class for encryption of a query or decryption of a response
* <p>
* File based: For encryption, specify:
* <p>
* (1) A query file - one selector per line and the first line in file is the unique query number,
* <p>
* (2) The query type, and
* <p>
* (3) All necessary encryption parameters.
* <p>
* Two corresponding files will be emitted:
* <p>
* (1) A file containing the serialized Query object (to be sent to the responder) and
* <p>
* (2) A file containing the serialized Querier object to be used for decryption.
* <p>
* For decryption, specify:
* <p>
* (1) A response file containing the serialized Response object and
* <p>
* (2) The corresponding decryption information file containing the serialized Querier object.
* <p>
* The output will be a file containing the hits for the query, where each line corresponds to one hit and is the string representation of the corresponding
* QueryResponseJSON object.
* <p>
* Can optionally specify a bit position that must be set in the Paillier modulus
* <p>
* TODO:
* <p>
* - Add interior functionality for multiple query looping?
* <p>
* - Partition size is (practically) fixed at 8 bits, for now... configurable, but ignored right now
*/
public class QuerierDriver implements Serializable
{
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(QuerierDriver.class);
public static void main(String... args) throws IOException, InterruptedException, PIRException
{
// General variables
String action;
String inputFile;
String outputFile;
String queryType = null;
int numThreads;
LocalFileSystemStore storage = new LocalFileSystemStore();
// Encryption variables
int hashBitSize = 0;
String hashKey = null;
int dataPartitionBitSize = 0;
int paillierBitSize = 0;
int certainty = 0;
int bitSet = -1;
boolean embedSelector = true;
boolean useMemLookupTable = false;
boolean useHDFSLookupTable = false;
// Decryption variables
String querierFile = null;
// Parse the args
QuerierCLI qdriverCLI = new QuerierCLI(args);
// Set the variables
action = SystemConfiguration.getProperty(QuerierProps.ACTION);
inputFile = SystemConfiguration.getProperty(QuerierProps.INPUTFILE);
outputFile = SystemConfiguration.getProperty(QuerierProps.OUTPUTFILE);
numThreads = Integer.parseInt(SystemConfiguration.getProperty(QuerierProps.NUMTHREADS));
if (action.equals("encrypt"))
{
queryType = SystemConfiguration.getProperty(QuerierProps.QUERYTYPE);
hashBitSize = Integer.parseInt(SystemConfiguration.getProperty(QuerierProps.HASHBITSIZE));
hashKey = SystemConfiguration.getProperty(QuerierProps.HASHBITSIZE);
dataPartitionBitSize = Integer.parseInt(SystemConfiguration.getProperty(QuerierProps.DATAPARTITIONSIZE));
paillierBitSize = Integer.parseInt(SystemConfiguration.getProperty(QuerierProps.PAILLIERBITSIZE));
certainty = Integer.parseInt(SystemConfiguration.getProperty(QuerierProps.CERTAINTY));
embedSelector = SystemConfiguration.getBooleanProperty(QuerierProps.EMBEDSELECTOR, true);
useMemLookupTable = SystemConfiguration.getBooleanProperty(QuerierProps.USEMEMLOOKUPTABLE, false);
useHDFSLookupTable = SystemConfiguration.getBooleanProperty(QuerierProps.USEHDFSLOOKUPTABLE, false);
if (SystemConfiguration.hasProperty(QuerierProps.BITSET))
{
bitSet = Integer.parseInt(SystemConfiguration.getProperty(QuerierProps.BITSET));
logger.info("bitSet = " + bitSet);
}
// Check to ensure we have a valid queryType
if (QuerySchemaRegistry.get(queryType) == null)
{
logger.error("Invalid schema: " + queryType + "; The following schemas are loaded:");
for (String schema : QuerySchemaRegistry.getNames())
{
logger.info("schema = " + schema);
}
System.exit(0);
}
// Enforce dataPartitionBitSize < 32
if (dataPartitionBitSize > 31)
{
logger.error("dataPartitionBitSize = " + dataPartitionBitSize + "; must be less than 32");
}
}
if (action.equals("decrypt"))
{
querierFile = SystemConfiguration.getProperty(QuerierProps.QUERIERFILE);
}
// Perform the action
if (action.equals("encrypt"))
{
logger.info("Performing encryption: \n inputFile = " + inputFile + "\n outputFile = " + outputFile + "\n numThreads = " + numThreads
+ "\n hashBitSize = " + hashBitSize + "\n hashKey = " + hashKey + "\n dataPartitionBitSize = " + dataPartitionBitSize + "\n paillierBitSize = "
+ paillierBitSize + "\n certainty = " + certainty);
// Read in the selectors and extract the queryIdentifier - first line in the file
ArrayList<String> selectors = FileIOUtils.readToArrayList(inputFile);
UUID queryIdentifier = UUID.fromString(selectors.get(0));
selectors.remove(0);
int numSelectors = selectors.size();
logger.info("queryIdentifier = " + queryIdentifier + " numSelectors = " + numSelectors);
// Set the necessary QueryInfo and Paillier objects
QueryInfo queryInfo = new QueryInfo(queryIdentifier, numSelectors, hashBitSize, hashKey, dataPartitionBitSize, queryType, useMemLookupTable,
embedSelector, useHDFSLookupTable);
if (SystemConfiguration.isSetTrue("pir.embedQuerySchema"))
{
queryInfo.addQuerySchema(QuerySchemaRegistry.get(queryType));
}
Paillier paillier = new Paillier(paillierBitSize, certainty, bitSet); // throws PIRException if certainty conditions are not satisfied
// Check the number of selectors to ensure that 2^{numSelector*dataPartitionBitSize} < N
// For example, if the highest bit is set, the largest value is \floor{paillierBitSize/dataPartitionBitSize}
int exp = numSelectors * dataPartitionBitSize;
BigInteger val = (BigInteger.valueOf(2)).pow(exp);
if (val.compareTo(paillier.getN()) != -1)
{
logger.error("The number of selectors = " + numSelectors + " must be such that " + "2^{numSelector*dataPartitionBitSize} < N = "
+ paillier.getN().toString(2));
System.exit(0);
}
// Perform the encryption
EncryptQuery encryptQuery = new EncryptQuery(queryInfo, selectors, paillier);
encryptQuery.encrypt(numThreads);
// Write necessary output files - two files written -
// (1) Querier object to <outputFile>-QuerierConst.QUERIER_FILETAG
// (2) Query object to <outputFile>-QuerierConst.QUERY_FILETAG
storage.store(outputFile + "-" + QuerierConst.QUERIER_FILETAG, encryptQuery.getQuerier());
storage.store(outputFile + "-" + QuerierConst.QUERY_FILETAG, encryptQuery.getQuery());
}
else
// Decryption
{
// Reconstruct the necessary objects from the files
Response response = storage.recall(inputFile, Response.class);
Querier querier = storage.recall(querierFile, Querier.class);
UUID querierQueryID = querier.getQuery().getQueryInfo().getIdentifier();
UUID responseQueryID = response.getQueryInfo().getIdentifier();
if (!querierQueryID.equals(responseQueryID))
{
logger.error("The query identifier in the Response: " + responseQueryID.toString() + " does not match the query identifier specified in the Querier: "
+ querierQueryID.toString());
System.exit(0);
}
// Perform decryption and output the result file
DecryptResponse decryptResponse = new DecryptResponse(response, querier);
decryptResponse.decrypt(numThreads);
decryptResponse.writeResultFile(outputFile);
}
}
}