Как я могу преобразовать строку в SecretKey - PullRequest
10 голосов
/ 29 декабря 2010

Я хочу конвертировать String в secretKey

public void generateCode(String keyStr){ 
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
secretKey skey=keyStr;  //How can I make the casting here
//SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
}

Я пытаюсь использовать BASE64Decoder вместо secretKey, но я сталкиваюсь с проблемой, которая заключается в том, что я не могу указать длину ключа.

EDIT: Я хочу вызвать эту функцию из другого места

 static public String encrypt(String message , String key , int keyLength) throws Exception {
     // Get the KeyGenerator
   KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(keyLength); // 192 and 256 bits may not be available
    // Generate the secret key specs.
     SecretKey skey = key; //here is the error
   byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    // Instantiate the cipher
    Cipher cipher = Cipher.getInstance("AES");

    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    System.out.println("msg is" + message + "\n raw is" + raw);
    byte[] encrypted = cipher.doFinal(message.getBytes());
    String cryptedValue = new String(encrypted);
    System.out.println("encrypted string: " + cryptedValue);
    return cryptedValue;
}

Если бы кто-нибудь мог помочь, я был бы очень благодарен.

Ответы [ 2 ]

37 голосов
/ 12 января 2012

Нет проверки целостности, по этим конкретным причинам

  1. Необходимость не очевидна из варианта использования.
  2. "AES/GCM/NoPadding" Режим доступен только изJava 7 и выше
  3. От пользователя зависит, хотят ли они развернуть, например, HMAC и / или AESCMAC (рекомендуется).
  4. Для этого потребуется как минимум дополнительный ключ и два полных прохода.

Если у вас есть реализация режима GCM с обеих сторон - например, с помощью Bouncy Castle на Java 6 - пожалуйста, сделайте это, так как он намного более безопасен (если «IV» действительноуникальный).Изменение реализации должно быть действительно простым.

Замечания по реализации, касающиеся шифрования

  1. Эта реализация небезопасна при использовании в неограниченной роли клиент / сервер, посколькуатак оракулового отступа (в среднем требуется 128 попыток на байт или меньше, независимо от алгоритма или размера ключа).Вам нужно будет использовать MAC, HMAC или Signature поверх зашифрованных данных и проверить их перед расшифровкой, чтобы развернуть их в режиме клиент / сервер.
  2. Decrypt вернет ноль, если расшифровка не удалась.Это может указывать только на исключение заполнения, которое должно быть надлежащим образом обработано (предупреждал ли я о нападениях оракула заполнения)
  3. Недопустимые ключи будут возвращены как InvalidArgumentException.
  4. Все другие исключения, связанные с безопасностью"подметаются под таблицей", поскольку это означает, что среда выполнения Java недопустима.Например, поддержка "UTF-8" и "AES/CBC/PKCS5Padding" требуется для каждой реализации Java SE.

Некоторые другие примечания

  1. Пожалуйста, не пытайтесь делать обратное и вставляйте байты непосредственно во входную строку метода шифрования (например, используя new String(byte[])).Метод может молча завершиться сбоем!
  2. Оптимизирован для удобства чтения.Если вам больше нравятся скорость и лучший объем памяти, перейдите к реализации потока Base64 и CipherStream.
  3. Для запуска этого кода требуется по крайней мере Java 6 SE или совместимый.
  4. Шифрование / дешифрование может завершиться неудачей для ключей AES размером более 128 бит, так как вам может нужны файлы политик для неограниченного шифрования (доступно в Oracle)
  5. Остерегайтесь правительственных правил при экспорте шифрования.
  6. Эта реализация использует шестнадцатеричные ключи вместо ключей base64, так как они достаточно малы, а шестнадцатеричный код легче редактировать / проверять вручную.
  7. Используется кодирование / декодирование шестнадцатеричного и base64, извлеченного из JDK, без внешних библиотекнужно что бы то ни было.
  8. Uber прост в использовании, но, конечно, не очень объектно-ориентирован, нет кэширования экземпляров объектов, используемых при шифровании / дешифровании.Рефакторинг по желанию.

