Selaa lähdekoodia

Merge branch 'simple-cipher'

Piet van Dongen 11 vuotta sitten
vanhempi
commit
a8486cb720

+ 1
- 0
config.json Näytä tiedosto

@@ -30,6 +30,7 @@
30 30
     "trinary",
31 31
     "rna-transcription",
32 32
     "sieve",
33
+    "simple-cipher",
33 34
     "pascals-triangle"	
34 35
   ],
35 36
   "deprecated": [

+ 11
- 0
simple-cipher/build.gradle Näytä tiedosto

@@ -0,0 +1,11 @@
1
+apply plugin: "java"
2
+apply plugin: "eclipse"
3
+apply plugin: "idea"
4
+
5
+repositories {
6
+  mavenCentral()
7
+}
8
+
9
+dependencies {
10
+  testCompile "junit:junit:4.10"
11
+}

+ 73
- 0
simple-cipher/example.java Näytä tiedosto

@@ -0,0 +1,73 @@
1
+import java.util.Random;
2
+import java.util.stream.IntStream;
3
+
4
+public class Cipher {
5
+
6
+    private static final String ALPHABET = "abcdefghijklmnopqrstuvwxyz";
7
+    private static final Random random = new Random();
8
+
9
+    public String key;
10
+
11
+    public Cipher() {
12
+        this.key = IntStream.range(0, 100)
13
+                .map(x -> ALPHABET.toCharArray()[random.nextInt(ALPHABET.length())])
14
+                .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
15
+                .toString();
16
+    }
17
+
18
+    public Cipher(String key) {
19
+        if (!isValidKey(key)) {
20
+            throw new IllegalArgumentException("Invalid key");
21
+        }
22
+
23
+        this.key = key;
24
+    }
25
+
26
+    private static boolean isValidKey(String key) {
27
+        return key.matches("^[a-z]+$");
28
+    }
29
+
30
+    public String getKey() {
31
+        return key;
32
+    }
33
+
34
+    public String encode(String plainText) {
35
+        StringBuilder ciphertext = new StringBuilder(plainText.length());
36
+
37
+        for (int index = 0; index < Math.min(plainText.length(), key.length()); index++) {
38
+            ciphertext.append(encodeCharacter(plainText, index));
39
+        }
40
+
41
+        return ciphertext.toString();
42
+    }
43
+
44
+    private char encodeCharacter(String plainText, int index) {
45
+        int alphabetIdx = ALPHABET.indexOf(plainText.toCharArray()[index]) + ALPHABET.indexOf(key.toCharArray()[index]);
46
+
47
+        if (alphabetIdx >= ALPHABET.length()) {
48
+            alphabetIdx -= ALPHABET.length();
49
+        }
50
+
51
+        return ALPHABET.toCharArray()[alphabetIdx];
52
+    }
53
+
54
+    public String decode(String cipherText) {
55
+        StringBuilder plainText = new StringBuilder(cipherText.length());
56
+
57
+        for (int i = 0; i < cipherText.length(); i++) {
58
+            plainText.append(decodeCharacter(cipherText, i));
59
+        }
60
+
61
+        return plainText.toString();
62
+    }
63
+
64
+    private char decodeCharacter(String cipherText, int index) {
65
+        int alphabetIdx = ALPHABET.indexOf(cipherText.toCharArray()[index]) - ALPHABET.indexOf(key.toCharArray()[index]);
66
+
67
+        if (alphabetIdx < 0) {
68
+            alphabetIdx += ALPHABET.length();
69
+        }
70
+
71
+        return ALPHABET.toCharArray()[alphabetIdx];
72
+    }
73
+}

+ 0
- 0
simple-cipher/src/main/java/.keep Näytä tiedosto


+ 2
- 0
simple-cipher/src/main/java/Cipher.java Näytä tiedosto

@@ -0,0 +1,2 @@
1
+public class Cipher {
2
+}

+ 29
- 0
simple-cipher/src/test/java/IncorrectKeyCipherTest.java Näytä tiedosto

@@ -0,0 +1,29 @@
1
+import org.junit.Test;
2
+
3
+public class IncorrectKeyCipherTest {
4
+
5
+    @Test(expected = IllegalArgumentException.class)
6
+    public void cipherThrowsWithAllCapsKey() {
7
+        new Cipher("ABCDEF");
8
+    }
9
+
10
+    @Test(expected = IllegalArgumentException.class)
11
+    public void cipherThrowsWithAnyCapsKey() {
12
+        new Cipher("abcdEFg");
13
+    }
14
+
15
+    @Test(expected = IllegalArgumentException.class)
16
+    public void cipherThrowsWithNumericKey() {
17
+        new Cipher("12345");
18
+    }
19
+
20
+    @Test(expected = IllegalArgumentException.class)
21
+    public void cipherThrowsWithAnyNumericKey() {
22
+        new Cipher("abcd345ef");
23
+    }
24
+
25
+    @Test(expected = IllegalArgumentException.class)
26
+    public void cipherThrowsWithEmptyKey() {
27
+        new Cipher("");
28
+    }
29
+}

+ 55
- 0
simple-cipher/src/test/java/RandomKeyCipherTest.java Näytä tiedosto

@@ -0,0 +1,55 @@
1
+import org.junit.Before;
2
+import org.junit.Test;
3
+
4
+import static org.junit.Assert.assertEquals;
5
+import static org.junit.Assert.assertTrue;
6
+
7
+public class RandomKeyCipherTest {
8
+
9
+    private Cipher cipher;
10
+
11
+    @Before
12
+    public void setup() {
13
+        this.cipher = new Cipher();
14
+    }
15
+
16
+    @Test
17
+    public void cipherKeyIsMadeOfLetters() {
18
+        assertTrue(cipher.getKey().matches("[a-z]+"));
19
+    }
20
+
21
+    @Test
22
+    public void defaultCipherKeyIs100Characters() {
23
+        assertEquals(100, cipher.getKey().length());
24
+    }
25
+
26
+    @Test
27
+    public void cipherKeysAreRandomlyGenerated() {
28
+        assertTrue(!(new Cipher().getKey().equals(cipher.getKey().length())));
29
+    }
30
+
31
+    /**
32
+     * Here we take advantage of the fact that plaintext of "aaa..." doesn't output the key. This is a critical problem
33
+     * with shift ciphers, some characters will always output the key verbatim.
34
+     */
35
+    @Test
36
+    public void cipherCanEncode() {
37
+        String expectedOutput = cipher.getKey().substring(0, 10);
38
+
39
+        assertEquals(expectedOutput, cipher.encode("aaaaaaaaaa"));
40
+    }
41
+
42
+    @Test
43
+    public void cipherCanDecode() {
44
+        String expectedOutput = "aaaaaaaaaa";
45
+
46
+        assertEquals(expectedOutput, cipher.decode(cipher.getKey().substring(0, 10)));
47
+    }
48
+
49
+    @Test
50
+    public void cipherIsReversible() {
51
+        String plainText = "abcdefghij";
52
+
53
+        assertEquals(plainText, cipher.decode(cipher.encode(plainText)));
54
+    }
55
+}

+ 11
- 0
simple-cipher/src/test/java/SimpleCipherTest.java Näytä tiedosto

@@ -0,0 +1,11 @@
1
+import org.junit.runner.RunWith;
2
+import org.junit.runners.Suite;
3
+
4
+@RunWith(Suite.class)
5
+@Suite.SuiteClasses({
6
+        RandomKeyCipherTest.class,
7
+        IncorrectKeyCipherTest.class,
8
+        SubstitutionCipherTest.class
9
+})
10
+public class SimpleCipherTest {
11
+}

+ 70
- 0
simple-cipher/src/test/java/SubstitutionCipherTest.java Näytä tiedosto

@@ -0,0 +1,70 @@
1
+import org.junit.Before;
2
+import org.junit.Test;
3
+
4
+import static org.junit.Assert.assertEquals;
5
+
6
+public class SubstitutionCipherTest {
7
+
8
+    private static final String KEY = "abcdefghij";
9
+    private Cipher cipher;
10
+
11
+    @Before
12
+    public void setup() {
13
+        this.cipher = new Cipher(KEY);
14
+    }
15
+
16
+    @Test
17
+    public void cipherKeepsTheSubmittedKey() {
18
+        assertEquals(KEY, cipher.getKey());
19
+    }
20
+
21
+    @Test
22
+    public void cipherCanEncodeWithGivenKey() {
23
+        String expectedOutput = "abcdefghij";
24
+
25
+        assertEquals(expectedOutput, cipher.encode("aaaaaaaaaa"));
26
+    }
27
+
28
+    @Test
29
+    public void cipherCanDecodeWithGivenKey() {
30
+        String expectedOutput = "aaaaaaaaaa";
31
+
32
+        assertEquals(expectedOutput, cipher.decode("abcdefghij"));
33
+    }
34
+
35
+    @Test
36
+    public void cipherIsReversibleGivenKey() {
37
+        String plainText = "abcdefghij";
38
+
39
+        assertEquals(plainText, cipher.decode(cipher.encode("abcdefghij")));
40
+    }
41
+
42
+    @Test
43
+    public void cipherCanDoubleShiftEncode() {
44
+        String plainText = "iamapandabear";
45
+        String expectedOutput = "qayaeaagaciai";
46
+
47
+        assertEquals(expectedOutput, new Cipher(plainText).encode(plainText));
48
+    }
49
+
50
+    @Test
51
+    public void cipherCanWrapEncode() {
52
+        String expectedOutput = "zabcdefghi";
53
+
54
+        assertEquals(expectedOutput, cipher.encode("zzzzzzzzzz"));
55
+    }
56
+
57
+    @Test
58
+    public void cipherCanEncodeMessageThatIsShorterThanTheKey() {
59
+        String expectedOutput = "abcde";
60
+
61
+        assertEquals(expectedOutput, cipher.encode("aaaaa"));
62
+    }
63
+
64
+    @Test
65
+    public void cipherCanDecodeMessageThatIsShorterThanTheKey() {
66
+        String expectedOutput = "aaaaa";
67
+
68
+        assertEquals(expectedOutput, cipher.decode("abcde"));
69
+    }
70
+}