Java:使用 KeyStore 保存 DES 密钥
Java: Saving a DES Key Using KeyStore
我正在尝试使用 KeyStore 将 DES 密钥保存到文件中供以后使用。这是我的代码:
// Generate a DES key.
KeyGenerator kg = KeyGenerator.getInstance("DES");
SecretKey k = kg.generateKey();
// Store it in a file.
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
char[] pw = "moon".toCharArray();
KeyStore.SecretKeyEntry sk = new KeyStore.SecretKeyEntry(k);
ks.setEntry("k1", sk, new KeyStore.PasswordProtection(pw));
// store away the keystore
FileOutputStream fos = null;
try {
fos = new FileOutputStream("DESKey.jks");
ks.store(fos, pw);
} finally {
if (fos != null) {
fos.close();
}
}
但是,当我尝试使用 KeyStore.setEntry() 方法时,我收到错误消息,指出 DES 是一种无法识别的算法。异常堆栈在这里:
Exception in thread "main" java.security.KeyStoreException: Key protection algorithm not found: java.security.NoSuchAlgorithmException: unrecognized algorithm name: DES
at java.base/sun.security.pkcs12.PKCS12KeyStore.setKeyEntry(PKCS12KeyStore.java:688)
at java.base/sun.security.pkcs12.PKCS12KeyStore.engineSetEntry(PKCS12KeyStore.java:1423)
at java.base/sun.security.util.KeyStoreDelegator.engineSetEntry(KeyStoreDelegator.java:173) at java.base/java.security.KeyStore.setEntry(KeyStore.java:1591) at CipherClient.main(CipherClient.java:27)
Caused by: java.security.NoSuchAlgorithmException: unrecognized algorithm name: DES
at java.base/sun.security.x509.AlgorithmId.get(AlgorithmId.java:448)
at java.base/sun.security.pkcs12.PKCS12KeyStore.setKeyEntry(PKCS12KeyStore.java:656)
... 4 more
在调试时我将问题缩小到函数 java.base/sun.security.x509.AlgorithmID.get(AlgorithmID.java:448)
这是 AlgorithmID class 中 algOID(algname)
的包装函数。它本质上只是一系列 if 语句,用于检查用于生成要保存的密钥的算法的名称。此处包含此方法的一个片段:
// See if algname is in printable OID ("dot-dot") notation
if (name.indexOf('.') != -1) {
if (name.startsWith("OID.")) {
return new ObjectIdentifier(name.substring("OID.".length()));
} else {
return new ObjectIdentifier(name);
}
}
// Digesting algorithms
if (name.equalsIgnoreCase("MD5")) {
return AlgorithmId.MD5_oid;
}
if (name.equalsIgnoreCase("MD2")) {
return AlgorithmId.MD2_oid;
}
if (name.equalsIgnoreCase("SHA") || name.equalsIgnoreCase("SHA1")
|| name.equalsIgnoreCase("SHA-1")) {
return AlgorithmId.SHA_oid;
}
if (name.equalsIgnoreCase("SHA-256") ||
name.equalsIgnoreCase("SHA256")) {
return AlgorithmId.SHA256_oid;
}
if (name.equalsIgnoreCase("SHA-384") ||
name.equalsIgnoreCase("SHA384")) {
return AlgorithmId.SHA384_oid;
}
if (name.equalsIgnoreCase("SHA-512") ||
name.equalsIgnoreCase("SHA512")) {
return AlgorithmId.SHA512_oid;
}
if (name.equalsIgnoreCase("SHA-224") ||
name.equalsIgnoreCase("SHA224")) {
return AlgorithmId.SHA224_oid;
}
if (name.equalsIgnoreCase("SHA-512/224") ||
name.equalsIgnoreCase("SHA512/224")) {
return AlgorithmId.SHA512_224_oid;
}
if (name.equalsIgnoreCase("SHA-512/256") ||
name.equalsIgnoreCase("SHA512/256")) {
return AlgorithmId.SHA512_256_oid;
}
// Various public key algorithms
if (name.equalsIgnoreCase("RSA")) {
return AlgorithmId.RSAEncryption_oid;
}
if (name.equalsIgnoreCase("RSASSA-PSS")) {
return AlgorithmId.RSASSA_PSS_oid;
}
if (name.equalsIgnoreCase("RSAES-OAEP")) {
return AlgorithmId.RSAES_OAEP_oid;
}
if (name.equalsIgnoreCase("Diffie-Hellman")
|| name.equalsIgnoreCase("DH")) {
return AlgorithmId.DH_oid;
}
if (name.equalsIgnoreCase("DSA")) {
return AlgorithmId.DSA_oid;
}
if (name.equalsIgnoreCase("EC")) {
return EC_oid;
}
if (name.equalsIgnoreCase("ECDH")) {
return AlgorithmId.ECDH_oid;
}
// Secret key algorithms
if (name.equalsIgnoreCase("AES")) {
return AlgorithmId.AES_oid;
}
// Common signature types
if (name.equalsIgnoreCase("MD5withRSA")
|| name.equalsIgnoreCase("MD5/RSA")) {
return AlgorithmId.md5WithRSAEncryption_oid;
}
if (name.equalsIgnoreCase("MD2withRSA")
|| name.equalsIgnoreCase("MD2/RSA")) {
return AlgorithmId.md2WithRSAEncryption_oid;
}
DES 是一种对称密钥算法,应与 AES 一起包含在密钥算法部分,但未列出。我知道 DES 是一种较旧的算法,但他们真的取消了对它的支持吗?
我将不胜感激任何帮助,无论是使密钥库工作还是其他将 DES 密钥写入文件以便稍后可以再次读取的方法。谢谢!
您使用的是哪个 JDK 版本?
众所周知,DES 算法很弱,因此它已从 JDK14 中的许多地方删除:https://bugs.openjdk.java.net/browse/JDK-8233607
简而言之,你不应该使用它。
就是说,[我尝试用 Clojure 重写您的示例][1](抱歉,这些天我不使用 Java)并且效果很好 - 使用 Java 17.0. 2:
(ns clojure-experiments.security.keystore
(:import (javax.crypto KeyGenerator)
(java.security KeyStore
KeyStore$SecretKeyEntry
KeyStore$PasswordProtection)))
;;
(comment
;; https://docs.oracle.com/javase/7/docs/api/javax/crypto/KeyGenerator.html
(def my-kg (KeyGenerator/getInstance "DES"))
(def my-key (.generateKey my-kg))
;; https://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.html
(def my-keystore (KeyStore/getInstance (KeyStore/getDefaultType)))
(.load my-keystore nil nil) ; passing nil input stream to create a new KeyStore
(def my-password (char-array "changeit"))
;; save the key in the keystore
(def my-key-entry (KeyStore$SecretKeyEntry. my-key))
(def my-key-alias "myKeyAlias")
(def my-key-password (KeyStore$PasswordProtection. my-password))
(.setEntry my-keystore my-key-alias my-key-entry my-key-password)
;; save the keystore
(def keystore-path "/Users/jumar/my-key-store.jks")
(.store my-keystore (java.io.FileOutputStream. keystore-path) my-password)
;; now read the key from the saved keystore
(def read-keystore (KeyStore/getInstance (KeyStore/getDefaultType)))
(.load read-keystore (java.io.FileInputStream. keystore-path) my-password)
(.getEntry read-keystore my-key-alias my-key-password)
;; => #object[java.security.KeyStore$SecretKeyEntry 0x58b80b62 "Secret key entry with algorithm DES/CBC"]
,)
And btw. I also copy-pasted your code to IntelliJ to try it quickly and it all worked - again, using OpenJDK 17.
我正在尝试使用 KeyStore 将 DES 密钥保存到文件中供以后使用。这是我的代码:
// Generate a DES key.
KeyGenerator kg = KeyGenerator.getInstance("DES");
SecretKey k = kg.generateKey();
// Store it in a file.
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
char[] pw = "moon".toCharArray();
KeyStore.SecretKeyEntry sk = new KeyStore.SecretKeyEntry(k);
ks.setEntry("k1", sk, new KeyStore.PasswordProtection(pw));
// store away the keystore
FileOutputStream fos = null;
try {
fos = new FileOutputStream("DESKey.jks");
ks.store(fos, pw);
} finally {
if (fos != null) {
fos.close();
}
}
但是,当我尝试使用 KeyStore.setEntry() 方法时,我收到错误消息,指出 DES 是一种无法识别的算法。异常堆栈在这里:
Exception in thread "main" java.security.KeyStoreException: Key protection algorithm not found: java.security.NoSuchAlgorithmException: unrecognized algorithm name: DES
at java.base/sun.security.pkcs12.PKCS12KeyStore.setKeyEntry(PKCS12KeyStore.java:688)
at java.base/sun.security.pkcs12.PKCS12KeyStore.engineSetEntry(PKCS12KeyStore.java:1423)
at java.base/sun.security.util.KeyStoreDelegator.engineSetEntry(KeyStoreDelegator.java:173) at java.base/java.security.KeyStore.setEntry(KeyStore.java:1591) at CipherClient.main(CipherClient.java:27)
Caused by: java.security.NoSuchAlgorithmException: unrecognized algorithm name: DES
at java.base/sun.security.x509.AlgorithmId.get(AlgorithmId.java:448)
at java.base/sun.security.pkcs12.PKCS12KeyStore.setKeyEntry(PKCS12KeyStore.java:656)
... 4 more
在调试时我将问题缩小到函数 java.base/sun.security.x509.AlgorithmID.get(AlgorithmID.java:448)
这是 AlgorithmID class 中 algOID(algname)
的包装函数。它本质上只是一系列 if 语句,用于检查用于生成要保存的密钥的算法的名称。此处包含此方法的一个片段:
// See if algname is in printable OID ("dot-dot") notation
if (name.indexOf('.') != -1) {
if (name.startsWith("OID.")) {
return new ObjectIdentifier(name.substring("OID.".length()));
} else {
return new ObjectIdentifier(name);
}
}
// Digesting algorithms
if (name.equalsIgnoreCase("MD5")) {
return AlgorithmId.MD5_oid;
}
if (name.equalsIgnoreCase("MD2")) {
return AlgorithmId.MD2_oid;
}
if (name.equalsIgnoreCase("SHA") || name.equalsIgnoreCase("SHA1")
|| name.equalsIgnoreCase("SHA-1")) {
return AlgorithmId.SHA_oid;
}
if (name.equalsIgnoreCase("SHA-256") ||
name.equalsIgnoreCase("SHA256")) {
return AlgorithmId.SHA256_oid;
}
if (name.equalsIgnoreCase("SHA-384") ||
name.equalsIgnoreCase("SHA384")) {
return AlgorithmId.SHA384_oid;
}
if (name.equalsIgnoreCase("SHA-512") ||
name.equalsIgnoreCase("SHA512")) {
return AlgorithmId.SHA512_oid;
}
if (name.equalsIgnoreCase("SHA-224") ||
name.equalsIgnoreCase("SHA224")) {
return AlgorithmId.SHA224_oid;
}
if (name.equalsIgnoreCase("SHA-512/224") ||
name.equalsIgnoreCase("SHA512/224")) {
return AlgorithmId.SHA512_224_oid;
}
if (name.equalsIgnoreCase("SHA-512/256") ||
name.equalsIgnoreCase("SHA512/256")) {
return AlgorithmId.SHA512_256_oid;
}
// Various public key algorithms
if (name.equalsIgnoreCase("RSA")) {
return AlgorithmId.RSAEncryption_oid;
}
if (name.equalsIgnoreCase("RSASSA-PSS")) {
return AlgorithmId.RSASSA_PSS_oid;
}
if (name.equalsIgnoreCase("RSAES-OAEP")) {
return AlgorithmId.RSAES_OAEP_oid;
}
if (name.equalsIgnoreCase("Diffie-Hellman")
|| name.equalsIgnoreCase("DH")) {
return AlgorithmId.DH_oid;
}
if (name.equalsIgnoreCase("DSA")) {
return AlgorithmId.DSA_oid;
}
if (name.equalsIgnoreCase("EC")) {
return EC_oid;
}
if (name.equalsIgnoreCase("ECDH")) {
return AlgorithmId.ECDH_oid;
}
// Secret key algorithms
if (name.equalsIgnoreCase("AES")) {
return AlgorithmId.AES_oid;
}
// Common signature types
if (name.equalsIgnoreCase("MD5withRSA")
|| name.equalsIgnoreCase("MD5/RSA")) {
return AlgorithmId.md5WithRSAEncryption_oid;
}
if (name.equalsIgnoreCase("MD2withRSA")
|| name.equalsIgnoreCase("MD2/RSA")) {
return AlgorithmId.md2WithRSAEncryption_oid;
}
DES 是一种对称密钥算法,应与 AES 一起包含在密钥算法部分,但未列出。我知道 DES 是一种较旧的算法,但他们真的取消了对它的支持吗?
我将不胜感激任何帮助,无论是使密钥库工作还是其他将 DES 密钥写入文件以便稍后可以再次读取的方法。谢谢!
您使用的是哪个 JDK 版本?
众所周知,DES 算法很弱,因此它已从 JDK14 中的许多地方删除:https://bugs.openjdk.java.net/browse/JDK-8233607
简而言之,你不应该使用它。
就是说,[我尝试用 Clojure 重写您的示例][1](抱歉,这些天我不使用 Java)并且效果很好 - 使用 Java 17.0. 2:
(ns clojure-experiments.security.keystore
(:import (javax.crypto KeyGenerator)
(java.security KeyStore
KeyStore$SecretKeyEntry
KeyStore$PasswordProtection)))
;;
(comment
;; https://docs.oracle.com/javase/7/docs/api/javax/crypto/KeyGenerator.html
(def my-kg (KeyGenerator/getInstance "DES"))
(def my-key (.generateKey my-kg))
;; https://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.html
(def my-keystore (KeyStore/getInstance (KeyStore/getDefaultType)))
(.load my-keystore nil nil) ; passing nil input stream to create a new KeyStore
(def my-password (char-array "changeit"))
;; save the key in the keystore
(def my-key-entry (KeyStore$SecretKeyEntry. my-key))
(def my-key-alias "myKeyAlias")
(def my-key-password (KeyStore$PasswordProtection. my-password))
(.setEntry my-keystore my-key-alias my-key-entry my-key-password)
;; save the keystore
(def keystore-path "/Users/jumar/my-key-store.jks")
(.store my-keystore (java.io.FileOutputStream. keystore-path) my-password)
;; now read the key from the saved keystore
(def read-keystore (KeyStore/getInstance (KeyStore/getDefaultType)))
(.load read-keystore (java.io.FileInputStream. keystore-path) my-password)
(.getEntry read-keystore my-key-alias my-key-password)
;; => #object[java.security.KeyStore$SecretKeyEntry 0x58b80b62 "Secret key entry with algorithm DES/CBC"]
,)
And btw. I also copy-pasted your code to IntelliJ to try it quickly and it all worked - again, using OpenJDK 17.