/** * Given a candidate key OTP decrypts a cipher text using either the key directly or a key pseudo * randomly derived from the candidate, in order to match the length of the cipher text. * * <p> * The key candidate is assumed to be uniformly random. Thus, if its size longer or equal to the * cipher text, the candidate key will be used directly as a OTP key. Otherwise, the key will be * deterministically <i>stretched</i> to match the length of the cipher text in some secure way * (e.g., using a hash function). * </p> * * @param cipherText the cipher text to be decrypted * @param keyCandidate the candidate key for OTP decryption * @return the resulting message */ public static byte[] decrypt(byte[] cipherText, byte[] keyCandidate) { return decrypt(cipherText, keyCandidate, cipherText.length); }
/** * Given a candidate key OTP encrypts a message using either using the key directly or a key * pseudo randomly derived from the candidate, in order to match the length of the message. * * <p> * The key candidate is assumed to be uniformly random. Thus, if its size is longer or equal to * the message, the candidate key will be used directly as a OTP key. Otherwise, the key will be * deterministically <i>stretched</i> to match the length of the message in some secure way (e.g., * using a hash function). * </p> * * @param message the message to be encrypted * @param keyCandidate the candidate key * @return the resulting cipher text */ public static byte[] encrypt(byte[] message, byte[] keyCandidate) { return encrypt(message, keyCandidate, message.length); }
@Override public void send(StrictBitVector messageZero, StrictBitVector messageOne) { int maxBitLength = Math.max(messageZero.getSize(), messageOne.getSize()); Pair<byte[], byte[]> seedMessages = sendRandomOt(); byte[] encryptedZeroMessage = PseudoOtp.encrypt(messageZero.toByteArray(), seedMessages.getFirst(), maxBitLength / Byte.SIZE); byte[] encryptedOneMessage = PseudoOtp.encrypt(messageOne.toByteArray(), seedMessages.getSecond(), maxBitLength / Byte.SIZE); network.send(otherId, encryptedZeroMessage); network.send(otherId, encryptedOneMessage); }
/** * Receive one-time padded OT messages and remove the pad of the one of the messages chosen in the * OT. * * @param encryptedZeroMessage The one-time padded zero-message * @param encryptedOneMessage the one-time padded one-message * @param seed The seed used for padding of one of the messages * @param choiceBit A bit indicating which message the seed matches. False implies message zero * and true message one. * @return The unpadded message as a StrictBitVector */ private StrictBitVector recoverTrueMessage(byte[] encryptedZeroMessage, byte[] encryptedOneMessage, byte[] seed, boolean choiceBit) { if (encryptedZeroMessage.length != encryptedOneMessage.length) { throw new MaliciousException("The length of the two choice messages is not equal"); } byte[] unpaddedMessage; if (choiceBit == false) { unpaddedMessage = PseudoOtp.decrypt(encryptedZeroMessage, seed); } else { unpaddedMessage = PseudoOtp.decrypt(encryptedOneMessage, seed); } return new StrictBitVector(unpaddedMessage); }
/** * Adjust the random, preprocessed message, to fit the specific messages to send. * * @param messageZero The actual zero message to send * @param messageOne The actual one message to send */ private void doActualSend(byte[] messageZero, byte[] messageOne) { // Find the correct preprocessed random OT messages StrictBitVector randomZero = randomMessages.getFirst().get(offset); StrictBitVector randomOne = randomMessages.getSecond().get(offset); int maxLength = Math.max(messageZero.length, messageOne.length); // Receive a bit from the receiver indicating whether the zero and one // messages should be switched around byte[] switchBit = network.receive(resources.getOtherId()); // If false (indicated by byte 0x00), then don't switch around if (switchBit[0] == 0x00) { network.send(resources.getOtherId(), PseudoOtp.encrypt(messageZero, randomZero.toByteArray(), maxLength)); network.send(resources.getOtherId(), PseudoOtp.encrypt(messageOne, randomOne.toByteArray(), maxLength)); } else { network.send(resources.getOtherId(), PseudoOtp.encrypt(messageOne, randomZero.toByteArray(), maxLength)); network.send(resources.getOtherId(), PseudoOtp.encrypt(messageZero, randomOne.toByteArray(), maxLength)); } } }
/** * Adjust the random, preprocessed message, to fit the specific message sent * by the sender. * * @param zeroAdjustment * The adjustment value for the zero message * @param oneAdjustment * The adjustment value for the one message * @return The actual message */ private byte[] doActualReceive(byte[] zeroAdjustment, byte[] oneAdjustment) { if (zeroAdjustment.length != oneAdjustment.length) { throw new MaliciousException( "Sender gave adjustment messages of different length."); } byte[] adjustment; if (choices.getBit(offset, false) == false) { adjustment = zeroAdjustment; } else { adjustment = oneAdjustment; } return PseudoOtp.decrypt(adjustment, randomMessages.get(offset).toByteArray()); }