Шифрование и дешифрование с использованием Java: невозможно получить одинаковый вывод - PullRequest
5 голосов
/ 02 апреля 2011

Я пытаюсь изучить и проверить API шифрования / дешифрования Java 1.6.Я хочу знать, что я делаю неправильно и чего мне не хватает с точки зрения знаний.

В следующем коде я создаю два шифра: один для шифрования и другой для расшифровки.Когда я использую эти шифры, я инициализирую их с другими ключами 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));

Ответы [ 3 ]

16 голосов
/ 02 апреля 2011

Добро пожаловать в шифрование! Как уже упоминалось, DES является симметричным и требует того же ключа для шифрования, что и для дешифрования. Этот ключ должен быть правильным количеством битов для шифра, который вы используете. Для DES это 56 бит. Прежде чем вы зайдете слишком далеко с этим, вот несколько вещей, которые вы могли бы рассмотреть:

  1. Вы должны использовать более строгий стандарт шифрования, такой как AES . Теперь можно нарушить шифрование DES .
  2. Если вы хотите использовать строку в качестве ключа, тогда вам следует использовать сильную хеш-функцию, такую ​​как SHA-256 против этой строки ключа. Затем возьмите столько битов из этого вывода хеша, сколько вам нужно для ключа шифрования, 128-бит достаточно для AES. Строка ключа должна быть такой же длинной, как у вас.
  3. Лучше всего использовать режим блочного шифра, который не генерирует один и тот же выход каждый раз для одного и того же ввода. См. режимы работы блочного шифра для получения информации и визуализации причин, по которым режим ECB плох.

Вот рабочий пример использования 128-битного шифрования AES в режиме CBC с заполнением PKCS # 5:

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"));
    }
}
5 голосов
/ 02 апреля 2011

Вот описание из документа JDK:

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 использует только первые 8 байтов байта [] в качестве ключа.Таким образом, используемые ключи в вашем примере идентичны.

0 голосов
/ 23 декабря 2013

Вот рабочий пример использования 56-битного шифрования DES.

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

public class CipherHelper {

    // Algorithm used
    private final static String ALGORITHM = "DES";

    /**
     * Encrypt data
     * @param secretKey -   a secret key used for encryption
     * @param data      -   data to encrypt
     * @return  Encrypted data
     * @throws Exception
     */
    public static String cipher(String secretKey, String data) throws Exception {
        // Key has to be of length 8
        if (secretKey == null || secretKey.length() != 8)
            throw new Exception("Invalid key length - 8 bytes key needed!");

        SecretKey key = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);

        return toHex(cipher.doFinal(data.getBytes()));
    }

    /**
     * Decrypt data
     * @param secretKey -   a secret key used for decryption
     * @param data      -   data to decrypt
     * @return  Decrypted data
     * @throws Exception
     */
    public static String decipher(String secretKey, String data) throws Exception {
        // Key has to be of length 8
        if (secretKey == null || secretKey.length() != 8)
            throw new Exception("Invalid key length - 8 bytes key needed!");

        SecretKey key = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);

        return new String(cipher.doFinal(toByte(data)));
    }

    // Helper methods

    private static byte[] toByte(String hexString) {
        int len = hexString.length()/2;

        byte[] result = new byte[len];

        for (int i = 0; i < len; i++)
            result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
        return result;
    }

    public static String toHex(byte[] stringBytes) {
        StringBuffer result = new StringBuffer(2*stringBytes.length);

        for (int i = 0; i < stringBytes.length; i++) {
            result.append(HEX.charAt((stringBytes[i]>>4)&0x0f)).append(HEX.charAt(stringBytes[i]&0x0f));
        }

        return result.toString();
    }

    private final static String HEX = "0123456789ABCDEF";

    // Helper methods - end

    /**
     * Quick test
     * @param args
     */
    public static void main(String[] args) {
        try {

            String secretKey    = "01234567";
            String data="test";
            String encryptedData = cipher(secretKey, data);

            System.out.println("encryptedData: " + encryptedData);

            String decryptedData = decipher(secretKey, encryptedData);

            System.out.println("decryptedData: " + decryptedData);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...