/** * Given a candidate key OTP encrypts a message using either 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 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 for OTP encryption * @param messageLength fixes the length of the message to encrypt, the given <code>message</code> * will be either truncated or padded with zeroes to match this length. * @return the resulting cipher text */ public static byte[] encrypt(byte[] message, byte[] keyCandidate, int messageLength) { Objects.requireNonNull(message); Objects.requireNonNull(keyCandidate); byte[] cipherText = LengthAdjustment.adjust(keyCandidate, messageLength); ByteArrayHelper.xor(cipherText, Arrays.copyOf(message, messageLength)); return cipherText; }
/** * 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 * @param messageLength fixes the length of the message to decrypt, the given * <code>cipherText</code> will be either truncated or padded with zeroes to match this * length. * @return the resulting message */ public static byte[] decrypt(byte[] cipherText, byte[] keyCandidate, int messageLength) { Objects.requireNonNull(cipherText); Objects.requireNonNull(keyCandidate); byte[] key = LengthAdjustment.adjust(keyCandidate, messageLength); ByteArrayHelper.xor(key, Arrays.copyOf(cipherText, messageLength)); return key; }
@Override public List<Pair<StrictBitVector, StrictBitVector>> send(int numMessages, int sizeOfEachMessage) { if (this.sender == null) { this.sender = rot.createSender(); } int amountToPreprocess = computeExtensionSize(numMessages, comSecParam, statSecParam); Pair<List<StrictBitVector>, List<StrictBitVector>> messages = sender.extend(amountToPreprocess); List<StrictBitVector> zeroMessages = messages.getFirst().parallelStream().limit(numMessages) .map(m -> LengthAdjustment.adjust(m.toByteArray(), sizeOfEachMessage / Byte.SIZE)) .map(StrictBitVector::new) .collect(Collectors.toList()); List<StrictBitVector> oneMessages = messages.getSecond().parallelStream().limit(numMessages) .map(m -> LengthAdjustment.adjust(m.toByteArray(), sizeOfEachMessage / Byte.SIZE)) .map(StrictBitVector::new) .collect(Collectors.toList()); return IntStream.range(0, numMessages).parallel() .mapToObj(i -> new Pair<>(zeroMessages.get(i), oneMessages.get(i))) .collect(Collectors.toList()); }
@Override public List<StrictBitVector> receive(StrictBitVector choiceBits, int sizeOfEachMessage) { if (this.receiver == null) { this.receiver = rot.createReceiver(); } int amountToPreprocess = computeExtensionSize(choiceBits.getSize(), comSecParam, statSecParam); byte[] extraByteChoices = Arrays.copyOf(choiceBits.toByteArray(), amountToPreprocess / Byte.SIZE); List<StrictBitVector> messages = receiver.extend(new StrictBitVector(extraByteChoices)); return messages.parallelStream().limit(choiceBits.getSize()) .map(m -> LengthAdjustment.adjust(m.toByteArray(), sizeOfEachMessage / Byte.SIZE)) .map(StrictBitVector::new) .collect(Collectors.toList()); }