ОК, вот код ...

    public static String encrypt(final String plainMessage,
            final String symKeyHex) {
        final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);

        final byte[] encodedMessage = plainMessage.getBytes(Charset
                .forName("UTF-8"));
        try {
            final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            final int blockSize = cipher.getBlockSize();

            // create the key
            final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

            // generate random IV using block size (possibly create a method for
            // this)
            final byte[] ivData = new byte[blockSize];
            final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
            rnd.nextBytes(ivData);
            final IvParameterSpec iv = new IvParameterSpec(ivData);

            cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

            final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

            // concatenate IV and encrypted message
            final byte[] ivAndEncryptedMessage = new byte[ivData.length
                    + encryptedMessage.length];
            System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
            System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                    blockSize, encryptedMessage.length);

            final String ivAndEncryptedMessageBase64 = DatatypeConverter
                    .printBase64Binary(ivAndEncryptedMessage);

            return ivAndEncryptedMessageBase64;
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException(
                    "key argument does not contain a valid AES key");
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException(
                    "Unexpected exception during encryption", e);
        }
    }

    public static String decrypt(final String ivAndEncryptedMessageBase64,
            final String symKeyHex) {
        final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);

        final byte[] ivAndEncryptedMessage = DatatypeConverter
                .parseBase64Binary(ivAndEncryptedMessageBase64);
        try {
            final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            final int blockSize = cipher.getBlockSize();

            // create the key
            final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

            // retrieve random IV from start of the received message
            final byte[] ivData = new byte[blockSize];
            System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
            final IvParameterSpec iv = new IvParameterSpec(ivData);

            // retrieve the encrypted message itself
            final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                    - blockSize];
            System.arraycopy(ivAndEncryptedMessage, blockSize,
                    encryptedMessage, 0, encryptedMessage.length);

            cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

            final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

            // concatenate IV and encrypted message
            final String message = new String(encodedMessage,
                    Charset.forName("UTF-8"));

            return message;
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException(
                    "key argument does not contain a valid AES key");
        } catch (BadPaddingException e) {
            // you'd better know about padding oracle attacks
            return null;
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException(
                    "Unexpected exception during decryption", e);
        }
    }

Использование:

    String plain = "Zaphod's just zis guy, ya knöw?";
    String encrypted = encrypt(plain, "000102030405060708090A0B0C0D0E0F");
    System.out.println(encrypted);
    String decrypted = decrypt(encrypted, "000102030405060708090A0B0C0D0E0F");
    if (decrypted != null && decrypted.equals(plain)) {
        System.out.println("Hey! " + decrypted);
    } else {
        System.out.println("Bummer!");
    }
3 голосов
/ 06 февраля 2015

Вот версия, использующая класс Base64 Util вместо DatatypeConverter

public static String encrypt(final String plainMessage,
                             final String symKeyHex) {
    final byte[] symKeyData = Base64.decode(symKeyHex,Base64.DEFAULT);

    final byte[] encodedMessage = plainMessage.getBytes(Charset
            .forName("UTF-8"));
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        final String ivAndEncryptedMessageBase64 = Base64.encodeToString(ivAndEncryptedMessage,Base64.DEFAULT);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    }
}

public static String decrypt(final String ivAndEncryptedMessageBase64,
                             final String symKeyHex) {
    final byte[] symKeyData = Base64.decode((symKeyHex),Base64.DEFAULT);

    final byte[] ivAndEncryptedMessage = Base64.decode(ivAndEncryptedMessageBase64,Base64.DEFAULT);
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    }
}

Просто напоминание для тех, кто получает исключение Padding.Убедитесь, что вы используете правильную длину ключа.Подсказка: посмотрите на пост Мартена: его гекс ровно 32;) Это не случайно:)

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