瀏覽代碼

Add new exercise Diffie Hellman (#1331)

* Add new exercise Diffie Hellman

* Add requested changes

* Add requested changes

* Add requested changes
Cristian Rivas Gómez 8 年之前
父節點
當前提交
3e9e592332

+ 12
- 0
config.json 查看文件

@@ -1119,6 +1119,18 @@
1119 1119
     {
1120 1120
       "core": false,
1121 1121
       "difficulty": 8,
1122
+      "slug": "diffie-hellman",
1123
+      "topics": [
1124
+        "algorithms",
1125
+        "integers",
1126
+        "transforming"
1127
+      ],
1128
+      "unlocked_by": "linked-list",
1129
+      "uuid": "9b191b2f-b1a4-4c0e-b911-36666bff614d"
1130
+    },
1131
+    {
1132
+      "core": false,
1133
+      "difficulty": 8,
1122 1134
       "slug": "simple-cipher",
1123 1135
       "topics": [
1124 1136
         "cryptography",

+ 3
- 0
exercises/diffie-hellman/.meta/hints.md 查看文件

@@ -0,0 +1,3 @@
1
+## Hints
2
+This exercise requires you to perform calculations on large numbers. To correctly represent large numbers, the
3
+[BigInteger](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html) class is used.

+ 24
- 0
exercises/diffie-hellman/.meta/src/reference/java/DiffieHellman.java 查看文件

@@ -0,0 +1,24 @@
1
+import java.math.BigInteger;
2
+import java.util.Random;
3
+
4
+class DiffieHellman {
5
+
6
+    private Random random = new Random();
7
+
8
+    BigInteger privateKey(BigInteger primeP) {
9
+        BigInteger privateKey;
10
+        do {
11
+            privateKey = new BigInteger(primeP.bitLength(), random);
12
+        } while (privateKey.compareTo(BigInteger.ZERO) == 0 || privateKey.compareTo(primeP) >= 0);
13
+        return privateKey;
14
+    }
15
+
16
+    BigInteger publicKey(BigInteger primeP, BigInteger primeG, BigInteger privateKey) {
17
+        return primeG.modPow(privateKey, primeP);
18
+    }
19
+
20
+    BigInteger secret(BigInteger primeP, BigInteger publicKey, BigInteger privateKey) {
21
+        return publicKey.modPow(privateKey, primeP);
22
+    }
23
+
24
+}

+ 63
- 0
exercises/diffie-hellman/README.md 查看文件

@@ -0,0 +1,63 @@
1
+# Diffie Hellman
2
+
3
+Diffie-Hellman key exchange.
4
+
5
+Alice and Bob use Diffie-Hellman key exchange to share secrets.  They
6
+start with prime numbers, pick private keys, generate and share public
7
+keys, and then generate a shared secret key.
8
+
9
+## Step 0
10
+
11
+The test program supplies prime numbers p and g.
12
+
13
+## Step 1
14
+
15
+Alice picks a private key, a, greater than 1 and less than p.  Bob does
16
+the same to pick a private key b.
17
+
18
+## Step 2
19
+
20
+Alice calculates a public key A.
21
+
22
+    A = g**a mod p
23
+
24
+Using the same p and g, Bob similarly calculates a public key B from his
25
+private key b.
26
+
27
+## Step 3
28
+
29
+Alice and Bob exchange public keys.  Alice calculates secret key s.
30
+
31
+    s = B**a mod p
32
+
33
+Bob calculates
34
+
35
+    s = A**b mod p
36
+
37
+The calculations produce the same result!  Alice and Bob now share
38
+secret s.
39
+
40
+# Java Tips
41
+
42
+## Hints
43
+This exercise requires you to perform calculations on large numbers. To correctly represent large numbers, the
44
+[BigInteger](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html) class is used.
45
+
46
+
47
+# Running the tests
48
+
49
+You can run all the tests for an exercise by entering
50
+
51
+```sh
52
+$ gradle test
53
+```
54
+
55
+in your terminal.
56
+
57
+## Source
58
+
59
+Wikipedia, 1024 bit key from www.cryptopp.com/wiki. [http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange](http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange)
60
+
61
+## Submitting Incomplete Solutions
62
+
63
+It's possible to submit an incomplete solution so you can see how others have completed the exercise.

+ 19
- 0
exercises/diffie-hellman/build.gradle 查看文件

@@ -0,0 +1,19 @@
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.12"
11
+}
12
+
13
+test {
14
+  testLogging {
15
+    exceptionFormat = 'full'
16
+    events = ["passed", "failed", "skipped"]
17
+  }
18
+}
19
+

+ 0
- 0
exercises/diffie-hellman/src/main/java/.keep 查看文件


+ 98
- 0
exercises/diffie-hellman/src/test/java/DiffieHellmanTest.java 查看文件

@@ -0,0 +1,98 @@
1
+import org.junit.Before;
2
+import org.junit.Ignore;
3
+import org.junit.Test;
4
+
5
+import static org.junit.Assert.assertNotEquals;
6
+import static org.junit.Assert.assertTrue;
7
+import static org.junit.Assert.assertEquals;
8
+
9
+import java.math.BigInteger;
10
+import java.util.*;
11
+
12
+public class DiffieHellmanTest {
13
+
14
+    private DiffieHellman diffieHellman;
15
+
16
+    @Before
17
+    public void setUp() {
18
+        diffieHellman = new DiffieHellman();
19
+    }
20
+
21
+    @Test
22
+    public void testPrivateKeyInRange() {
23
+        BigInteger prime = BigInteger.valueOf(23);
24
+        List<BigInteger> privateKeys = new ArrayList<>();
25
+        for (int i = 0; i < 10; i++) {
26
+            privateKeys.add(diffieHellman.privateKey(prime));
27
+        }
28
+
29
+        for (BigInteger privateKey : privateKeys) {
30
+            assertTrue(privateKey.compareTo(BigInteger.ONE) >= 0);
31
+            assertTrue(privateKey.compareTo(prime) < 0);
32
+        }
33
+    }
34
+
35
+    // Note: due to the nature of randomness, there is always a chance that this test fails
36
+    // Be sure to check the actual generated values
37
+    @Ignore("Remove to run test")
38
+    @Test
39
+    public void testPrivateKeyRandomlyGenerated() {
40
+        BigInteger prime = BigInteger.valueOf(7919);
41
+        BigInteger privateKeyA = diffieHellman.privateKey(prime);
42
+        BigInteger privateKeyB = diffieHellman.privateKey(prime);
43
+
44
+        assertNotEquals(privateKeyA, privateKeyB);
45
+    }
46
+
47
+    @Ignore("Remove to run test")
48
+    @Test
49
+    public void testPublicKeyCorrectlyCalculated() {
50
+        BigInteger primeA = BigInteger.valueOf(23);
51
+        BigInteger primeB = BigInteger.valueOf(5);
52
+        BigInteger privateKey = BigInteger.valueOf(6);
53
+        BigInteger expected = BigInteger.valueOf(8);
54
+
55
+        assertEquals(expected, diffieHellman.publicKey(primeA, primeB, privateKey));
56
+    }
57
+
58
+    @Ignore("Remove to run test")
59
+    @Test
60
+    public void testSecretKeyCorrectlyCalculated() {
61
+        BigInteger prime = BigInteger.valueOf(23);
62
+        BigInteger publicKey = BigInteger.valueOf(19);
63
+        BigInteger privateKey = BigInteger.valueOf(6);
64
+        BigInteger expected = BigInteger.valueOf(2);
65
+
66
+        assertEquals(expected, diffieHellman.secret(prime, publicKey, privateKey));
67
+    }
68
+
69
+    @Ignore("Remove to run test")
70
+    @Test
71
+    public void testSecretKeyCorrectlyCalculatedWhenUsingLargePrimes() {
72
+        BigInteger prime = new BigInteger("120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543");
73
+        BigInteger publicKey = new BigInteger("75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188");
74
+        BigInteger privateKey = new BigInteger("2483479393625932939911081304356888505153797135447327501792696199190469015215177630758617902200417377685436170904594686456961202706692908603181062371925882");
75
+        BigInteger expected = new BigInteger("70900735223964890815905879227737819348808518698920446491346508980461201746567735331455825644429877946556431095820785835497384849778344216981228226252639932672153547963980483673419756271345828771971984887453014488572245819864454136618980914729839523581263886740821363010486083940557620831348661126601106717071");
76
+
77
+        assertEquals(expected, diffieHellman.secret(prime, publicKey, privateKey));
78
+    }
79
+
80
+    @Ignore("Remove to run test")
81
+    @Test
82
+    public void testExchange() {
83
+        BigInteger primeA = BigInteger.valueOf(23);
84
+        BigInteger primeB = BigInteger.valueOf(5);
85
+
86
+        BigInteger privateKeyA = diffieHellman.privateKey(primeA);
87
+        BigInteger privateKeyB = diffieHellman.privateKey(primeB);
88
+
89
+        BigInteger publicKeyA = diffieHellman.publicKey(primeA, primeB, privateKeyA);
90
+        BigInteger publicKeyB = diffieHellman.publicKey(primeA, primeB, privateKeyB);
91
+
92
+        BigInteger secretA = diffieHellman.secret(primeA, publicKeyB, privateKeyA);
93
+        BigInteger secretB = diffieHellman.secret(primeA, publicKeyA, privateKeyB);
94
+
95
+        assertEquals(secretA, secretB);
96
+    }
97
+
98
+}

+ 1
- 0
exercises/settings.gradle 查看文件

@@ -24,6 +24,7 @@ include 'crypto-square'
24 24
 include 'custom-set'
25 25
 include 'diamond'
26 26
 include 'difference-of-squares'
27
+include 'diffie-hellman'
27 28
 include 'etl'
28 29
 include 'flatten-array'
29 30
 include 'food-chain'