在 Java 中生成并使用两个密钥进行加密和解密
Generating and using two keys for encryption and decryption in Java
我正在开发一个 Java 应用程序,它需要我使用两个密钥
从不同的字符串生成用于加密和解密。一
字符串来自用户,其他是主密钥。我在网上看
并找到了一些关于它的参考资料。我真的很想要一些
帮助了解如何实现这一点。我会展示我现在的东西。
正如您从代码中看到的那样,我使用了其他 Whosebug post 中的一些代码并对其进行了一些修改。我只是不知道如何从 2 个字符串生成 2 个密钥,以及从哪里可以获得用于解密的 SecretKey desKey。
代码:
public class Encryption {
public void doStuff() {
String plaintext = "abc";
SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();
String firstEncryption = desEncryption(plaintext, k1);
String decryption = desDecryption(firstEncryption, k2);
String secondEncryption = desEncryption(decryption, k1);
System.out.println(firstEncryption);
System.out.println(decryption);
System.out.println(secondEncryption);
}
public static SecretKey generateDESkey() {
KeyGenerator keyGen = null;
try {
keyGen = KeyGenerator.getInstance("DESede");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Test.class
.getName()).log(Level.SEVERE, null, ex);
}
try {
assert keyGen != null;
keyGen.init(112); // key length 56
return keyGen.generateKey();
} catch (NullPointerException ex){
return null;
}
}
public static String desEncryption(String strToEncrypt, SecretKey desKey) {
try {
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, desKey);
return Base64.encode(cipher.doFinal(strToEncrypt.getBytes()));
} catch (NoSuchAlgorithmException | NoSuchPaddingException |
IllegalBlockSizeException | BadPaddingException |
InvalidKeyException ex) {
Logger.getLogger(Test.class
.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static String desDecryption(String strToDecrypt, SecretKey desKey) {
try {
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, desKey);
return new String(cipher.doFinal(Base64.decode(strToDecrypt)));
} catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException
| InvalidKeyException | NoSuchPaddingException ex) {
Logger.getLogger(Test.class
.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
如有任何困惑或疑惑。请告诉我。
更改代码前的答案。
您正在尝试仅使用两个键而不是三个键来执行 DESede。
这可能通常有效,但不像您写的那样。问题是填充。在第二步中,您尝试使用其他密钥解密密文,而不是使用加密的密钥,因此在 256 次中,解密将失败超过 255 次,因为填充将是错误的(也因为您使用 Base64 编码没有必要)。
如果你真的想这样做,你将不得不在不填充和Base64编码的情况下解密。好消息是未编码的密文已经是块大小的倍数,所以没有阻止你使用 "DES/ECB/NoPadding"
.
public static void main(String[] args) {
// First I would like to create keys by giving Strings
SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();
// encryption
byte[] firstEncryption = desEncryption("plaintext".getBytes("UTF-8"), k1, false);
byte[] decryption = desDecryption(firstEncryption, k2, true);
byte[] secondEncryption = desEncryption(decryption, k1, true);
// decryption
byte[] firstDecryption = desDecryption(secondEncryption, k1, true);
byte[] encryption = desEncryption(firstDecryption, k2, true);
byte[] secondDecryption = desDecryption(encryption, k1, false);
System.out.println(new String(secondDecryption)); // plaintext
}
public static byte[] desEncryption(byte[] strToEncrypt, SecretKey desKey, boolean noPadding) {
try {
Cipher cipher = Cipher.getInstance(noPadding ? "DES/ECB/NoPadding" : "DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, desKey);
return cipher.doFinal(strToEncrypt);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static byte[] desDecryption(byte[] strToDecrypt, SecretKey desKey, boolean noPadding) {
try {
Cipher cipher = Cipher.getInstance(noPadding ? "DES/ECB/NoPadding" : "DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, desKey);
return cipher.doFinal(strToDecrypt);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
这实际上是在以这种方式构造通用密钥时,具有两个密钥的 DESede 的等效实现:
SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();
byte[] edeKeyBytes = new byte[24];
System.arraycopy(k1.getEncoded(), 0, edeKeyBytes, 0, 8);
System.arraycopy(k2.getEncoded(), 0, edeKeyBytes, 8, 8);
System.arraycopy(k1.getEncoded(), 0, edeKeyBytes, 16, 8);
edeKey = new SecretKeySpec(edeKeyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, edeKey);
System.out.println(Base64.encode(cipher.doFinal("plaintext".getBytes("UTF-8"))));
DESede 使用三个键,我们称之为 k1、k2 和 k3。所有这些都连接成一个字节数组。在您的情况下,第二次使用 k1 代替 k3。
我正在开发一个 Java 应用程序,它需要我使用两个密钥 从不同的字符串生成用于加密和解密。一 字符串来自用户,其他是主密钥。我在网上看 并找到了一些关于它的参考资料。我真的很想要一些 帮助了解如何实现这一点。我会展示我现在的东西。
正如您从代码中看到的那样,我使用了其他 Whosebug post 中的一些代码并对其进行了一些修改。我只是不知道如何从 2 个字符串生成 2 个密钥,以及从哪里可以获得用于解密的 SecretKey desKey。
代码:
public class Encryption {
public void doStuff() {
String plaintext = "abc";
SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();
String firstEncryption = desEncryption(plaintext, k1);
String decryption = desDecryption(firstEncryption, k2);
String secondEncryption = desEncryption(decryption, k1);
System.out.println(firstEncryption);
System.out.println(decryption);
System.out.println(secondEncryption);
}
public static SecretKey generateDESkey() {
KeyGenerator keyGen = null;
try {
keyGen = KeyGenerator.getInstance("DESede");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Test.class
.getName()).log(Level.SEVERE, null, ex);
}
try {
assert keyGen != null;
keyGen.init(112); // key length 56
return keyGen.generateKey();
} catch (NullPointerException ex){
return null;
}
}
public static String desEncryption(String strToEncrypt, SecretKey desKey) {
try {
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, desKey);
return Base64.encode(cipher.doFinal(strToEncrypt.getBytes()));
} catch (NoSuchAlgorithmException | NoSuchPaddingException |
IllegalBlockSizeException | BadPaddingException |
InvalidKeyException ex) {
Logger.getLogger(Test.class
.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static String desDecryption(String strToDecrypt, SecretKey desKey) {
try {
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, desKey);
return new String(cipher.doFinal(Base64.decode(strToDecrypt)));
} catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException
| InvalidKeyException | NoSuchPaddingException ex) {
Logger.getLogger(Test.class
.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
如有任何困惑或疑惑。请告诉我。
更改代码前的答案。
您正在尝试仅使用两个键而不是三个键来执行 DESede。
这可能通常有效,但不像您写的那样。问题是填充。在第二步中,您尝试使用其他密钥解密密文,而不是使用加密的密钥,因此在 256 次中,解密将失败超过 255 次,因为填充将是错误的(也因为您使用 Base64 编码没有必要)。
如果你真的想这样做,你将不得不在不填充和Base64编码的情况下解密。好消息是未编码的密文已经是块大小的倍数,所以没有阻止你使用 "DES/ECB/NoPadding"
.
public static void main(String[] args) {
// First I would like to create keys by giving Strings
SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();
// encryption
byte[] firstEncryption = desEncryption("plaintext".getBytes("UTF-8"), k1, false);
byte[] decryption = desDecryption(firstEncryption, k2, true);
byte[] secondEncryption = desEncryption(decryption, k1, true);
// decryption
byte[] firstDecryption = desDecryption(secondEncryption, k1, true);
byte[] encryption = desEncryption(firstDecryption, k2, true);
byte[] secondDecryption = desDecryption(encryption, k1, false);
System.out.println(new String(secondDecryption)); // plaintext
}
public static byte[] desEncryption(byte[] strToEncrypt, SecretKey desKey, boolean noPadding) {
try {
Cipher cipher = Cipher.getInstance(noPadding ? "DES/ECB/NoPadding" : "DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, desKey);
return cipher.doFinal(strToEncrypt);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static byte[] desDecryption(byte[] strToDecrypt, SecretKey desKey, boolean noPadding) {
try {
Cipher cipher = Cipher.getInstance(noPadding ? "DES/ECB/NoPadding" : "DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, desKey);
return cipher.doFinal(strToDecrypt);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
这实际上是在以这种方式构造通用密钥时,具有两个密钥的 DESede 的等效实现:
SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();
byte[] edeKeyBytes = new byte[24];
System.arraycopy(k1.getEncoded(), 0, edeKeyBytes, 0, 8);
System.arraycopy(k2.getEncoded(), 0, edeKeyBytes, 8, 8);
System.arraycopy(k1.getEncoded(), 0, edeKeyBytes, 16, 8);
edeKey = new SecretKeySpec(edeKeyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, edeKey);
System.out.println(Base64.encode(cipher.doFinal("plaintext".getBytes("UTF-8"))));
DESede 使用三个键,我们称之为 k1、k2 和 k3。所有这些都连接成一个字节数组。在您的情况下,第二次使用 k1 代替 k3。