dk.alexandra.fresco.demo.AESDemo.java Source code

Java tutorial

Introduction

Here is the source code for dk.alexandra.fresco.demo.AESDemo.java

Source

/*******************************************************************************
 * Copyright (c) 2015 FRESCO (http://github.com/aicis/fresco).
 *
 * This file is part of the FRESCO project.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * FRESCO uses SCAPI - http://crypto.biu.ac.il/SCAPI, Crypto++, Miracl, NTL,
 * and Bouncy Castle. Please see these projects for any further licensing issues.
 *******************************************************************************/
package dk.alexandra.fresco.demo;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;

import dk.alexandra.fresco.framework.Application;
import dk.alexandra.fresco.framework.MPCException;
import dk.alexandra.fresco.framework.Protocol;
import dk.alexandra.fresco.framework.ProtocolFactory;
import dk.alexandra.fresco.framework.ProtocolProducer;
import dk.alexandra.fresco.framework.configuration.CmdLineUtil;
import dk.alexandra.fresco.framework.sce.SCE;
import dk.alexandra.fresco.framework.sce.SCEFactory;
import dk.alexandra.fresco.framework.sce.configuration.SCEConfiguration;
import dk.alexandra.fresco.framework.util.ByteArithmetic;
import dk.alexandra.fresco.framework.value.OBool;
import dk.alexandra.fresco.framework.value.SBool;
import dk.alexandra.fresco.lib.crypto.BristolCryptoFactory;
import dk.alexandra.fresco.lib.field.bool.BasicLogicFactory;
import dk.alexandra.fresco.lib.helper.ParallelProtocolProducer;
import dk.alexandra.fresco.lib.helper.sequential.SequentialProtocolProducer;

/**
 * This demonstrates how to aggregate generic protocols to form an application.
 * 
 * It is designed for two players and requires a protocol suite that supports
 * basic logic operations.
 * 
 * Player 1 inputs a secret 128-bit AES key (as a 32 char hex string), player 2
 * inputs a secret plaintext (also a 32 char hex string). The output (to both
 * players) is the resulting AES encryption of the plaintext under the given AES
 * key.
 * 
 * Suppose we have two players. P2 has the plaintext block
 * 000102030405060708090a0b0c0d0e0f and P1 has the key
 * 00112233445566778899aabbccddeeff. They both want to know the ciphertext,
 * i.e., the result of encrypting 000102030405060708090a0b0c0d0e0f under the key
 * 00112233445566778899aabbccddeeff, but they do not want to reveal the key and
 * the plaintext to each other.
 * 
 * The two players can then run this application with these parameters:
 * 
 * P1: $ java -jar aes.jar -i1 -s dummy -p1:localhost:9292 -p2:localhost:9994 -in 000102030405060708090a0b0c0d0e0f
 * 
 * P2: $ java -jar aes.jar -i2 -s dummy -p1:localhost:9292 -p2:localhost:9994 -in 00112233445566778899aabbccddeeff
 * 
 * This results in this output (at both parties):
 * 
 * The resulting ciphertext is: 69c4e0d86a7b0430d8cdb78070b4c55a
 * 
 * OBS: Using the dummy protocol suite is not secure!
 * 
 */
public class AESDemo implements Application {

    /**
     * Applications can be uploaded to fresco dynamically and are therefore
     * Serializable's. This means that each application must have a unique
     * serialVersionUID.
     * 
     */
    private static final long serialVersionUID = 1081355810959328531L;

    private boolean[] in;
    private int id;

    public OBool[] result;

    private final static int BLOCK_SIZE = 128; // 128 bit AES
    private final static int INPUT_LENGTH = 32; // chars for defining 128 bit in hex

    public AESDemo(int id, boolean[] in) {
        this.in = in;
        this.id = id;
    }

