使用Java加密和解密:无法获得相同的输出

jak*_*ake 5 java encryption

我正在尝试学习和测试java 1.6加密/解密API.我想知道我做错了什么以及我在知识方面缺少什么.

在下面的代码中,我创建了两个密码:一个用于加密,另一个用于解密.当我使用这些密码时,我使用不同的SecretKey初始化它们,但我仍然能够获得相同的值.为什么是这样?

    String algorithm = "DES";
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);

    byte[] encBytes = "12345678".getBytes("UTF8");
    byte[] decBytes = "56781234".getBytes("UTF8");

    DESKeySpec keySpecEncrypt = new DESKeySpec(encBytes);
    DESKeySpec keySpecDecrypt = new DESKeySpec(decBytes);


    SecretKey keyEncrypt = keyFactory.generateSecret(keySpecEncrypt);
    SecretKey keyDecrypt = keyFactory.generateSecret(keySpecDecrypt);

    Cipher cipherEncrypt = Cipher.getInstance(algorithm);
    Cipher cipherDecrypt = Cipher.getInstance(algorithm);

    String input = "john doe";

    cipherEncrypt.init(Cipher.ENCRYPT_MODE, keyEncrypt);
    byte[] inputBytes = cipherEncrypt.doFinal(input.getBytes());
    System.out.println("inputBytes: " + new String(inputBytes));

    cipherDecrypt.init(Cipher.DECRYPT_MODE, keyDecrypt);
    byte[] outputBytes = cipherDecrypt.doFinal(inputBytes);
    System.out.println("outputBytes: " + new String(outputBytes));
Run Code Online (Sandbox Code Playgroud)

Whi*_*g34 16

欢迎加密!如上所述,DES是对称的,并且需要与解密相同的加密密钥.该密钥需要是您正在使用的密码的正确位数.对于那个56位的DES.在你走得太远之前,这里有一些你可能想要考虑的事情:

  1. 您应该使用更强大的加密标准,如AES.现在可以破解DES加密.
  2. 如果您想使用字符串作为键,那么您应该使用强大的哈希函数,如SHA-256对该键字符串.然后根据加密密钥需要从该散列输出中获取尽可能多的位,128位足以用于AES.你的钥匙串应该像你一样长.
  3. 最好使用块密码模式,每次都不会为同一输入生成相同的输出.有关信息,请参阅分组密码操作模式,并查看ECB模式为何不良的可视化.

以下是使用PKCS#5填充在CBC模式下使用128位AES加密的工作示例:

import java.security.MessageDigest;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class EncryptDecrypt {
    public static void main(String[] args) throws Exception {
        // here are your inputs
        String keyString = "averylongtext!@$@#$#@$#*&(*&}{23432432432dsfsdf";
        String input = "john doe";

        // setup AES cipher in CBC mode with PKCS #5 padding
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // setup an IV (initialization vector) that should be
        // randomly generated for each input that's encrypted
        byte[] iv = new byte[cipher.getBlockSize()];
        new SecureRandom().nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        // hash keyString with SHA-256 and crop the output to 128-bit for key
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(keyString.getBytes());
        byte[] key = new byte[16];
        System.arraycopy(digest.digest(), 0, key, 0, key.length);
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

        // encrypt
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(input.getBytes("UTF-8"));
        System.out.println("encrypted: " + new String(encrypted));

        // include the IV with the encrypted bytes for transport, you'll
        // need the same IV when decrypting (it's safe to send unencrypted)

        // decrypt
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        System.out.println("decrypted: " + new String(decrypted, "UTF-8"));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您以任何形式分发对称加密的私钥,则无法进行任何混淆或操纵以安全地隐藏它.这是默默无闻的安全性,有人可以提取密钥.听起来你可能需要的是像RSA或DSA这样的非对称加密.有了这些,您就拥有了一个公钥和一个私钥,您可以使用旨在安全地执行此操作的程序生成该密钥.您可以提供公钥,因此包含在您分发的jar中是安全的.只有您的私钥才能解密使用该公钥加密的任何输入. (2认同)

Rol*_*Boy 5

这是JDK doc的描述:

DESKeySpec
public DESKeySpec(byte[] key)
           throws InvalidKeyException
Creates a DESKeySpec object using the first 8 bytes in key as the key material for the DES key. 
The bytes that constitute the DES key are those between key[0] and key[7] inclusive. 

DESKeySpec仅使用byte []的前8个字节作为键.因此,在您的示例中,使用的实际键是相同的.