面试题答案
一键面试1. 密钥交换协议改进 - 使用 Diffie - Hellman 密钥交换
- 实现原理:Diffie - Hellman 密钥交换允许双方在不安全的通信信道上协商出一个共享密钥,而无需事先共享秘密信息。其基于离散对数问题的数学原理,攻击者很难从公开交换的信息中计算出共享密钥。
- 双方(例如 A 和 B)先商定两个公开参数:一个大素数
p
和一个p
的原根g
。 - A 选择一个秘密整数
a
,计算A = g^a mod p
并发送给 B。 - B 选择一个秘密整数
b
,计算B = g^b mod p
并发送给 A。 - A 计算共享密钥
K = B^a mod p
,B 计算共享密钥K = A^b mod p
,由于数学性质,二者计算出的K
相同。
- 双方(例如 A 和 B)先商定两个公开参数:一个大素数
- 关键代码片段:
import java.math.BigInteger;
import java.security.SecureRandom;
public class DiffieHellman {
private static final BigInteger ONE = BigInteger.ONE;
private static final SecureRandom random = new SecureRandom();
private BigInteger p; // 大素数
private BigInteger g; // 原根
private BigInteger privateKey;
private BigInteger publicKey;
public DiffieHellman(int bitLength) {
p = BigInteger.probablePrime(bitLength, random);
g = findGenerator(p);
privateKey = new BigInteger(bitLength, random);
publicKey = g.modPow(privateKey, p);
}
private BigInteger findGenerator(BigInteger p) {
BigInteger phi = p.subtract(ONE);
BigInteger fact = phi;
BigInteger a = BigInteger.TWO;
while (a.compareTo(phi) < 0) {
if (phi.gcd(a).equals(ONE)) {
boolean isGenerator = true;
for (BigInteger divisor : fact.divisors()) {
if (a.modPow(phi.divide(divisor), p).equals(ONE)) {
isGenerator = false;
break;
}
}
if (isGenerator) {
return a;
}
}
a = a.add(ONE);
}
return null;
}
public BigInteger calculateSharedKey(BigInteger otherPublicKey) {
return otherPublicKey.modPow(privateKey, p);
}
}
2. 数字签名的应用
- 实现原理:发送方使用自己的私钥对数据的哈希值进行加密,生成数字签名。接收方使用发送方的公钥对数字签名进行解密,得到哈希值,并对接收的数据重新计算哈希值,对比二者是否一致,以验证数据的完整性和发送方的身份。
- 发送方:
- 计算数据
data
的哈希值,例如使用 SHA - 256 算法:MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(data);
- 使用私钥对哈希值进行加密,例如使用 RSA 算法:
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] signature = cipher.doFinal(hash);
- 计算数据
- 接收方:
- 使用发送方的公钥对数字签名进行解密:
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] decryptedHash = cipher.doFinal(signature);
- 对接收的数据重新计算哈希值:
MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] receivedHash = digest.digest(receivedData);
- 对比解密后的哈希值和重新计算的哈希值是否一致。
- 使用发送方的公钥对数字签名进行解密:
- 发送方:
- 关键代码片段:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
public class DigitalSignatureExample {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String data = "Hello, World!";
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] signedData = signature.sign();
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(publicKey);
verifier.update(data.getBytes());
boolean isValid = verifier.verify(signedData);
System.out.println("Signature is valid: " + isValid);
}
}
3. 验证通信双方身份的完整性
- 实现原理:结合数字证书和认证机构(CA)。通信双方都从可信任的 CA 处获取数字证书,证书包含公钥及相关身份信息,并由 CA 使用其私钥进行签名。
- 发送方在通信时,将数字证书和数据一起发送给接收方。
- 接收方首先使用 CA 的公钥验证数字证书的签名,确认证书的真实性。如果证书有效,接收方可以从证书中获取发送方的公钥,用于后续的数字签名验证和密钥交换验证等操作。
- 关键代码片段:验证数字证书签名可以使用
java.security.cert.CertificateFactory
和java.security.cert.X509Certificate
等类,示例如下:
import java.io.FileInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class CertificateVerification {
public static void main(String[] args) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream in = new FileInputStream("sender_certificate.crt");
X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
// 假设已经有 CA 的公钥
cert.verify(caPublicKey);
System.out.println("Certificate is valid.");
}
}
在实际应用中,还需要考虑证书链的验证等更复杂的情况,以确保整个信任体系的完整性。通过上述密钥交换协议改进、数字签名应用以及身份验证机制,可以有效抵御中间人攻击对数据加密造成的威胁。