为啥从 Java 中的密码派生密钥时需要 SecretKeySpec?

Posted

技术标签:

【中文标题】为啥从 Java 中的密码派生密钥时需要 SecretKeySpec?【英文标题】:Why is a SecretKeySpec needed when deriving a key from a password in Java?为什么从 Java 中的密码派生密钥时需要 SecretKeySpec? 【发布时间】:2015-01-19 11:51:42 【问题描述】:

Java 中 SecretKeySecretKeySpec 类之间有什么区别?

SecretKeySpec 的文档说:

它可以用来从一个字节数组构造一个SecretKey

在这段代码中,如果我以十六进制打印 secretKey.getEncoded()secret.getEncoded(),那么两者都会给出相同的输出。那么为什么我们需要SecretKeySpec

final String password = "test";
int pswdIterations = 65536  ;
int keySize = 256;
byte[] ivBytes;
byte[] saltBytes = 0,1,2,3,4,5,6;

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

PBEKeySpec spec = new PBEKeySpec(
                    password.toCharArray(), 
                    saltBytes, 
                    pswdIterations, 
                    keySize
                    );

SecretKey secretKey = factory.generateSecret(spec);

SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(),"AES");

这是对getEncoded() 的两次调用的输出:

00367171843C185C043DDFB90AA97677F11D02B629DEAFC04F935419D832E697

【问题讨论】:

【参考方案1】:

SecretKey 只是一个需要提供者特定实现的接口。 SecretKeySpec 是一个具体的类,它允许从现有的密钥材料轻松构造 SecretKey。因此,为了获取 SecretKey,您需要使用适当的工厂类或 SecretKeySpec 作为快捷方式。

【讨论】:

【参考方案2】:

每个SecretKey 都有一个关联的算法名称。例如,在需要 AES 密钥的上下文中,您不能将 SecretKey 与算法 "DES" 一起使用。

在您的代码中,以下行生成SecretKey

SecretKey secretKey = factory.generateSecret(spec);

但是,此时密钥不是 AES 密钥。如果你打电话给secretKey.getAlgorithm(),结果是"PBKDF2WithHmacSHA1"。您需要某种方式告诉 Java 这实际上是一个 AES 密钥。

最简单的方法是构造一个新的SecretKeySpec 对象,使用原始密钥数据并明确指定算法名称:

SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(),"AES");

注意:我个人会将secret 声明为SecretKey,因为我认为您不需要关心之后的具体实现。

【讨论】:

"每个 SecretKey 都有一个关联的算法名称。" ,那不会降低加密的安全性吗?键不应该独立于算法吗? ,例如,如果有人得到了密钥,他们就不能识别用于加密的算法吗? 强密码学的工作基础是每个人都知道一切,除了你的密钥的值。一旦有人拿到了你的密钥,弄清楚你是如何加密数据的就是一件小事。所以不,你的算法不需要保密。【参考方案3】:

SecretKey 是一个接口,SecretKeySpecSecretKey 的实现

【讨论】:

以上是关于为啥从 Java 中的密码派生密钥时需要 SecretKeySpec?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 ssh 不要求时 git 要求输入密钥密码?

国密算法密码长度才256位二进制,为啥能说是安全的?

将密钥库密码从无密码更改为非空密码

为啥我新签名的 apk 中的指纹不同?

如何在 Java(Android)中生成与 .Net 中相同的 AES 密钥?

从 iOS 中的私钥派生的证书(Objective-C)