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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27059587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:45:42  来源:igfitidea点击:

Why is a SecretKeySpec needed when deriving a key from a password in Java?

javacryptographyjcesecret-key

提问by Riley Willow

What is difference between SecretKeyvs SecretKeySpecclasses in Java?

SecretKeySecretKeySpecJava 中的类有什么区别?

The documentation of SecretKeySpecsays:

的文档SecretKeySpec说:

it can be used to construct a SecretKey from a byte array

它可用于从字节数组构造 SecretKey

In this code, if I print secretKey.getEncoded()or secret.getEncoded(), in hex then both give the same output. So why do we need the SecretKeySpec?

在此代码中,如果我以十六进制打印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");

Here is the output of both calls to getEncoded():

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

00367171843C185C043DDFB90AA97677F11D02B629DEAFC04F935419D832E697

00367171843C185C043DDFB90AA97677F11D02B629DEAFC04F935419D832E697

采纳答案by Duncan Jones

Every SecretKeyhas an associated algorithm name. You cannot use a SecretKeywith algorithm "DES"in a context where an AES key is needed, for example.

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

In your code, the following line produces a SecretKey:

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

SecretKey secretKey = factory.generateSecret(spec);

However, at this point the key is notan AES key. If you were to call secretKey.getAlgorithm(), the result is "PBKDF2WithHmacSHA1". You need some way of telling Java that this is actually an AES key.

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

The easiest way to do this is to construct a new SecretKeySpecobject, using the original key data and explicitly specifying the algorithm name:

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

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

Note: I would personally declare secretas a SecretKey, since I don't think you'll need to care about the concrete implementation after this.

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

回答by Marko ?ivanovi?

SecretKey is just an interface that requires provider-specific implementation. SecretKeySpec is a concrete class that allows for easy construction of SecretKey from existing key material. So, in order to get SecretKey, you need to use either appropriate factory class or SecretKeySpec, as a shortcut.

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

回答by Buhake Sindi

SecretKeyis an interface and SecretKeySpecis an implementation of SecretKey

SecretKey是一个接口,SecretKeySpec是一个实现SecretKey