commit 7fa074027d7f9cfac130ccdb8927133070b0b444 Author: Paul Date: Sun Oct 18 21:40:18 2020 +0200 initial commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..4aa91ea --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/description.html b/.idea/description.html new file mode 100644 index 0000000..db5f129 --- /dev/null +++ b/.idea/description.html @@ -0,0 +1 @@ +Simple Java application that includes a class with main() method \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..ab2dc53 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/libraries/javassist_javassist_3_12_1_GA.xml b/.idea/libraries/javassist_javassist_3_12_1_GA.xml new file mode 100644 index 0000000..61c0f12 --- /dev/null +++ b/.idea/libraries/javassist_javassist_3_12_1_GA.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..a185f7d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4cd623a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/project-template.xml b/.idea/project-template.xml new file mode 100644 index 0000000..d57a956 --- /dev/null +++ b/.idea/project-template.xml @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..b93ac08 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ChaCha20.iml b/ChaCha20.iml new file mode 100644 index 0000000..b010649 --- /dev/null +++ b/ChaCha20.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/tech/loedige/AdditiveStreamCipher.java b/src/tech/loedige/AdditiveStreamCipher.java new file mode 100644 index 0000000..f445b56 --- /dev/null +++ b/src/tech/loedige/AdditiveStreamCipher.java @@ -0,0 +1,10 @@ +package tech.loedige; + +public class AdditiveStreamCipher { + + static public void encrypt(KeyStreamGenerator ksg, byte[] m) { + for (int i = 0; i < m.length; ++i) { + m[i] ^= ksg.getNextKeyStreamByte(m[i]); + } + } +} diff --git a/src/tech/loedige/KeyStreamGenerator.java b/src/tech/loedige/KeyStreamGenerator.java new file mode 100644 index 0000000..6d813bc --- /dev/null +++ b/src/tech/loedige/KeyStreamGenerator.java @@ -0,0 +1,12 @@ +package tech.loedige; + +public abstract class KeyStreamGenerator { + /** + * Berechnung des nächsten Schlüsselstrombytes. + * (Entspricht einem einmaligen Aufruf der + * Update-Funktion s und der Extraktions-Funktion S.) + * + * @return Nächstes Schlüsselstrombyte + */ + abstract byte getNextKeyStreamByte(byte mByte); +} diff --git a/src/tech/loedige/KeyStreamGenerator_AES_CTR.java b/src/tech/loedige/KeyStreamGenerator_AES_CTR.java new file mode 100644 index 0000000..0bcfeae --- /dev/null +++ b/src/tech/loedige/KeyStreamGenerator_AES_CTR.java @@ -0,0 +1,63 @@ +package tech.loedige; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class KeyStreamGenerator_AES_CTR extends KeyStreamGenerator { + + private Cipher cipher; + private final byte[] state = new byte[16]; + private final byte[] ctr = new byte[16]; + private int currentByte=0; + + public void initState(byte[] key, byte[] iv) + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + if((iv.length!=16)||(key.length!=16)){ + throw new IllegalArgumentException("Invalid input length"); + } + System.arraycopy(iv,0,ctr,0,16); + + SecretKey secretKey = new SecretKeySpec(key,"AES"); + cipher = Cipher.getInstance("AES/ECB/NOPADDING"); + cipher.init(Cipher.ENCRYPT_MODE,secretKey); + } + + @Override + byte getNextKeyStreamByte(byte mByte) { + currentByte++; + if(currentByte>=16){ + try { + updateStateBlock(); + } catch (BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + } + currentByte=0; + } + return state[currentByte]; + } + + private void updateStateBlock() + throws BadPaddingException, IllegalBlockSizeException { + incrementCtr(); + System.arraycopy(cipher.doFinal(ctr),0,state,0,16); + } + + /** + * inkrementiert den counter + */ + private void incrementCtr(){ + for(int i = 0; i<16; i++){ + //falls das Byte die volle Länge erreicht hat findet ein Übertrag statt + if(ctr[i]==0xff){ + ctr[i]=0x00; + } + else{ + //falls das Byte nicht die volle Länge hat endet die Inkrementierung + ctr[i]++; + return; + } + } + } +} diff --git a/src/tech/loedige/KeyStreamGenerator_ChaCha20.java b/src/tech/loedige/KeyStreamGenerator_ChaCha20.java new file mode 100644 index 0000000..ef79921 --- /dev/null +++ b/src/tech/loedige/KeyStreamGenerator_ChaCha20.java @@ -0,0 +1,135 @@ +package tech.loedige; + +public class KeyStreamGenerator_ChaCha20 extends SynchronousKeyStreamGenerator { + // Zustand des Schlüsselstromgenerators + // definiert durch (s0, s, c) + private final int[] s0 = new int[16]; + private final int[] s = new int[16]; + private long c; + /** + * Initialisierung des Schlüsselstromgenerators (Funktion s_0) + * + * @param key Schlüssel zu Initialisierung des + * Schlüsselstromgenerators (Bytearray der Länge 32) + * @param nonce Nonce-Wert zu Initialisierung des + * Schlüsselstromgenerators (Bytearray der Länge 12) + */ + public void initState(byte[] key, byte[] nonce) { + initState(key, nonce, 0); + } + /** + * Initialisierung des Schlüsselstromgenerators (Funktion s_0 mit zusätzlicher Initialisierung der + * Zählervariablen in der ersten Komponente der Zustandsvariablen s0[12]) + * @param key Schlüssel zu Initialisierung des + * Schlüsselstromgenerators (Bytearray der Länge 32) + * @param nonce Nonce-Wert zu Initialisierung des + * Schlüsselstromgenerators (Bytearray der Länge 12) + * @param blockCtr Initialwert des Zählerwerts in s0[12] + */ + public void initState(byte[] key, byte[] nonce, int blockCtr) { + if ((key.length != 32) || (nonce.length != 12)) { + throw new IllegalArgumentException("Invalid length of key or nonce!"); + } + s0[0] = 0x61707865; + s0[1] = 0x3320646e; + s0[2] = 0x79622d32; + s0[3] = 0x6b206574; + // Transformation der Schlüsselbytes in int-Werte + // s0[4},...,s0[11] (Die Bytes werden in ’little-endian order’ eingelesen.) + for (int i = 0; i < 8; ++i) { + s0[i + 4] = (0xff & key[4 * i]); + s0[i + 4] |= (0xff & key[4 * i + 1]) << 8; + s0[i + 4] |= (0xff & key[4 * i + 2]) << 16; + s0[i + 4] |= (0xff & key[4 * i + 3]) << 24; + } + s0[12] = blockCtr; + + // Transformation der Nonce-Bytes in int-Werte + // s0[13},s0[14],s0[15] + for (int i = 0; i < 3; ++i) { + s0[i + 13] = (0xff & nonce[4 * i]); + s0[i + 13] |= (0xff & nonce[4 * i + 1]) << 8; + s0[i + 13] |= (0xff & nonce[4 * i + 2]) << 16; + s0[i + 13] |= (0xff & nonce[4 * i + 3]) << 24; + } + c = 0; + + // Aufruf von updateStateBlocks() (entspricht der + // Funktion s) wird durch Aufruf von + // getNextKeyStreamByte() (entspricht der Funktion S) + // angestossen. + } + + + /** + * Berechnung des nächsten Schlüsselstrombytes. + * (Entspricht eines einmaligen Aufrufs der Funktionen s + * und S.) + * + * @return Nächstes Schlüsselstrombyte + */ + @Override + public byte getNextKeyStreamByte() { + if ((c & 0x3f) == 0) { // (c mod 64) == 0 + if (c == 0x4000000000L) { // 2^38 + throw new RuntimeException("Keystream exhausted!"); + } + updateStateBlocks(); + } + int stateWord = s[(int) ((c >> 2) & 0x0f)]; + byte keyStreamByte= (byte) (stateWord >> (int) 8 * (c & 0x03)); + ++c; + return keyStreamByte; + } + + /** + * Update (Funktion s) der Block-Komponenten des Zustands100 + * (für (c mod 64) == 0) + */ + private void updateStateBlocks() { + System.arraycopy(s0, 0, s, 0, 16); + // 10-fache Anwendung der Inner-Block_Funktion f_{ib} + for (int i = 0; i < 10; ++i) { + quaterround(0, 4, 8, 12); + quaterround(1, 5, 9, 13); + quaterround(2, 6, 10, 14); + quaterround(3, 7, 11, 15); + quaterround(0, 5, 10, 15); + quaterround(1, 6, 11, 12); + quaterround(2, 7, 8, 13); + quaterround(3, 4, 9, 14); + } + for (int i = 0; i < 16; ++i) { + s[i] += s0[i]; + } + s0[12] += 1; // Inkrementierung des Block-Zählers + } + + /** + * Quater-Round-Funktion (Funktion q) + */ + private void quaterround(int i1, int i2, int i3, int i4) { + int a = s[i1]; + int b = s[i2]; + int c = s[i3]; + int d = s[i4]; + a += b; + d ^= a; + d = (d << 16) | (d >>> 16); + c += d; + b ^= c; + b = (b << 12) | (b >>> 20); + a += b; + d ^= a; + d = (d << 8) | (d >>> 24); + c += d; + b ^= c; + b = (b << 7) | (b >>> 25); + s[i1] = a; + s[i2] = b; + s[i3] = c; + s[i4] = d; + } + + } + diff --git a/src/tech/loedige/Main.java b/src/tech/loedige/Main.java new file mode 100644 index 0000000..d4f44b5 --- /dev/null +++ b/src/tech/loedige/Main.java @@ -0,0 +1,33 @@ +package tech.loedige; + +import th_owl.hs.datensicherheit.util.Dump; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class Main { + + public static void main(String[] args) + throws Exception { + byte[] key = Dump.hexString2byteArray("0102030405060708090A0B0C0D0E0F10"); + SecretKey secretKey = new SecretKeySpec(key, "AES"); + Cipher cipher= Cipher.getInstance("AES/CTR/NOPADDING"); + byte[] ctr = Dump.hexString2byteArray("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE"); + IvParameterSpec iv = new IvParameterSpec(ctr); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); + byte[] m = new byte[35]; + byte[] c = cipher.doFinal(m); + System.out.println("AES-CTR-Verschlüsselung mit "+ + "Cipher-Instanz vom Typ AES/CTR/NOPADDING:"); + System.out.println(Dump.dump(c)); + System.out.println(); + KeyStreamGenerator_AES_CTR ksg= new KeyStreamGenerator_AES_CTR(); + ksg.initState(key, ctr); + AdditiveStreamCipher.encrypt(ksg, m); + System.out.println("AES-CTR-Verschlüsselung mit "+ "KeyStreamGenerator_AES_CTR-Implementierung:"); + System.out.println(Dump.dump(m)); + System.out.println(); + } +} diff --git a/src/tech/loedige/SynchronousKeyStreamGenerator.java b/src/tech/loedige/SynchronousKeyStreamGenerator.java new file mode 100644 index 0000000..3b2b1a4 --- /dev/null +++ b/src/tech/loedige/SynchronousKeyStreamGenerator.java @@ -0,0 +1,35 @@ +package tech.loedige; + +public abstract class SynchronousKeyStreamGenerator extends KeyStreamGenerator{ + + @Override + final byte getNextKeyStreamByte(byte mByte){ + return getNextKeyStreamByte(); + } + + /** + * Berechnung des nächsten Schlüsselstrombytes. + * (Entspricht eines einmaligen Aufrufs der + * Update-Funktion s und der Extraktions-Funktion S.) + * + * @return Nächstes Schlüsselstrombyte15 + */ + abstract byte getNextKeyStreamByte(); + /** + * Generierung einer vorgegebenen Anzahl weiterer + * Schlüsselstrombytes. (Entspricht einer entsprechenden + * Anzahl von Aufrufen der Funktionen s und S.) + * + * @param noOfBytes Anzahl der zu generierenden + * Schlüsselstrombytes + * @return Die nächsten noOfBytes Bytes des + * Schlüsselstroms + */ + public byte[] getNextKeyStreamBytes(int noOfBytes) { + byte[] keyStream = new byte[noOfBytes]; + for (int i = 0; i < noOfBytes; ++i) { + keyStream[i] = getNextKeyStreamByte(); + } + return keyStream; + } +} diff --git a/src/th_owl/hs/datensicherheit/util/Dump.java b/src/th_owl/hs/datensicherheit/util/Dump.java new file mode 100644 index 0000000..40b1ac1 --- /dev/null +++ b/src/th_owl/hs/datensicherheit/util/Dump.java @@ -0,0 +1,215 @@ +/* + * Stefan Heiss + * TH Ostwestfalen-Lippe + * FB Elektrotechnik und Technische Informatik + * Quellcode zur Lehrveranstaltung Datensicherheit + */ +package th_owl.hs.datensicherheit.util; + +import java.math.BigInteger; +import java.util.Formatter; + +public class Dump { + + public final static String NL + = System.getProperty("line.separator", "\r\n"); + + public static byte[] hexString2byteArray( + String hexString) { + // remove all whitespaces + hexString = hexString.replaceAll("\\s", ""); + hexString = hexString.replaceAll(":", ""); + + if ((hexString.length() & 0x01) != 0) { + throw new IllegalHexDumpException( + "Odd number of nibbles!"); + } + int byteArrayLength = hexString.length() >> 1; + byte[] ba = new byte[byteArrayLength]; + for (int i = 0; i < byteArrayLength; ++i) { + try { + ba[i] + = (byte) Integer.parseInt( + hexString.substring(2 * i, 2 * i + 2), 16); + } catch (NumberFormatException nfe) { + throw new IllegalHexDumpException( + "Invalid characters " + + hexString.substring(2 * i, 2 * i + 2) + + " at position " + 2 * i + + " (of streamlined string)!"); + } + } + return ba; + } + + // ------------------------------------------------------ + public static String dumpString(int i) { + String retString = Integer.toString(i, 16); + if ((retString.length() & 0x01) != 0) { + retString = "0" + retString; + } + + return retString.toUpperCase(); + } + + public static String dumpString(byte b) { + return dumpString(b & 0xff); + } + + public static String dumpString(byte[] data) { + return dumpString(data, 0, data.length); + } + + public static String dumpString( + byte[] data, int offset, int length) { + return dumpString(data, "", offset, length); + } + + public static String dumpString( + byte[] data, String interBytesString, + int offset, int length) { + if (offset < 0 || length < 0) { + throw new IllegalArgumentException( + "Values for offset and parameters must be " + + "non-negative!"); + } + if (data == null) { + if (offset > 0 || length > 0) { + throw new IllegalArgumentException( + "Specified range not available in data!"); + } + return ""; + } + if ((offset + length) > data.length) { + throw new IllegalArgumentException( + "Specified range not available in data!"); + } + + StringBuffer sb = new StringBuffer(length + * (2 + interBytesString.length())); + for (int i = offset; i < offset + length; ++i) { + if (i != 0) { + sb.append(interBytesString); + } + sb.append(dumpString(data[i])); + } + return new String(sb); + } + + // ------------------------------------------------------ + public static String dump(BigInteger b) { + byte[] data = b.toByteArray(); + int l = data.length; + if (l > 1 && data[0] == 0) { + System.arraycopy(data, 1, data, 0, --l); + } + return dump(data, l); + } + + public static String dump(byte[] data) { + return dump(data, data.length); + } + + public static String dump(byte[] data, int length) { + StringBuffer sb + = new StringBuffer(78 * ((length + 15) >> 4)); + char[] txt = new char[16]; + + int i = 0; + for (; i < length;) { + if ((i & 0x0f) == 0) { + sb.append(alignRight( + Integer.toHexString(i) + " ", 9, '0')); + } + + int temp = (0xff & data[i]); + sb.append(dumpString(temp)); + sb.append(" "); + + if (temp < 0x20 || temp > 0x7e) /// ??? + { + txt[i++ & 0x0f] = '.'; + } // if( temp == 0x0a || temp == 0x09 || temp == 0x0d ) /// ??? + // txt[i++ & 0x0f] = (char)0; + else { + txt[i++ & 0x0f] = (char) temp; + } + + if ((i & 0x0f) == 0) { + sb.append(" "); + sb.append(txt, 0, 16); + sb.append(NL); + } + } + + if (i == 0) // empty data + { + sb.append("000000 "); + } + + if ((i = (i & 0x0f)) != 0) { + sb.append(fillString(3 * (16 - i), ' ') + " "); + sb.append(txt, 0, i); + sb.append(NL); + } + + return new String(sb.toString().trim()); + } + + /** + * @return If str.length() < totalLength, a String of + * length totalLength is returned. (The original String + * extended by specified character from the left.) + */ + public static String alignRight( + String str, int totalLength, char fillChar) { + if (totalLength <= str.length()) { + return str; + } + return fillString(totalLength - str.length(), fillChar) + + str; + } + + /** + * @return If str.length() < totalLength, a String of + * length totalLength is returned. (The original String + * extended by space characters from the left.) + */ + public static String alignRight( + String str, int totalLength) { + return alignRight(str, totalLength, ' '); + } + + /** + * @return A String of repLength many repetitions of + * specified character. + */ + public static String fillString( + int spaceLength, char fillChar) { + if (spaceLength < 0) { + spaceLength = 0; + } + StringBuffer sb = new StringBuffer(spaceLength); + for (int i = 0; i < spaceLength; ++i) { + sb.append(fillChar); + } + return new String(sb); + } + + // ------------------------------------------------------ + public static String dumpIntArray(int[] array) { + int nosPerLine = 4; + StringBuffer sb = new StringBuffer(); + Formatter formatter = new Formatter(sb); + for (int i = 0; i < array.length; ++i) { + if (i != 0 && i % nosPerLine == 0) { + sb.append(NL); + } + formatter.format(" %08x", array[i]); + } + sb.append(NL); + return new String(sb); + } +} + + diff --git a/src/th_owl/hs/datensicherheit/util/IllegalHexDumpException.java b/src/th_owl/hs/datensicherheit/util/IllegalHexDumpException.java new file mode 100644 index 0000000..853b97f --- /dev/null +++ b/src/th_owl/hs/datensicherheit/util/IllegalHexDumpException.java @@ -0,0 +1,15 @@ +/* + * Stefan Heiss + * TH Ostwestfalen-Lippe + * FB Elektrotechnik und Technische Informatik + * Quellcode zur Lehrveranstaltung Datensicherheit + */ +package th_owl.hs.datensicherheit.util; + +public class IllegalHexDumpException + extends IllegalArgumentException { + + public IllegalHexDumpException(String s) { + super(s); + } +}