diff --git a/.gitignore b/.gitignore index d9ea881..3de6611 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ .DS_Store build .gradle -.idea -bin \ No newline at end of file +.idea \ No newline at end of file diff --git a/src/main/java/ch/fhnw/kry/CTR.java b/src/main/java/ch/fhnw/kry/CTR.java deleted file mode 100644 index 16c8c73..0000000 --- a/src/main/java/ch/fhnw/kry/CTR.java +++ /dev/null @@ -1,51 +0,0 @@ -package ch.fhnw.kry; - -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; - -import static ch.fhnw.kry.Main.BLOCK_LENGTH; - -/** - * Implementation of CTR mode for decryption. - */ -public class CTR { - private final SPN spn = new SPN(); - private final int iv; - private final int key; - - public CTR(int iv, int key) { - this.iv = iv; - this.key = key; - } - - /** - * Generate a 16 bit long initialisation vector. - * - * @return Generated initialisation vector. - */ - public static int generateIV() { - Random random = ThreadLocalRandom.current(); - byte[] r = new byte[2]; - random.nextBytes(r); - - return r[0] << 8 & r[1]; - } - - public int getIV() { - return iv; - } - - /** - * Decrypt a block in CTR mode. - * - * @param block Encrypted block (only lower 16 bits get looked at). - * @param idx Block index. - * @return Decrypted block (in the lower 16 bits of the int). - */ - public int decrypt(int block, int idx) { - int e = (iv + idx) % (1 << BLOCK_LENGTH); // iv + i mod 2^16 - e = spn.encryptBlock(key, e); // yes, we need the encryption function, as this is CTR - - return block ^ e; - } -} diff --git a/src/main/java/ch/fhnw/kry/Decrypt.java b/src/main/java/ch/fhnw/kry/Decrypt.java deleted file mode 100644 index 69aeab8..0000000 --- a/src/main/java/ch/fhnw/kry/Decrypt.java +++ /dev/null @@ -1,88 +0,0 @@ -package ch.fhnw.kry; - -import java.nio.charset.StandardCharsets; - -import static ch.fhnw.kry.Main.BLOCK_LENGTH; - -/** - * Decrypt cipher text with CTR and SPN. - *

- * Some implemented functions are not as flexible as could be, - * as everything basically assumes a block length of 16 bits. - * For this learning exercise, this is satisfactory though. - */ -public class Decrypt { - /** - * Decrypt a cipher text with a key, using CTR and an SPN. - *

- * The decrypted data is interpreted as ASCII code. - * - * @param keyString Key as a bit string. - * @param cipher Cipher text as a bit string. - * @return Decrypted data, interpreted as an ASCII string. - */ - public String decrypt(String keyString, String cipher) { - int key = Integer.parseInt(keyString, 2); // get the key - - int[] data = strToArray(cipher); - byte[] decryptedData = - new byte[data.length * 2]; // as the block size is 16 bits, the byte array needs double the capacity - int iv = data[0]; // first block is the iv - var ctr = new CTR(iv, key); - - for (int i = 0; i < data.length - 1; i++) { - int block = data[i + 1]; // index is i + 1 because i = 0 is the iv, hence the encrypted block is offset by 1 - int decryptedBlock = ctr.decrypt(block, i); - - decryptedData[i * 2] = (byte) (decryptedBlock >>> 8); // get the upper half of the decrypted block - decryptedData[i * 2 + 1] = (byte) (decryptedBlock & 0xFF); // and the lower half - } - - decryptedData = removePadding(decryptedData); - - return new String(decryptedData, StandardCharsets.US_ASCII); - } - - /** - * Remove the padding of data by traversing it - * backwards until a byte != 0 s found and lop it off behind - * the found position. - * - * @param data Data with padding. - * @return Input data without the padding. - */ - public byte[] removePadding(byte[] data) { - int idx = data.length - 1; - - while (idx > 0 && data[idx] == 0) { - idx--; - } - - byte[] unpaddedData = new byte[idx]; - System.arraycopy(data, 0, unpaddedData, 0, idx); - return unpaddedData; - } - - /** - * Convert a bit string into an integer array. - *

- * Because later we only ever look at the lower 16 bits, - * we stuff every block of 16 bits into the lower half of an int - * (meaning the igh 16 bits of the ints in the array are always 0). - * - * @param bits Bit string. Its length must be a multiple of 16. - * @return int array, with every int's lower 16 bits set to 16 bits of the input string. - */ - public int[] strToArray(String bits) { - int[] data = new int[bits.length() / BLOCK_LENGTH]; - - for (int i = 0; i < data.length; i++) { - int startIdx = i * BLOCK_LENGTH; - String wordBits = bits.substring(startIdx, startIdx + BLOCK_LENGTH); - int word = Integer.parseInt(wordBits, 2); - data[i] = word; - } - - return data; - } -} diff --git a/src/main/java/ch/fhnw/kry/Main.java b/src/main/java/ch/fhnw/kry/Main.java index dbcec11..e260c3d 100644 --- a/src/main/java/ch/fhnw/kry/Main.java +++ b/src/main/java/ch/fhnw/kry/Main.java @@ -5,21 +5,11 @@ package ch.fhnw.kry; */ public class Main { - static final String KEY = "00111010100101001101011000111111"; - static final String CIPHER = + private static final String KEY = "00111010100101001101011000111111"; + private static final String CHIFFRE = "00000100110100100000101110111000000000101000111110001110011111110110000001010001010000111010000000010011011001110010101110110000"; - static final int BLOCK_LENGTH = 16; - - /** - * Decrypt {@link Main#CIPHER} with {@link Main#KEY}. - *

- * In a real program we would read those from files or command line arguments. - * - * @param args Command line arguments. - */ public static void main(String[] args) { - var decrypt = new Decrypt(); - System.out.printf("decrypted message: %s%n", decrypt.decrypt(KEY, CIPHER)); + } } diff --git a/src/main/java/ch/fhnw/kry/SPN.java b/src/main/java/ch/fhnw/kry/SPN.java index 565ac7d..3b9ef91 100644 --- a/src/main/java/ch/fhnw/kry/SPN.java +++ b/src/main/java/ch/fhnw/kry/SPN.java @@ -3,7 +3,6 @@ package ch.fhnw.kry; import java.util.HashMap; import java.util.Map; -import static ch.fhnw.kry.Main.BLOCK_LENGTH; import static java.util.Map.entry; public class SPN { @@ -44,7 +43,6 @@ public class SPN { entry(7, 0xF) ); private final static int ROUND_KEY_LENGTH = 16; - private static final int ROUNDS = 4; private final Map PERMUTATION = Map.ofEntries( entry(0, 0), entry(1, 4), @@ -64,91 +62,56 @@ public class SPN { entry(15, 15) ); - /** - * Encrypt a block with the defined SPN. - * - * @param key Key for encryption (round keys get derived from this). - * @param x Input block (high 16 bits get ignored). - * @return Encrypted block. - */ + public String decrypt(int key, String chiffre) { + + return null; + } + public int encryptBlock(int key, int x) { - x = init(key, x, 0); // initialer Weisschritt + x = init(key, x, 0); - for (int i = 1; i < ROUNDS; i++) { // for rounds > 0 && < r - x = substitution(x, SBOX); // run through s-box - x = permutation(x); // permutate - x ^= k(key, i); // xor with derived round key + for (int i = 1; i < 4; i++) { + x = substitution(x, SBOX); + x = permutation(x); + x ^= k(key, i); } - x = substitution(x, SBOX); // run through s-box - x ^= k(key, ROUNDS); // xor with last round key + x = substitution(x, SBOX); + x ^= k(key, 4); return x; } - /** - * Decrypt a block with the defined SPN. - * - * @param key Key for decryption (round keys get derived from this). - * @param x Encrypted block (high 16 bits get ignored). - * @return Decrypted block. - */ public int decryptBlock(int key, int x) { - x = init(key, x, ROUNDS); // initialer Weisschritt + x = init(key, x, 4); - for (int i = ROUNDS - 1; i > 0; i--) { // for rounds > 0 && < r, going in reverse - x = substitution(x, SBOX_REVERSE); // run through reverse s-box - x = permutation(x); // permutate - x ^= permutation(k(key, i)); // xor with permutated derived round key + for (int i = 3; i > 0; i--) { + x = substitution(x, SBOX_REVERSE); + x = permutation(x); + x ^= k(key, i); } - x = substitution(x, SBOX_REVERSE); // run through reverse s-box - x ^= k(key, 0); // xor with round key 0 + x = substitution(x, SBOX_REVERSE); + x ^= k(key, 0); return x; } - /** - * Derive a round key from a key by multiplying - * the round number with four and taking the next 16 - * bits from that position in the key. - * - * @param key Key as input. - * @param i Round number (starts at 0). - * @return Derived key. - */ public int k(int key, int i) { - i *= ROUNDS; + i *= 4; int mask = 0xFFFF_0000 >>> i; return (key & mask) >>> ROUND_KEY_LENGTH - i; } - /** - * Initialer Weisschritt. - *

- * XOR an input with the key of a specific round. - * - * @param key Key to derive the round key. - * @param x Input. - * @param r Round number (starts at 0). - * @return Input xored with the derived round key. - */ public int init(int key, int x, int r) { return x ^ k(key, r); } - /** - * Permutate an input by swapping all its lower 16 bits as defined - * by a map. - * - * @param x Initial state (the high 16 bits of the integer are ignored). - * @return End state, after running all permutations. - */ public int permutation(int x) { Map blocked = new HashMap<>(); - for (int i = 0; i < BLOCK_LENGTH; i++) { + for (int i = 0; i < 16; i++) { int target = PERMUTATION.get(i); if (!blocked.containsKey(target)) { x = swapBits(x, i, target); @@ -158,13 +121,6 @@ public class SPN { return x; } - /** - * Substitute every four bits of an input by running them through an S-Box. - * - * @param x Initial state (the high 16 bits of the integer are ignored). - * @param sbox A mapping consisting of hex keys and values. - * @return End state, after running all substitutions. - */ public int substitution(int x, Map sbox) { int mask = 0xF000; for (int i = 0; i < 4; i++) { @@ -179,18 +135,7 @@ public class SPN { return x; } - /** - * Swap two bits. - *

- * Because we work with blocks of 16 bits, the high bits of the int input x are ignored. - * - * @param x Value where the bits get swapped (high 16 bits get ignored). - * @param a Position of the first bit to swap. - * @param b Position of the second bit to swap. - * @return Input value with bits in position a and b swapped. - */ public int swapBits(int x, int a, int b) { - // calculate the position respective to the 32 bits, hence ignoring the high 16 bits of x a = 15 - a; b = 15 - b; diff --git a/src/test/java/ch/fhnw/kry/CTRTest.java b/src/test/java/ch/fhnw/kry/CTRTest.java deleted file mode 100644 index ec0588f..0000000 --- a/src/test/java/ch/fhnw/kry/CTRTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package ch.fhnw.kry; - -import org.junit.jupiter.api.Test; - -class CTRTest { - - @Test - void generateIV() { - int count = 0; - while (count < Integer.MAX_VALUE) { - int iv = CTR.generateIV(); - assert (iv < 1 << 16); - count++; - } - } -} diff --git a/src/test/java/ch/fhnw/kry/DecryptTest.java b/src/test/java/ch/fhnw/kry/DecryptTest.java deleted file mode 100644 index e5e5d87..0000000 --- a/src/test/java/ch/fhnw/kry/DecryptTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package ch.fhnw.kry; - -import org.junit.jupiter.api.Test; - -import static ch.fhnw.kry.Main.CIPHER; -import static ch.fhnw.kry.Main.KEY; -import static org.junit.jupiter.api.Assertions.assertEquals; - -class DecryptTest { - - @Test - void strToArray() { - var decrypt = new Decrypt(); - - int[] data = decrypt.strToArray(CIPHER); - - assertEquals(8, data.length); - assertEquals(0x04D2, data[0]); - assertEquals(0x2BB0, data[data.length - 1]); - } - - @Test - void decrypt() { - var decrypt = new Decrypt(); - assertEquals("Gut gemacht!", decrypt.decrypt(KEY, CIPHER)); - } -} diff --git a/src/test/java/ch/fhnw/kry/SPNTest.java b/src/test/java/ch/fhnw/kry/SPNTest.java index d6e3127..782408b 100644 --- a/src/test/java/ch/fhnw/kry/SPNTest.java +++ b/src/test/java/ch/fhnw/kry/SPNTest.java @@ -2,7 +2,7 @@ package ch.fhnw.kry; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; class SPNTest { @@ -11,9 +11,9 @@ class SPNTest { var spn = new SPN(); final int key = 0xFFFFFFFF; - assertEquals(0xFFFF, spn.k(key, 0)); - assertEquals(0xFFFF, spn.k(key, 1)); - assertEquals(0xFFFF, spn.k(key, 2)); + assertEquals(0xFFFF, spn.k(key, 0)); + assertEquals(0xFFFF, spn.k(key, 1)); + assertEquals(0xFFFF, spn.k(key, 2)); } @Test @@ -63,10 +63,10 @@ class SPNTest { } @Test - void blockEncryptionDecryption() { + void sp() { var spn = new SPN(); - int x = 0x128F; + int x = 0x128F ; int key = 0x11288C00; int y = 0xAEB4;