java.security包详解
摘要 Digest
摘要类图
摘要使用示例
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;public class MessageDigestExample {public static void main(String[] args) {String input = "Hello, World!";try {// 创建 MessageDigest 实例,指定算法为 SHA-256MessageDigest digest = MessageDigest.getInstance("SHA-256");// 将输入字符串转换为字节数组并传递给 digestbyte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));// 将字节数组转换为十六进制字符串StringBuilder hexString = new StringBuilder();for (byte b : hashBytes) {String hex = Integer.toHexString(0xff & b);if (hex.length() == 1) hexString.append('0');hexString.append(hex);}// 输出哈希值System.out.println("Input: " + input);System.out.println("SHA-256 Hash: " + hexString.toString());} catch (NoSuchAlgorithmException e) {e.printStackTrace();}}
}
密钥 Key
密钥类图
KeyGenerator使用示例
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class KeyGeneratorExample {public static void main(String[] args) {try {// 1. 获取 KeyGenerator 实例,指定算法为 AESKeyGenerator keyGen = KeyGenerator.getInstance("AES");// 2. 初始化 KeyGenerator,指定密钥长度(例如 128 位)keyGen.init(128); // 也可以是 192 或 256,取决于 JCE 支持// 3. 生成密钥SecretKey secretKey = keyGen.generateKey();// 4. 将密钥转换为字节数组byte[] keyBytes = secretKey.getEncoded();// 5. 将字节数组转换为 Base64 编码的字符串(便于显示和存储)String base64Key = Base64.getEncoder().encodeToString(keyBytes);// 输出生成的密钥System.out.println("Generated AES Key (Base64): " + base64Key);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}}
}
byte[]还原秘钥Key示例
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;public class SecretKeyRestoreExample {public static void main(String[] args) {try {// 1. 假设有一个字节数组形式的密钥(例如 AES 密钥)String keyBase64 = "3q2+7w=="; // Base64 编码的密钥byte[] keyBytes = Base64.getDecoder().decode(keyBase64);// 2. 使用 SecretKeySpec 将字节数组还原为 SecretKeySecretKey secretKey = new SecretKeySpec(keyBytes, "AES");// 3. 验证还原的密钥System.out.println("Restored SecretKey Algorithm: " + secretKey.getAlgorithm());System.out.println("Restored SecretKey Format: " + secretKey.getFormat());System.out.println("Restored SecretKey (Base64): " +Base64.getEncoder().encodeToString(secretKey.getEncoded()));} catch (Exception e) {e.printStackTrace();}}
}
加密算法参数 AlgorithmParameters
AlgorithmParameters
是 Java 中用于管理和传递加密算法参数的类。它提供加密算法参数的不透明表示。它通常与加密算法(如 AES、DES 等)一起使用,用于存储和传递算法的初始化参数(如 IV(初始化向量)、盐值等)。
不透明表示:不可以直接访问参数域
透明表示:可以通过某个“get”来分别访问每个值
加密算法参数与byte[]相互转换示例
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class AlgorithmParametersExample {public static void main(String[] args) {try {// 1. 生成 AES 密钥KeyGenerator keyGen = KeyGenerator.getInstance("AES");keyGen.init(128); // 128 位密钥SecretKey secretKey = keyGen.generateKey();// 2. 初始化 AES 加密器(使用 CBC 模式,需要 IV)Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, secretKey);// 3. 获取 AlgorithmParameters(包含 IV 等参数)AlgorithmParameters params = cipher.getParameters();// 4. 将 AlgorithmParameters 编码为字节数组(便于存储或传输)byte[] encodedParams = params.getEncoded();System.out.println("Encoded AlgorithmParameters (Base64): " +Base64.getEncoder().encodeToString(encodedParams));// 5. 解码 AlgorithmParametersAlgorithmParameters decodedParams = AlgorithmParameters.getInstance("AES");decodedParams.init(encodedParams);// 6. 从 AlgorithmParameters 中提取 IVIvParameterSpec ivSpec = decodedParams.getParameterSpec(IvParameterSpec.class);System.out.println("IV (Base64): " +Base64.getEncoder().encodeToString(ivSpec.getIV()));// 7. 使用解码后的参数初始化解密器Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);System.out.println("AlgorithmParameters usage completed successfully.");} catch (Exception e) {e.printStackTrace();}}
}
AlgorithmParameterGenerator 使用示例
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;public class DESAlgorithmParameterGeneratorExample {public static void main(String[] args) {try {// 1. 生成 DES 密钥KeyGenerator keyGen = KeyGenerator.getInstance("DES");SecretKey secretKey = keyGen.generateKey();// 2. 获取 AlgorithmParameterGenerator 实例,指定算法为 DESAlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DES");// 3. 初始化 AlgorithmParameterGenerator(可以指定密钥大小,但 DES 固定为 56 位)paramGen.init(56); // DES 的密钥大小固定为 56 位// 4. 生成 AlgorithmParametersAlgorithmParameters params = paramGen.generateParameters();// 5. 将 AlgorithmParameters 转换为 IvParameterSpec(获取 IV)IvParameterSpec ivSpec = params.getParameterSpec(IvParameterSpec.class);// 6. 输出生成的 IVSystem.out.println("Generated IV (Base64): " +Base64.getEncoder().encodeToString(ivSpec.getIV()));// 7. 使用密钥和 IV 初始化加密器Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);// 8. 加密数据String plainText = "Hello, DES!";byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());System.out.println("Encrypted Data (Base64): " +Base64.getEncoder().encodeToString(encryptedBytes));// 9. 使用相同的密钥和 IV 初始化解密器cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);// 10. 解密数据byte[] decryptedBytes = cipher.doFinal(encryptedBytes);String decryptedText = new String(decryptedBytes);System.out.println("Decrypted Text: " + decryptedText);} catch (Exception e) {e.printStackTrace();}}
}
密钥对KeyPair
KeyPairGenerator:用于生产新的秘钥对;
KeyFactory:用于转换秘钥数据为key对象
密钥对类图
KeyPairGenerator 使用示例
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class KeyPairGeneratorExample {public static void main(String[] args) {try {// 1. 获取 KeyPairGenerator 实例,指定算法为 RSAKeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");// 2. 初始化 KeyPairGenerator,指定密钥大小为 2048 位keyPairGen.initialize(2048);// 3. 生成密钥对KeyPair keyPair = keyPairGen.generateKeyPair();// 4. 获取公钥和私钥byte[] publicKeyBytes = keyPair.getPublic().getEncoded();byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();// 5. 将公钥和私钥转换为 Base64 编码的字符串(便于显示和存储)String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyBytes);String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKeyBytes);// 6. 输出公钥和私钥System.out.println("Generated RSA Key Pair:");System.out.println("Public Key (Base64): " + publicKeyBase64);System.out.println("Private Key (Base64): " + privateKeyBase64);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}}
}
KeyFactory 使用示例
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;public class KeyFactoryExample {public static void main(String[] args) {try {// 1. 生成 RSA 密钥对KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");keyPairGen.initialize(2048); // 2048 位密钥KeyPair keyPair = keyPairGen.generateKeyPair();// 2. 获取公钥和私钥的编码形式byte[] publicKeyBytes = keyPair.getPublic().getEncoded();byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();// 3. 将公钥和私钥编码为 Base64 字符串(便于显示和存储)String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKeyBytes);String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKeyBytes);System.out.println("Original Public Key (Base64): " + publicKeyBase64);System.out.println("Original Private Key (Base64): " + privateKeyBase64);// 4. 使用 KeyFactory 还原公钥KeyFactory keyFactory = KeyFactory.getInstance("RSA");// 还原公钥X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64));PublicKey restoredPublicKey = keyFactory.generatePublic(publicKeySpec);// 还原私钥PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBase64));PrivateKey restoredPrivateKey = keyFactory.generatePrivate(privateKeySpec);// 5. 验证还原的密钥System.out.println("Restored Public Key (Base64): " +Base64.getEncoder().encodeToString(restoredPublicKey.getEncoded()));System.out.println("Restored Private Key (Base64): " +Base64.getEncoder().encodeToString(restoredPrivateKey.getEncoded()));// 6. 检查还原的密钥是否与原始密钥一致boolean isPublicKeyEqual = keyPair.getPublic().equals(restoredPublicKey);boolean isPrivateKeyEqual = keyPair.getPrivate().equals(restoredPrivateKey);System.out.println("Is Public Key Restored Correctly? " + isPublicKeyEqual);System.out.println("Is Private Key Restored Correctly? " + isPrivateKeyEqual);} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {e.printStackTrace();}}
}
签名Signature
Signature 使用示例
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.security.SignatureException;public class SignatureDemo {public static void main(String[] args) {try {// 生成密钥对KeyPair keyPair = generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();// 要签名的数据String data = "Hello, World!";byte[] dataBytes = data.getBytes();// 生成签名byte[] signatureBytes = SignatureExample.signData(dataBytes, privateKey);System.out.println("Signature: " + new String(signatureBytes));// 验证签名boolean isValid = SignatureExample.verifySignature(dataBytes, signatureBytes, publicKey);System.out.println("Signature is valid: " + isValid);} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {e.printStackTrace();}}// 生成密钥对public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048); // 密钥大小为2048位return keyPairGenerator.generateKeyPair();}// 生成签名public static byte[] signData(byte[] data, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {Signature signature = Signature.getInstance("SHA256withRSA");signature.initSign(privateKey);signature.update(data);return signature.sign();}// 验证签名public static boolean verifySignature(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(publicKey);signature.update(data);return signature.verify(signatureBytes);}
}
时间戳Timestamp
创建Timestamp示例
import java.security.Timestamp;
import java.security.cert.CertPath;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;public class TimestampExample {public static void main(String[] args) throws Exception {// 1. 创建证书链List<X509Certificate> certList = new ArrayList<>();// 假设我们已经有一个 X.509 证书X509Certificate cert = getSampleCertificate(); // 获取示例证书certList.add(cert);// 2. 创建 CertPathCertificateFactory certFactory = CertificateFactory.getInstance("X.509");CertPath certPath = certFactory.generateCertPath(certList);// 3. 创建 TimestampDate timestampDate = new Date(); // 当前时间Timestamp timestamp = new Timestamp(timestampDate, certPath);// 4. 输出 Timestamp 信息System.out.println("Timestamp Date: " + timestamp.getTimestamp());System.out.println("Signer Cert Path: " + timestamp.getSignerCertPath());}// 模拟获取一个示例证书private static X509Certificate getSampleCertificate() throws Exception {// 这里可以使用 KeyPair 和自签名证书生成逻辑// 以下是一个占位符,实际应用中需要从文件或密钥库加载证书return null;}
}
验证Timestamp示例
import java.security.Timestamp;
import java.security.cert.CertPath;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;public class TimestampVerifier {public static void main(String[] args) throws Exception {// 1. 创建证书链List<X509Certificate> certList = new ArrayList<>();X509Certificate cert = getSampleCertificate(); // 获取示例证书certList.add(cert);// 2. 创建 CertPathCertificateFactory certFactory = CertificateFactory.getInstance("X.509");CertPath certPath = certFactory.generateCertPath(certList);// 3. 创建 TimestampDate timestampDate = new Date(); // 当前时间Timestamp timestamp = new Timestamp(timestampDate, certPath);// 4. 验证证书链boolean isCertValid = verifyCertPath(certPath);System.out.println("Certificate Chain is valid: " + isCertValid);// 5. 验证时间戳是否在证书的有效期内boolean isTimestampValid = verifyTimestamp(timestamp);System.out.println("Timestamp is valid: " + isTimestampValid);}// 验证证书链的有效性private static boolean verifyCertPath(CertPath certPath) {// 这里可以添加证书链验证逻辑// 例如,检查证书是否过期,是否由受信任的 CA 签发等return true; // 假设证书链有效}// 验证时间戳是否在证书的有效期内private static boolean verifyTimestamp(Timestamp timestamp) {Date timestampDate = timestamp.getTimestamp();CertPath certPath = timestamp.getSignerCertPath();X509Certificate signerCert = (X509Certificate) certPath.getCertificates().get(0);// 检查时间戳是否在证书的有效期内return timestampDate.after(signerCert.getNotBefore()) &×tampDate.before(signerCert.getNotAfter());}// 模拟获取一个示例证书private static X509Certificate getSampleCertificate() throws Exception {// 这里可以使用 KeyPair 和自签名证书生成逻辑// 以下是一个占位符,实际应用中需要从文件或密钥库加载证书return null;}
}
密钥库KeyStore
java.security.KeyStore
类用于管理密钥和证书。KeyStore
可以存储以下内容:
-
私钥(Private Key)
-
公钥证书(Public Key Certificate)
-
受信任的证书(Trusted Certificate)
创建 KeyStore 并存储密钥和证书示例
import java.io.FileOutputStream;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Date;
import javax.security.auth.x500.X500Principal;public class KeyStoreExample {public static void main(String[] args) throws Exception {// 1. 创建 KeyStoreKeyStore keyStore = KeyStore.getInstance("JKS"); // JKS 是 Java 默认的 KeyStore 类型keyStore.load(null, null); // 初始化一个空的 KeyStore// 2. 生成密钥对KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048); // 2048 位密钥KeyPair keyPair = keyPairGenerator.generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();// 3. 创建自签名证书X509Certificate certificate = generateSelfSignedCertificate(keyPair, "CN=Test Certificate");// 4. 将私钥和证书存储到 KeyStorechar[] password = "password".toCharArray(); // KeyStore 密码KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password);KeyStore.PrivateKeyEntry privateKeyEntry = new KeyStore.PrivateKeyEntry(privateKey, new Certificate[]{certificate});KeyStore.Entry entry = privateKeyEntry;keyStore.setEntry("myPrivateKey", entry, entryPassword);// 5. 将受信任的证书存储到 KeyStorekeyStore.setCertificateEntry("myTrustedCert", certificate);// 6. 保存 KeyStore 到文件try (FileOutputStream fos = new FileOutputStream("myKeystore.jks")) {keyStore.store(fos, password);}System.out.println("KeyStore created and saved to myKeystore.jks");}// 生成自签名证书private static X509Certificate generateSelfSignedCertificate(KeyPair keyPair, String dn) throws Exception {X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();X500Principal principal = new X500Principal(dn);certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));certGen.setSubjectDN(principal);certGen.setIssuerDN(principal); // 自签名certGen.setNotBefore(new Date());certGen.setNotAfter(new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L)); // 1 年有效期certGen.setPublicKey(keyPair.getPublic());certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");return certGen.generateX509Certificate(keyPair.getPrivate(), "BC"); // 使用 BouncyCastle 提供程序}
}
从 KeyStore 加载密钥和证书示例
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;public class KeyStoreLoader {public static void main(String[] args) throws Exception {// 1. 加载 KeyStorechar[] password = "password".toCharArray(); // KeyStore 密码KeyStore keyStore = KeyStore.getInstance("JKS");try (FileInputStream fis = new FileInputStream("myKeystore.jks")) {keyStore.load(fis, password);}// 2. 获取私钥KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password);KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("myPrivateKey", entryPassword);PrivateKey privateKey = privateKeyEntry.getPrivateKey();System.out.println("Private Key loaded: " + privateKey);// 3. 获取证书Certificate certificate = keyStore.getCertificate("myTrustedCert");System.out.println("Certificate loaded: " + certificate);}
}
javax.crypto 包详解
安全消息摘要Mac
Mac
类支持以下常见的 HMAC 算法:
-
HmacSHA256
-
HmacSHA512
-
HmacSHA1
-
HmacMD5
生成 HMAC 示例
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import java.util.Base64;public class MacExample {public static void main(String[] args) throws Exception {// 1. 生成密钥KeyGenerator keyGen = KeyGenerator.getInstance("HmacSHA256"); // 使用 HMAC-SHA256 算法SecretKey secretKey = keyGen.generateKey();// 2. 创建 Mac 实例Mac mac = Mac.getInstance("HmacSHA256");mac.init(secretKey);// 3. 要计算 HMAC 的消息String message = "Hello, World!";byte[] messageBytes = message.getBytes();// 4. 计算 HMACbyte[] hmacBytes = mac.doFinal(messageBytes);String hmacBase64 = Base64.getEncoder().encodeToString(hmacBytes);System.out.println("HMAC: " + hmacBase64);}
}
验证 HMAC 示例
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import java.util.Base64;public class MacVerifier {public static void main(String[] args) throws Exception {// 1. 假设我们已经有一个密钥和 HMACSecretKey secretKey = getSecretKey(); // 获取密钥String message = "Hello, World!";byte[] messageBytes = message.getBytes();String receivedHmacBase64 = "收到的 HMAC 值";// 2. 创建 Mac 实例Mac mac = Mac.getInstance("HmacSHA256");mac.init(secretKey);// 3. 计算本地 HMACbyte[] localHmacBytes = mac.doFinal(messageBytes);String localHmacBase64 = Base64.getEncoder().encodeToString(localHmacBytes);// 4. 比较收到的 HMAC 和本地计算的 HMACif (receivedHmacBase64.equals(localHmacBase64)) {System.out.println("HMAC 验证成功!");} else {System.out.println("HMAC 验证失败!");}}// 模拟获取密钥private static SecretKey getSecretKey() throws Exception {KeyGenerator keyGen = KeyGenerator.getInstance("HmacSHA256");return keyGen.generateKey();}
}
密钥生成器KeyGenerator
密钥协定KeyAgreement
KeyAgreement
类支持以下常见的密钥协商算法:
-
DH
(Diffie-Hellman) -
ECDH
(Elliptic Curve Diffie-Hellman)
生成密钥对示例
import javax.crypto.KeyAgreement;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;public class KeyAgreementExample {public static void main(String[] args) throws Exception {// 1. 生成 Alice 的密钥对KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");keyPairGenerator.initialize(2048); // 2048 位密钥KeyPair aliceKeyPair = keyPairGenerator.generateKeyPair();PrivateKey alicePrivateKey = aliceKeyPair.getPrivate();PublicKey alicePublicKey = aliceKeyPair.getPublic();// 2. 生成 Bob 的密钥对KeyPair bobKeyPair = keyPairGenerator.generateKeyPair();PrivateKey bobPrivateKey = bobKeyPair.getPrivate();PublicKey bobPublicKey = bobKeyPair.getPublic();// 3. Alice 和 Bob 进行密钥协商byte[] aliceSharedSecret = generateSharedSecret(alicePrivateKey, bobPublicKey);byte[] bobSharedSecret = generateSharedSecret(bobPrivateKey, alicePublicKey);// 4. 验证双方生成的共享密钥是否相同System.out.println("Alice's shared secret: " + bytesToHex(aliceSharedSecret));System.out.println("Bob's shared secret: " + bytesToHex(bobSharedSecret));System.out.println("Shared secrets match: " + java.util.Arrays.equals(aliceSharedSecret, bobSharedSecret));}// 生成共享密钥private static byte[] generateSharedSecret(PrivateKey privateKey, PublicKey publicKey) throws Exception {KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");keyAgreement.init(privateKey);keyAgreement.doPhase(publicKey, true);return keyAgreement.generateSecret();}// 将字节数组转换为十六进制字符串private static String bytesToHex(byte[] bytes) {StringBuilder result = new StringBuilder();for (byte b : bytes) {result.append(String.format("%02x", b));}return result.toString();}
}
秘密密钥工厂SecretKeyFactory
KeyGenerator:用于生产新的密钥;
SecretKeyFactory:用于转换密钥数据为key对象
byte[] 还原为密钥
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;public class SecretKeyFactoryExample {public static void main(String[] args) {try {KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");SecretKey secretKey1 = keyGenerator.generateKey();// 1. 假设我们有一个字节数组表示的密钥byte[] keyBytes = secretKey1.getEncoded();// 2. 使用 SecretKeySpec 将字节数组转换为 SecretKeySecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");System.out.println("SecretKeySpec: " + bytesToHex(secretKeySpec.getEncoded()));// 3. 使用 SecretKeyFactory 将 SecretKeySpec 转换为 SecretKeySecretKeyFactory keyFactory = SecretKeyFactory.getInstance("AES");KeySpec keySpec = new SecretKeySpec(keyBytes, "AES");SecretKey secretKey = keyFactory.generateSecret(keySpec);System.out.println("SecretKey: " + bytesToHex(secretKey.getEncoded()));} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {e.printStackTrace();}}// 将字节数组转换为十六进制字符串private static String bytesToHex(byte[] bytes) {StringBuilder result = new StringBuilder();for (byte b : bytes) {result.append(String.format("%02x", b));}return result.toString();}
}
加密与解密Cipher
AES 加密和解密示例
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class CipherExample {public static void main(String[] args) {try {// 1. 生成 AES 密钥SecretKey secretKey = generateAESKey();System.out.println("AES Key: " + Base64.getEncoder().encodeToString(secretKey.getEncoded()));// 2. 生成初始化向量 (IV)byte[] iv = new byte[16]; // AES 块大小为 16 字节IvParameterSpec ivSpec = new IvParameterSpec(iv);// 3. 要加密的数据String plainText = "Hello, World!";System.out.println("Plain Text: " + plainText);// 4. 加密数据byte[] encryptedBytes = encrypt(plainText, secretKey, ivSpec);String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);System.out.println("Encrypted Text: " + encryptedText);// 5. 解密数据String decryptedText = decrypt(encryptedBytes, secretKey, ivSpec);System.out.println("Decrypted Text: " + decryptedText);} catch (Exception e) {e.printStackTrace();}}// 生成 AES 密钥private static SecretKey generateAESKey() throws NoSuchAlgorithmException {KeyGenerator keyGen = KeyGenerator.getInstance("AES");keyGen.init(128); // 128 位密钥return keyGen.generateKey();}// 加密数据private static byte[] encrypt(String plainText, SecretKey secretKey, IvParameterSpec ivSpec) throws Exception {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // AES/CBC 模式cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);return cipher.doFinal(plainText.getBytes());}// 解密数据private static String decrypt(byte[] encryptedBytes, SecretKey secretKey, IvParameterSpec ivSpec) throws Exception {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);byte[] decryptedBytes = cipher.doFinal(encryptedBytes);return new String(decryptedBytes);}
}
RSA 加密和解密示例
import javax.crypto.Cipher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;public class CipherRSAExample {public static void main(String[] args) {try {// 1. 生成 RSA 密钥对KeyPair keyPair = generateRSAKeyPair();PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();// 2. 要加密的数据String plainText = "Hello, RSA!";System.out.println("Plain Text: " + plainText);// 3. 加密数据byte[] encryptedBytes = encrypt(plainText, publicKey);String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);System.out.println("Encrypted Text: " + encryptedText);// 4. 解密数据String decryptedText = decrypt(encryptedBytes, privateKey);System.out.println("Decrypted Text: " + decryptedText);} catch (Exception e) {e.printStackTrace();}}// 生成 RSA 密钥对private static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048); // 2048 位密钥return keyPairGenerator.generateKeyPair();}// 加密数据private static byte[] encrypt(String plainText, PublicKey publicKey) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(plainText.getBytes());}// 解密数据private static String decrypt(byte[] encryptedBytes, PrivateKey privateKey) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, privateKey);byte[] decryptedBytes = cipher.doFinal(encryptedBytes);return new String(decryptedBytes);}
}
密封对象SealedObject
javax.crypto.SealedObject
类用于将对象加密并封装为一个密封对象。它结合了 Cipher
的加密功能和对象的序列化功能,使得可以将任何可序列化的对象加密存储或传输。SealedObject 只能加密实现了 Serializable 接口的对象。
加密和解密对象示例
import javax.crypto.Cipher;
import javax.crypto.SealedObject;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.io.Serializable;
import java.security.NoSuchAlgorithmException;public class SealedObjectExample {public static void main(String[] args) {try {// 1. 生成 AES 密钥SecretKey secretKey = generateAESKey();System.out.println("AES Key: " + bytesToHex(secretKey.getEncoded()));// 2. 创建一个可序列化的对象MyObject myObject = new MyObject("Hello, SealedObject!", 123);System.out.println("Original Object: " + myObject);// 3. 加密对象SealedObject sealedObject = encryptObject(myObject, secretKey);System.out.println("Sealed Object: " + sealedObject);// 4. 解密对象MyObject decryptedObject = decryptObject(sealedObject, secretKey);System.out.println("Decrypted Object: " + decryptedObject);} catch (Exception e) {e.printStackTrace();}}// 生成 AES 密钥private static SecretKey generateAESKey() throws NoSuchAlgorithmException {KeyGenerator keyGen = KeyGenerator.getInstance("AES");keyGen.init(128); // 128 位密钥return keyGen.generateKey();}// 加密对象private static SealedObject encryptObject(Serializable object, SecretKey secretKey) throws Exception {Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.ENCRYPT_MODE, secretKey);return new SealedObject(object, cipher);}// 解密对象private static MyObject decryptObject(SealedObject sealedObject, SecretKey secretKey) throws Exception {Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.DECRYPT_MODE, secretKey);return (MyObject) sealedObject.getObject(cipher);}// 将字节数组转换为十六进制字符串private static String bytesToHex(byte[] bytes) {StringBuilder result = new StringBuilder();for (byte b : bytes) {result.append(String.format("%02x", b));}return result.toString();}// 定义一个可序列化的对象static class MyObject implements Serializable {private String message;private int number;public MyObject(String message, int number) {this.message = message;this.number = number;}@Overridepublic String toString() {return "MyObject{" +"message='" + message + '\'' +", number=" + number +'}';}}
}
java.security.spec包和javax.crypto.spec包详解
密要规范KeySpec
java.security.cert包详解
证书Certificate
使用 BouncyCastle 创建 X.509 证书
import org.bouncycastle.x509.X509V3CertificateGenerator;import javax.security.auth.x500.X500Principal;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;public class CreateCertificateExample {public static void main(String[] args) throws Exception {// 1. 生成密钥对KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048); // 2048 位密钥KeyPair keyPair = keyPairGenerator.generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();// 2. 创建 X.509 证书X509Certificate certificate = generateSelfSignedCertificate(keyPair, "CN=Test Certificate");// 3. 使用 CertificateFactory 加载证书CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");byte[] certBytes = certificate.getEncoded();X509Certificate loadedCertificate = (X509Certificate) certificateFactory.generateCertificate(new java.io.ByteArrayInputStream(certBytes));// 4. 输出证书信息System.out.println("Subject: " + loadedCertificate.getSubjectX500Principal());System.out.println("Issuer: " + loadedCertificate.getIssuerX500Principal());System.out.println("Valid From: " + loadedCertificate.getNotBefore());System.out.println("Valid Until: " + loadedCertificate.getNotAfter());System.out.println("Serial Number: " + loadedCertificate.getSerialNumber());System.out.println("Signature Algorithm: " + loadedCertificate.getSigAlgName());System.out.println("Version: " + loadedCertificate.getVersion());}// 生成自签名证书private static X509Certificate generateSelfSignedCertificate(KeyPair keyPair, String dn) throws Exception {X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();X500Principal principal = new X500Principal(dn);// 设置证书信息certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));certGen.setSubjectDN(principal);certGen.setIssuerDN(principal); // 自签名certGen.setNotBefore(new Date());certGen.setNotAfter(new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L)); // 1 年有效期certGen.setPublicKey(keyPair.getPublic());certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");// 使用私钥签名证书return certGen.generateX509Certificate(keyPair.getPrivate(), "BC"); // 使用 BouncyCastle 提供程序}
}
将证书保存到文件
import java.io.FileOutputStream;
import java.security.cert.X509Certificate;public class SaveCertificateExample {public static void main(String[] args) throws Exception {// 生成证书(参考前面的代码)X509Certificate certificate = CreateCertificateExample.generateSelfSignedCertificate(KeyPairGenerator.getInstance("RSA").generateKeyPair(), "CN=Test Certificate");// 将证书保存到文件try (FileOutputStream fos = new FileOutputStream("certificate.cer")) {fos.write(certificate.getEncoded());}System.out.println("Certificate saved to certificate.cer");}
}
使用 CertificateFactory 加载和解析 X.509 证书
import java.io.FileInputStream;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;public class CertificateFactoryExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 从文件加载证书FileInputStream fis = new FileInputStream("certificate.cer"); // 证书文件路径Certificate certificate = certificateFactory.generateCertificate(fis);fis.close();// 3. 将证书转换为 X509Certificateif (certificate instanceof X509Certificate) {X509Certificate x509Certificate = (X509Certificate) certificate;// 4. 输出证书信息System.out.println("Subject: " + x509Certificate.getSubjectX500Principal());System.out.println("Issuer: " + x509Certificate.getIssuerX500Principal());System.out.println("Valid From: " + x509Certificate.getNotBefore());System.out.println("Valid Until: " + x509Certificate.getNotAfter());System.out.println("Serial Number: " + x509Certificate.getSerialNumber());System.out.println("Signature Algorithm: " + x509Certificate.getSigAlgName());System.out.println("Version: " + x509Certificate.getVersion());// 5. 验证证书是否有效Date currentDate = new Date();if (currentDate.before(x509Certificate.getNotAfter()) && currentDate.after(x509Certificate.getNotBefore())) {System.out.println("Certificate is valid.");} else {System.out.println("Certificate is expired or not yet valid.");}} else {System.out.println("The certificate is not an X.509 certificate.");}} catch (Exception e) {e.printStackTrace();}}
}
使用 CertificateFactory 加载证书链
import java.io.FileInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Iterator;public class CertificateChainExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 从文件加载证书链FileInputStream fis = new FileInputStream("certificate-chain.pem"); // 证书链文件路径Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(fis);fis.close();// 3. 遍历证书链Iterator<? extends Certificate> iterator = certificates.iterator();int index = 1;while (iterator.hasNext()) {Certificate certificate = iterator.next();if (certificate instanceof X509Certificate) {X509Certificate x509Certificate = (X509Certificate) certificate;System.out.println("Certificate #" + index + ":");System.out.println(" Subject: " + x509Certificate.getSubjectX500Principal());System.out.println(" Issuer: " + x509Certificate.getIssuerX500Principal());System.out.println(" Valid From: " + x509Certificate.getNotBefore());System.out.println(" Valid Until: " + x509Certificate.getNotAfter());System.out.println(" Serial Number: " + x509Certificate.getSerialNumber());System.out.println(" Signature Algorithm: " + x509Certificate.getSigAlgName());System.out.println(" Version: " + x509Certificate.getVersion());index++;}}} catch (Exception e) {e.printStackTrace();}}
}
证书撤销列表CRL
CRL:证书撤销列表,
X509CRL:标明类型为X.509的CRL
X509CRLEntry:用于表示CRL中已撤销的证书
使用 X509CRL 加载和解析 CRL
import java.io.FileInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.util.Iterator;
import java.util.Set;public class X509CRLExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 从文件加载 CRLFileInputStream fis = new FileInputStream("crl.pem"); // CRL 文件路径X509CRL crl = (X509CRL) certificateFactory.generateCRL(fis);fis.close();// 3. 输出 CRL 信息System.out.println("Issuer: " + crl.getIssuerX500Principal());System.out.println("This Update: " + crl.getThisUpdate());System.out.println("Next Update: " + crl.getNextUpdate());System.out.println("CRL Number: " + crl.getExtensionValue("2.5.29.20")); // CRL 编号扩展// 4. 遍历吊销的证书条目Set<? extends X509CRLEntry> revokedCertificates = crl.getRevokedCertificates();if (revokedCertificates != null) {Iterator<? extends X509CRLEntry> iterator = revokedCertificates.iterator();while (iterator.hasNext()) {X509CRLEntry entry = iterator.next();System.out.println("Serial Number: " + entry.getSerialNumber());System.out.println("Revocation Date: " + entry.getRevocationDate());System.out.println("Reason: " + entry.getRevocationReason()); // 吊销原因}} else {System.out.println("No revoked certificates in this CRL.");}} catch (Exception e) {e.printStackTrace();}}
}
生成 CRL(使用 BouncyCastle)
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509v2CRLBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
import org.bouncycastle.cert.jcajce.JcaX509v2CRLBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.cert.X509CRL;
import java.util.Date;public class GenerateCRLExample {public static void main(String[] args) throws Exception {// 1. 生成密钥对KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048); // 2048 位密钥KeyPair keyPair = keyPairGenerator.generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();// 2. 创建 CRL 生成器X509v2CRLBuilder crlBuilder = new JcaX509v2CRLBuilder(new org.bouncycastle.asn1.x500.X500Name("CN=Example CA, OU=Example CA Org, O=Example CA Org, L=Example CA City, ST=Example CA State, C=US"),new Date());// 3. 添加 CRL 扩展crlBuilder.addExtension(Extension.cRLNumber, false, new CRLNumber(BigInteger.ONE));// 4. 添加吊销的证书条目crlBuilder.addCRLEntry(BigInteger.valueOf(1234567890L), // 吊销证书的序列号new Date(), // 吊销日期CRLReason.privilegeWithdrawn // 吊销原因);// 5. 使用私钥签名 CRLX509CRL crl = new JcaX509CRLConverter().getCRL(crlBuilder.build(new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(privateKey)));// 6. 输出 CRL 信息System.out.println("Issuer: " + crl.getIssuerX500Principal());System.out.println("This Update: " + crl.getThisUpdate());System.out.println("Next Update: " + crl.getNextUpdate());System.out.println("CRL Number: " + crl.getExtensionValue("2.5.29.20")); // CRL 编号扩展// 7. 保存 CRL 到文件try (java.io.FileOutputStream fos = new java.io.FileOutputStream("generated_crl.pem")) {fos.write(crl.getEncoded());}System.out.println("CRL saved to generated_crl.pem");}
}
证书链CertPath
构建证书路径
import java.io.FileInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;public class CertPathExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 加载证书文件List<X509Certificate> certificates = new ArrayList<>();certificates.add(loadCertificate(certificateFactory, "cert1.cer")); // 终端实体证书certificates.add(loadCertificate(certificateFactory, "cert2.cer")); // 中间 CA 证书certificates.add(loadCertificate(certificateFactory, "cert3.cer")); // 根 CA 证书// 3. 构建 CertPathCertPath certPath = certificateFactory.generateCertPath(certificates);// 4. 输出 CertPath 信息System.out.println("CertPath Type: " + certPath.getType());System.out.println("CertPath Length: " + certPath.getCertificates().size());for (java.security.cert.Certificate cert : certPath.getCertificates()) {X509Certificate x509Cert = (X509Certificate) cert;System.out.println("Subject: " + x509Cert.getSubjectX500Principal());System.out.println("Issuer: " + x509Cert.getIssuerX500Principal());System.out.println("Serial Number: " + x509Cert.getSerialNumber());System.out.println("Valid From: " + x509Cert.getNotBefore());System.out.println("Valid Until: " + x509Cert.getNotAfter());System.out.println("-----");}} catch (Exception e) {e.printStackTrace();}}// 从文件加载证书private static X509Certificate loadCertificate(CertificateFactory certificateFactory, String filePath) throws Exception {try (FileInputStream fis = new FileInputStream(filePath)) {return (X509Certificate) certificateFactory.generateCertificate(fis);}}
}
验证证书路径
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.*;
import java.util.ArrayList;
import java.util.List;public class CertPathValidationExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 加载证书文件List<X509Certificate> certificates = new ArrayList<>();certificates.add(loadCertificate(certificateFactory, "cert1.cer")); // 终端实体证书certificates.add(loadCertificate(certificateFactory, "cert2.cer")); // 中间 CA 证书certificates.add(loadCertificate(certificateFactory, "cert3.cer")); // 根 CA 证书// 3. 构建 CertPathCertPath certPath = certificateFactory.generateCertPath(certificates);// 4. 加载受信任的根证书KeyStore keyStore = KeyStore.getInstance("JKS");try (FileInputStream fis = new FileInputStream("truststore.jks")) {keyStore.load(fis, "password".toCharArray()); // 信任库密码}// 5. 创建 PKIXParametersPKIXParameters params = new PKIXParameters(keyStore);params.setRevocationEnabled(false); // 禁用吊销检查(可选)// 6. 验证 CertPathCertPathValidator validator = CertPathValidator.getInstance("PKIX");CertPathValidatorResult result = validator.validate(certPath, params);System.out.println("CertPath validation succeeded: " + result);} catch (Exception e) {e.printStackTrace();}}// 从文件加载证书private static X509Certificate loadCertificate(CertificateFactory certificateFactory, String filePath) throws Exception {try (FileInputStream fis = new FileInputStream(filePath)) {return (X509Certificate) certificateFactory.generateCertificate(fis);}}
}
保存 CertPath 到文件
import java.io.FileOutputStream;
import java.security.cert.CertPath;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;public class SaveCertPathExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 加载证书文件List<X509Certificate> certificates = new ArrayList<>();certificates.add(loadCertificate(certificateFactory, "cert1.cer")); // 终端实体证书certificates.add(loadCertificate(certificateFactory, "cert2.cer")); // 中间 CA 证书certificates.add(loadCertificate(certificateFactory, "cert3.cer")); // 根 CA 证书// 3. 构建 CertPathCertPath certPath = certificateFactory.generateCertPath(certificates);// 4. 保存 CertPath 到文件try (FileOutputStream fos = new FileOutputStream("certpath.pem")) {fos.write(certPath.getEncoded());}System.out.println("CertPath saved to certpath.pem");} catch (Exception e) {e.printStackTrace();}}// 从文件加载证书private static X509Certificate loadCertificate(CertificateFactory certificateFactory, String filePath) throws Exception {try (FileInputStream fis = new FileInputStream(filePath)) {return (X509Certificate) certificateFactory.generateCertificate(fis);}}
}
文件中加载 CertPath
import java.io.FileInputStream;
import java.security.cert.CertPath;
import java.security.cert.CertificateFactory;public class LoadCertPathExample {public static void main(String[] args) {try {// 1. 创建 CertificateFactory 实例CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");// 2. 从文件加载 CertPathtry (FileInputStream fis = new FileInputStream("certpath.pem")) {CertPath certPath = certificateFactory.generateCertPath(fis);// 3. 输出 CertPath 信息System.out.println("CertPath Type: " + certPath.getType());System.out.println("CertPath Length: " + certPath.getCertificates().size());}} catch (Exception e) {e.printStackTrace();}}
}