Простой способ сохранить / восстановить ключ шифрования для расшифровки строки в Java - PullRequest
15 голосов
/ 18 декабря 2009

Для шифрования я использую что-то вроде этого:

SecretKey aesKey = KeyGenerator.getInstance("AES").generateKey();
StringEncrypter aesEncrypt = new StringEncrypter(aesKey, aesKey.getAlgorithm());
String aesEncrypted= aesEncrypt.encrypt(StringContent);

Если я распечатываю aesKey, я получаю: "javax.crypto.spec.SecretKeySpec@1708d".

Так что для шифрования я бы хотел попросить у пользователя ключ, но не знаю, как и в каком формате он должен быть. Мой план был примерно таким:

SecretKey aesKey = javax.crypto.spec.SecretKeySpec@1708d;
StringEncrypter aesEncrypt = new StringEncrypter(aesKey, aesKey.getAlgorithm());
String aesDecrypt = aesEncrypt.decrypt(aesEncrypted);

Но, похоже, это не работает. Есть ли какой-нибудь простой способ распечатать ключ после шифрования на консоли, чтобы пользователь мог сохранить его (или запомнить), а затем использовать для расшифровки?

Весь код здесь: Невозможно расшифровать зашифрованный текст из текстового файла, реализовать симметричный ключ. в Яве Так что извините за повторную публикацию, но я не уверен, что код читабелен (я новичок).

Ответы [ 4 ]

21 голосов
/ 24 августа 2011

Мне недавно пришлось сделать это самому. И хотя другие ответы здесь привели меня в правильном направлении, это могло бы быть проще. Итак, вот моя «доля» на этот день, пара вспомогательных методов для простого манипулирования ключами AES. (Обратите внимание на зависимость от Apache Commons и Codec.)

Теперь все это в git-репо: github.com / stuinzuri / SimpleJavaKeyStore

import static org.apache.commons.codec.binary.Hex.*;
import static org.apache.commons.io.FileUtils.*;
import java.io.*;
import java.security.NoSuchAlgorithmException;
import javax.crypto.*;
import org.apache.commons.codec.DecoderException;

public static SecretKey generateKey() throws NoSuchAlgorithmException
{
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    keyGenerator.init(256); // 128 default; 192 and 256 also possible
    return keyGenerator.generateKey();
}

public static void saveKey(SecretKey key, File file) throws IOException
{
    char[] hex = encodeHex(key.getEncoded());
    writeStringToFile(file, String.valueOf(hex));
}

public static SecretKey loadKey(File file) throws IOException
{
    String data = new String(readFileToByteArray(file));
    byte[] encoded;
    try {
        encoded = decodeHex(data.toCharArray());
    } catch (DecoderException e) {
        e.printStackTrace();
        return null;
    }
    return new SecretKeySpec(encoded, "AES");
}
14 голосов
/ 18 декабря 2009

Большинство экземпляров Java Key представлены в виде строки байтов, полученной в результате их метода getEncoded(). Это то, что нужно сохранить, чтобы позже восстановить ключ.

Однако для безопасного хранения ключа в электронном виде он должен быть зашифрован. Конечно, для шифрования ключа потребуется другой ключ (или пароль) & hellip; и поэтому у вас есть бесконечный регресс. Java KeyStore может использоваться для хранения SecretKey объектов таким способом, и это полезно, когда у вас есть много секретных ключей, которые все защищены одним «главным» паролем. Но для защиты одного ключа это не имеет большого смысла.

Одной из альтернатив является предоставление пользователю ключа в форме, которая может быть сохранена безопасным способом (во многих приложениях, которые могут быть на бумажке в кошельке). Это может быть так же просто, как отобразить байты ключа, закодированного в шестнадцатеричном, Base-64 или другом текстовом кодировании, и попросить пользователя записать его.

Другой подход заключается в том, чтобы позволить пользователю выбрать запоминающийся пароль и с его помощью сгенерировать ключ, используя алгоритм типа PBKDF2. Соль (и, возможно, счетчик итераций), используемая для получения ключа, должна быть где-то записана. Другим недостатком является то, что люди склонны выбирать из относительно ограниченного количества паролей из общего числа доступных. Таким образом, ключи, полученные из паролей, могут быть легче угадать, чем предполагает размер ключа.


Вот иллюстрация основного метода сохранения и восстановления секретного ключа.

byte[] encoded = aesKey.getEncoded();
/* Now store "encoded" somewhere. For example, display the key and 
   ask the user to write it down. */
String output = Base64.getEncoder().withoutPadding().encodeToString(encoded);
System.out.println("Keep it secret, keep it safe! " + output);

...

/* At some point, you need to reconstitute the key. Let's say the user 
   enters it as a base-64 number that you convert to bytes. */
String input = ... ;
byte[] encoded = Base64.getDecoder().decode(input);
SecretKey aesKey = new SecretKeySpec(encoded, "AES");
4 голосов
/ 18 декабря 2009

Я сохранил ключи в файлах хранилища ключей Java.Вот статья, которая может вам помочь

http://www.informit.com/articles/article.aspx?p=170967&seqNum=3

0 голосов
/ 18 декабря 2009

Просто для справки: результат, который вы видите, является результатом метода toString по умолчанию, а смешное число в конце - хеш-код. Смотрите здесь . Хэш-коды по своей конструкции необратимы, и toString не обязательно гарантирует, что вы получите достаточно информации для восстановления исходного объекта (хотя это и происходит для определенных классов).

...