    /**
     * The main method sets up application specific command line parameters,
     * parses command line arguments. Based on the command line arguments it
     * configures the SCE, instantiates the TestAESDemo and runs the TestAESDemo on the
     * SCE.
     * 
     */
    public static void main(String[] args) {
        CmdLineUtil util = new CmdLineUtil();
        SCEConfiguration sceConf = null;
        boolean[] input = null;
        try {

            util.addOption(Option.builder("in")
                    .desc("The input to use for encryption. " + "A " + INPUT_LENGTH
                            + " char hex string. Required for player 1 and 2. "
                            + "For player 1 this is interpreted as the AES key. "
                            + "For player 2 this is interpreted as the plaintext block to encrypt.")
                    .longOpt("input").hasArg().build());

            CommandLine cmd = util.parse(args);
            sceConf = util.getSCEConfiguration();

            // Get and validate the AES specific input.
            if (sceConf.getMyId() == 1 || sceConf.getMyId() == 2) {
                if (!cmd.hasOption("in")) {
                    throw new ParseException("Player 1 and 2 must submit input");
                } else {
                    if (cmd.getOptionValue("in").length() != INPUT_LENGTH) {
                        throw new IllegalArgumentException(
                                "bad input hex string: must be hex string of length " + INPUT_LENGTH);
                    }
                    input = ByteArithmetic.toBoolean(cmd.getOptionValue("in"));
                }
            } else {
                if (cmd.hasOption("in")) {
                    throw new ParseException("Only player 1 and 2 should submit input");
                }
            }

        } catch (ParseException | IllegalArgumentException e) {
            System.out.println("Error: " + e);
            System.out.println();
            util.displayHelp();
            System.exit(-1);
        }

        // Do the secure computation using config from property files.
        AESDemo aes = new AESDemo(sceConf.getMyId(), input);
        SCE sce = SCEFactory.getSCEFromConfiguration(sceConf, util.getProtocolSuiteConfiguration());

        try {
            sce.runApplication(aes);
        } catch (MPCException e) {
            System.out.println("Error while doing MPC: " + e.getMessage());
            System.exit(-1);
        }

        // Print result.
        boolean[] res = new boolean[BLOCK_SIZE];
        for (int i = 0; i < BLOCK_SIZE; i++) {
            res[i] = aes.result[i].getValue();
        }
        System.out.println("The resulting ciphertext is: " + ByteArithmetic.toHex(res));

    }

    /**
     * This is where the actual computation is defined. The method builds up a
     * protocol that does one evaluation of an AES block encryption. This
     * involves protocols for 'closing' the plaintext and key, i.e., converting
     * them from something that one of the players knows to secret values. It
     * also involves a protocol for AES that works on secret values, and
     * protocols for opening up the resulting ciphertext.
     * 
     * The final protocol is build from smaller protocols using the
     * ParallelProtocolProducer and SequentialProtocolProducer. The open and
     * closed values (OBool and SBool) are used to 'glue' the subprotocols
     * together.
     * 
     */
    @Override
    public ProtocolProducer prepareApplication(ProtocolFactory factory) {

        if (!(factory instanceof BasicLogicFactory)) {
            throw new MPCException(factory.getClass().getSimpleName()
                    + " is not a BasicLogicFactory. This AES demo requires a protocol suite that implements the BasicLogicFactory.");
        }
        BasicLogicFactory boolFactory = (BasicLogicFactory) factory;

        OBool[] plainOpen = new OBool[BLOCK_SIZE];
        OBool[] keyOpen = new OBool[BLOCK_SIZE];
        for (int i = 0; i < BLOCK_SIZE; i++) {
            keyOpen[i] = boolFactory.getOBool();
            plainOpen[i] = boolFactory.getOBool();
            if (this.id == 1) {
                keyOpen[i].setValue(this.in[i]);
            } else if (this.id == 2) {
                plainOpen[i].setValue(this.in[i]);
            } else {
                // OK, there might be more players, but they don't have input.
            }
        }

        // Establish some secure values.
        SBool[] keyClosed = boolFactory.getSBools(BLOCK_SIZE);
        SBool[] plainClosed = boolFactory.getSBools(BLOCK_SIZE);
        SBool[] outClosed = boolFactory.getSBools(BLOCK_SIZE);

        // Build protocol where player 1 closes his key. 
        ProtocolProducer[] closeKeyBits = new ProtocolProducer[BLOCK_SIZE];
        for (int i = 0; i < BLOCK_SIZE; i++) {
            closeKeyBits[i] = boolFactory.getCloseProtocol(1, keyOpen[i], keyClosed[i]);
        }
        ProtocolProducer closeKey = new ParallelProtocolProducer(closeKeyBits);

        // Buil protocol where player 2 closes his plaintext.
        ProtocolProducer[] closePlainBits = new ProtocolProducer[BLOCK_SIZE];
        for (int i = 0; i < BLOCK_SIZE; i++) {
            closePlainBits[i] = boolFactory.getCloseProtocol(2, plainOpen[i], plainClosed[i]);
        }
        ProtocolProducer closePlain = new ParallelProtocolProducer(closePlainBits);

        // We can close key and plaintext in parallel.
        ProtocolProducer closeKeyAndPlain = new ParallelProtocolProducer(closeKey, closePlain);

        // Build an AES protocol.
        Protocol doAES = new BristolCryptoFactory(boolFactory).getAesProtocol(plainClosed, keyClosed, outClosed);

        // Create wires that glue together the AES to the following open of the result.
        this.result = boolFactory.getOBools(BLOCK_SIZE);

        // Construct protocol for opening up the result.
        Protocol[] opens = new Protocol[BLOCK_SIZE];
        for (int i = 0; i < BLOCK_SIZE; i++) {
            opens[i] = boolFactory.getOpenProtocol(outClosed[i], result[i]);
        }
        ProtocolProducer openCipher = new ParallelProtocolProducer(opens);

        // First we close key and plaintext, then we do the AES, then we open the resulting ciphertext.
        ProtocolProducer finalProtocol = new SequentialProtocolProducer(closeKeyAndPlain, doAES, openCipher);

        return finalProtocol;

    }

}