更新的答案
我仍然不是密码学专家,所以在做这个过程中我学到了很多,非常感谢!
我已经重写了逻辑,下面的整个示例已发布,供以后遇到此问题的任何人参考。它还在Compile Java的沙盒中进行了测试。
我将尝试解释这里发生的事情,但如果有人注意到我的实现/解释中存在明显缺陷,请告诉我。我不能说我完全理解了它或Java所使用的API,因此非常希望得到任何澄清。
解释
这使用了一些聪明的数学技巧,其中大部分由底层API处理,我们只需要按照正确的顺序和正确的值告诉它该做什么。
选择生成器g和模数p,并在所有参与者之间共享。
Alice、Bob、Carol和Sara选择私钥(A、B、C和S)并计算其公钥(gA,gB,gC,gS)。这些是从g的私钥幂模p计算出来的。
每个参与者都需要将其操作结果发送给下一个参与者,并且每个参与者都需要使用从另一个参与者传递过来的值执行n-1次操作,其中n是参与者的数量。
在此过程结束时,每个参与者都将通过使用进程和传递方法,将g提高到每个其他人的私钥幂模p而无需向彼此透露其私钥。
在第一轮中,每个参与者通过将其公钥提高到左侧参与者的公钥幂模p,计算出中间值(gAB,gBC等)。
在第2+次通过中,他们重复此过程,但是使用来自其左侧的人的上一次操作结果,将该结果提高到其自己的私钥幂模p。
这种传递和计算过程重复进行,直到每个人都计算出了gABCS,它变成了共享的秘密。
由于数学的工作方式(如果我没有弄错,则是指数法则),gABCS=gBCSA=gCSAB=gSABC等。
一个窃听者Eve可以看到
gA, gB, gC, gS, gAB, gBC, gCS, gSA, gABC, gBCS, gCSA 的值,但是她不能使用它们的任何组合来有效地重现
gABCS,因为她不知道
A,B,C或
S的值,这些是从未传输的私钥。
理论上,这种方法可以扩展到更多参与者。按照下面代码中的模式进行操作。您需要添加另一个参与者,在每次传递中将其添加到操作列表中,并添加一次操作以确保每个人都执行所需的操作数量。
下面添加了关于四个和五个参与者的示例代码。
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
public class DHKeyAgreement4 {
private DHKeyAgreement4() {}
public static void main(String argv[]) throws Exception {
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(2048);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
DHParameterSpec dhParamShared = ((DHPublicKey)aliceKpair.getPublic()).getParams();
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamShared);
KeyPair bobKpair = bobKpairGen.generateKeyPair();
KeyPairGenerator carolKpairGen = KeyPairGenerator.getInstance("DH");
carolKpairGen.initialize(dhParamShared);
KeyPair carolKpair = carolKpairGen.generateKeyPair();
KeyPairGenerator saraKpairGen = KeyPairGenerator.getInstance("DH");
saraKpairGen.initialize(dhParamShared);
KeyPair saraKpair = saraKpairGen.generateKeyPair();
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKpair.getPrivate());
KeyAgreement carolKeyAgree = KeyAgreement.getInstance("DH");
carolKeyAgree.init(carolKpair.getPrivate());
KeyAgreement saraKeyAgree = KeyAgreement.getInstance("DH");
saraKeyAgree.init(saraKpair.getPrivate());
Key gSA = aliceKeyAgree.doPhase(saraKpair.getPublic(), false);
Key gAB = bobKeyAgree.doPhase(aliceKpair.getPublic(), false);
Key gBC = carolKeyAgree.doPhase(bobKpair.getPublic(), false);
Key gCS = saraKeyAgree.doPhase(carolKpair.getPublic(), false);
Key gCSA = aliceKeyAgree.doPhase(gCS, false);
Key gSAB = bobKeyAgree.doPhase(gSA, false);
Key gABC = carolKeyAgree.doPhase(gAB, false);
Key gBCS = saraKeyAgree.doPhase(gBC, false);
Key gBCSA = aliceKeyAgree.doPhase(gBCS, true);
Key gCSAB = bobKeyAgree.doPhase(gCSA, true);
Key gABCS = saraKeyAgree.doPhase(gABC, true);
Key gSABC = carolKeyAgree.doPhase(gSAB, true);
byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
System.out.println("Alice secret: " + toHexString(aliceSharedSecret));
byte[] bobSharedSecret = bobKeyAgree.generateSecret();
System.out.println("Bob secret: " + toHexString(bobSharedSecret));
byte[] carolSharedSecret = carolKeyAgree.generateSecret();
System.out.println("Carol secret: " + toHexString(carolSharedSecret));
byte[] saraSharedSecret = saraKeyAgree.generateSecret();
System.out.println("Sara secret: " + toHexString(saraSharedSecret));
if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret))
System.out.println("Alice and Bob differ");
else
System.out.println("Alice and Bob are the same");
if (!java.util.Arrays.equals(bobSharedSecret, carolSharedSecret))
System.out.println("Bob and Carol differ");
else
System.out.println("Bob and Carol are the same");
if (!java.util.Arrays.equals(carolSharedSecret, saraSharedSecret))
System.out.println("Carol and Sara differ");
else
System.out.println("Carol and Sara are the same");
}
private static void byte2hex(byte b, StringBuffer buf) {
char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
int high = ((b & 0xf0) >> 4);
int low = (b & 0x0f);
buf.append(hexChars[high]);
buf.append(hexChars[low]);
}
private static String toHexString(byte[] block) {
StringBuffer buf = new StringBuffer();
int len = block.length;
for (int i = 0; i < len; i++) {
byte2hex(block[i], buf);
if (i < len-1) {
buf.append(":");
}
}
return buf.toString();
}
}
五人参与的示例
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
public class DHKeyAgreement5 {
private DHKeyAgreement5() {}
public static void main(String argv[]) throws Exception {
KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
aliceKpairGen.initialize(2048);
KeyPair aliceKpair = aliceKpairGen.generateKeyPair();
DHParameterSpec dhParamShared = ((DHPublicKey)aliceKpair.getPublic()).getParams();
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamShared);
KeyPair bobKpair = bobKpairGen.generateKeyPair();
KeyPairGenerator carolKpairGen = KeyPairGenerator.getInstance("DH");
carolKpairGen.initialize(dhParamShared);
KeyPair carolKpair = carolKpairGen.generateKeyPair();
KeyPairGenerator saraKpairGen = KeyPairGenerator.getInstance("DH");
saraKpairGen.initialize(dhParamShared);
KeyPair saraKpair = saraKpairGen.generateKeyPair();
KeyPairGenerator daveKpairGen = KeyPairGenerator.getInstance("DH");
daveKpairGen.initialize(dhParamShared);
KeyPair daveKpair = daveKpairGen.generateKeyPair();
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKpair.getPrivate());
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKpair.getPrivate());
KeyAgreement carolKeyAgree = KeyAgreement.getInstance("DH");
carolKeyAgree.init(carolKpair.getPrivate());
KeyAgreement saraKeyAgree = KeyAgreement.getInstance("DH");
saraKeyAgree.init(saraKpair.getPrivate());
KeyAgreement daveKeyAgree = KeyAgreement.getInstance("DH");
daveKeyAgree.init(daveKpair.getPrivate());
Key gDA = aliceKeyAgree.doPhase(daveKpair.getPublic(), false);
Key gAB = bobKeyAgree.doPhase(aliceKpair.getPublic(), false);
Key gBC = carolKeyAgree.doPhase(bobKpair.getPublic(), false);
Key gCS = saraKeyAgree.doPhase(carolKpair.getPublic(), false);
Key gSD = daveKeyAgree.doPhase(saraKpair.getPublic(), false);
Key gSDA = aliceKeyAgree.doPhase(gSD, false);
Key gDAB = bobKeyAgree.doPhase(gDA, false);
Key gABC = carolKeyAgree.doPhase(gAB, false);
Key gBCS = saraKeyAgree.doPhase(gBC, false);
Key gCSD = daveKeyAgree.doPhase(gCS, false);
Key gCSDA = aliceKeyAgree.doPhase(gCSD, false);
Key gSDAB = bobKeyAgree.doPhase(gSDA, false);
Key gDABC = carolKeyAgree.doPhase(gDAB, false);
Key gABCS = saraKeyAgree.doPhase(gABC, false);
Key gBCSD = daveKeyAgree.doPhase(gBCS, false);
Key gBCSDA = aliceKeyAgree.doPhase(gBCSD, true);
Key gCSDAB = bobKeyAgree.doPhase(gCSDA, true);
Key gSDABC = carolKeyAgree.doPhase(gSDAB, true);
Key gDABCS = saraKeyAgree.doPhase(gDABC, true);
Key gABCSD = daveKeyAgree.doPhase(gABCS, true);
byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
System.out.println("Alice secret: " + toHexString(aliceSharedSecret));
byte[] bobSharedSecret = bobKeyAgree.generateSecret();
System.out.println("Bob secret: " + toHexString(bobSharedSecret));
byte[] carolSharedSecret = carolKeyAgree.generateSecret();
System.out.println("Carol secret: " + toHexString(carolSharedSecret));
byte[] saraSharedSecret = saraKeyAgree.generateSecret();
System.out.println("Sara secret: " + toHexString(saraSharedSecret));
byte[] daveSharedSecret = daveKeyAgree.generateSecret();
System.out.println("Dave secret: " + toHexString(daveSharedSecret));
if (!java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret))
System.out.println("Alice and Bob differ");
else
System.out.println("Alice and Bob are the same");
if (!java.util.Arrays.equals(bobSharedSecret, carolSharedSecret))
System.out.println("Bob and Carol differ");
else
System.out.println("Bob and Carol are the same");
if (!java.util.Arrays.equals(carolSharedSecret, saraSharedSecret))
System.out.println("Carol and Sara differ");
else
System.out.println("Carol and Sara are the same");
if (!java.util.Arrays.equals(saraSharedSecret, daveSharedSecret))
System.out.println("Sara and Dave differ");
else
System.out.println("Sara and Dave are the same");
}
private static void byte2hex(byte b, StringBuffer buf) {
char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
int high = ((b & 0xf0) >> 4);
int low = (b & 0x0f);
buf.append(hexChars[high]);
buf.append(hexChars[low]);
}
private static String toHexString(byte[] block) {
StringBuffer buf = new StringBuffer();
int len = block.length;
for (int i = 0; i < len; i++) {
byte2hex(block[i], buf);
if (i < len-1) {
buf.append(":");
}
}
return buf.toString();
}
}