注意 , 虽然使用PBE加解密数据 , 都需要使用相同的password、salt、iteratorCount , 但这里面只有password是需要保密的 , salt与iteratorCount不需要 , 可以保存在数据库中 , 比如每个用户注册时给他生成一个随机盐 。
到此 , JCA密码算法就介绍完了 , 来回顾一下:
文章插图
整体来说 , JCA对密码算法相关的类设计与封装还是非常清晰简单的!
但使用密码算法时 , 依赖SecretKey、PublicKey、PrivateKey对象提供密钥信息 , 那这些密钥对象是怎么来的呢?
密钥生成与读取密码学随机数密码学随机数算法在安全场景中使用广泛 , 如:生成对称密钥、盐、iv等 , 因此相比普通的随机数算法(如线性同余) , 它需要更高强度的不可预测性 , 在Java中 , 使用SecureRandom来生成更安全的随机数 , 如下:
public class SecureRandoms { public static byte[] randBytes(int len) throws NoSuchAlgorithmException {byte[] bytes = new byte[len];SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");secureRandom.nextBytes(bytes);return bytes; }}
SecureRandom使用了更高强度的随机算法 , 同时会读取机器本身的随机熵值 , 如/dev/urandom
, 因此相比普通的Random , 它具有更强的随机性 , 因此 , 对于需要生成密钥的场景 , 该用哪个要拧得清 。对称密钥在JCA中对称密钥使用SecretKey表示 , 若要生成一个新的SecretKey , 可使用KeyGenerator , 如下:
//生成新的密钥public static SecretKey genSecretKey() {KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");keyGenerator.init(SecureRandom.getInstance("SHA1PRNG"));SecretKey secretKey = keyGenerator.generateKey();}
而如果是从文件中读取密钥的话 , 则可以借助SecretKeyFactory将其转换为SecretKey , 如下://读取密钥public static SecretKey getSecretKey() {byte[] keyBytes = readKeyBytes();String alg = "AES";SecretKey secretKey = SecretKeyFactory.getInstance(alg).generateSecret(new SecretKeySpec(keyBytes, alg));}
非对称密钥在JCA中 , 对于非对称密钥 , 公钥使用PublicKey表示 , 私钥使用PrivateKey表示 , 若要生成一个新的公私钥对 , 可使用KeyPairGenerator , 如下://生成新的公私钥对public static void genKeyPair() {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");keyPairGen.initialize(2048);KeyPair keyPair = keyPairGen.generateKeyPair();PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();}
而如果是从文件中读取公私钥的话 , 一般公钥是X509格式 , 而私钥是PKCS8格式 , 分别对应JCA中的X509EncodedKeySpec与PKCS8EncodedKeySpec , 如下://读取私钥public static PrivateKey getPrivateKey() {byte[] privateKeyBytes = readPrivateKeyBytes();PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);}//读取公钥public static PublicKey getPublicKey() {byte[] publicKeyBytes = readPublicKeyBytes();X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec);}
注意 , KeyGenerator、KeyPairGenerator与KeyFactory从命名上看起来有点相似 , 但它们实现的功能是完全不同的 , KeyGenerator、KeyPairGenerator用于生成新的密钥 , 而KeyFactory则用于将KeySpec转换为对应的Key密钥对象 。
经验总结扩展阅读
- [WPF] 抄抄超强的苹果官网滚动文字特效实现
- Java函数式编程:一、函数式接口,lambda表达式和方法引用
- 不妨试试更快更小更灵活Java开发框架Solon
- 11 微服务架构学习与思考:开源 API 网关02-以 Java 为基础的 API 网关详细介绍
- java 新特性之 Stream API
- java 入土--集合详解
- 4 Java I/O:AIO和NIO中的Selector
- 2023容易暴富的星座女实现质的飞跃
- 通过 Github Action 实现定时推送天气预报
- 3 Java I/O:NIO中的Buffer