RosettaCodeData/Task/One-time-pad/Java/one-time-pad.java

127 lines
5.0 KiB
Java

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class OneTimePad {
public static void main(String[] args) {
String controlName = "AtomicBlonde";
generatePad(controlName, 5, 60, 65, 90);
String text = "IT WAS THE BEST OF TIMES IT WAS THE WORST OF TIMES";
String encrypted = parse(true, controlName, text.replaceAll(" ", ""));
String decrypted = parse(false, controlName, encrypted);
System.out.println("Input text = " + text);
System.out.println("Encrypted text = " + encrypted);
System.out.println("Decrypted text = " + decrypted);
controlName = "AtomicBlondeCaseSensitive";
generatePad(controlName, 5, 60, 32, 126);
text = "It was the best of times, it was the worst of times.";
encrypted = parse(true, controlName, text);
decrypted = parse(false, controlName, encrypted);
System.out.println();
System.out.println("Input text = " + text);
System.out.println("Encrypted text = " + encrypted);
System.out.println("Decrypted text = " + decrypted);
}
private static String parse(boolean encryptText, String controlName, String text) {
StringBuilder sb = new StringBuilder();
int minCh = 0;
int maxCh = 0;
Pattern minChPattern = Pattern.compile("^# MIN_CH = ([\\d]+)$");
Pattern maxChPattern = Pattern.compile("^# MAX_CH = ([\\d]+)$");
boolean validated = false;
try (BufferedReader in = new BufferedReader(new FileReader(getFileName(controlName))); ) {
String inLine = null;
while ( (inLine = in.readLine()) != null ) {
Matcher minMatcher = minChPattern.matcher(inLine);
if ( minMatcher.matches() ) {
minCh = Integer.parseInt(minMatcher.group(1));
continue;
}
Matcher maxMatcher = maxChPattern.matcher(inLine);
if ( maxMatcher.matches() ) {
maxCh = Integer.parseInt(maxMatcher.group(1));
continue;
}
if ( ! validated && minCh > 0 && maxCh > 0 ) {
validateText(text, minCh, maxCh);
validated = true;
}
// # is comment. - is used key.
if ( inLine.startsWith("#") || inLine.startsWith("-") ) {
continue;
}
// Have encryption key.
String key = inLine;
if ( encryptText ) {
for ( int i = 0 ; i < text.length(); i++) {
sb.append((char) (((text.charAt(i) - minCh + key.charAt(i) - minCh) % (maxCh - minCh + 1)) + minCh));
}
}
else {
for ( int i = 0 ; i < text.length(); i++) {
int decrypt = text.charAt(i) - key.charAt(i);
if ( decrypt < 0 ) {
decrypt += maxCh - minCh + 1;
}
decrypt += minCh;
sb.append((char) decrypt);
}
}
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return sb.toString();
}
private static void validateText(String text, int minCh, int maxCh) {
// Validate text is in range
for ( char ch : text.toCharArray() ) {
if ( ch != ' ' && (ch < minCh || ch > maxCh) ) {
throw new IllegalArgumentException("ERROR 103: Invalid text.");
}
}
}
private static String getFileName(String controlName) {
return controlName + ".1tp";
}
private static void generatePad(String controlName, int keys, int keyLength, int minCh, int maxCh) {
Random random = new Random();
try ( BufferedWriter writer = new BufferedWriter(new FileWriter(getFileName(controlName), false)); ) {
writer.write("# Lines starting with '#' are ignored.");
writer.newLine();
writer.write("# Lines starting with '-' are previously used.");
writer.newLine();
writer.write("# MIN_CH = " + minCh);
writer.newLine();
writer.write("# MAX_CH = " + maxCh);
writer.newLine();
for ( int line = 0 ; line < keys ; line++ ) {
StringBuilder sb = new StringBuilder();
for ( int ch = 0 ; ch < keyLength ; ch++ ) {
sb.append((char) (random.nextInt(maxCh - minCh + 1) + minCh));
}
writer.write(sb.toString());
writer.newLine();
}
writer.write("# EOF");
writer.newLine();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}