Преобразование секретного ключа в строку и наоборот

Я генерирую ключ и должен хранить его в БД, поэтому я конвертирую его в String, но возвращаю ключ из строки. Каковы возможные пути достижения этого?

Мой код,

SecretKey key = KeyGenerator.getInstance("AES").generateKey(); String stringKey=key.toString(); System.out.println(stringKey); 

Как я могу вернуть ключ из строки?

Вы можете преобразовать SecretKey в массив байтов ( byte[] ), затем Base64 кодирует это в String . Чтобы преобразовать обратно в SecretKey , Base64 декодирует String и использует его в SecretKeySpec для восстановления оригинального SecretKey .

Для Java 8

SecretKey to String:

 // create new key SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); // get base64 encoded version of the key String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded()); 

Строка в SecretKey:

 // decode the base64 encoded string byte[] decodedKey = Base64.getDecoder().decode(encodedKey); // rebuild key using SecretKeySpec SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); 

Для Java 7 и до (включая Android):

ПРИМЕЧАНИЕ. I: вы можете пропустить часть кодировки / декодирования Base64 и просто сохранить byte[] в SQLite. При этом выполнение кодирования / декодирования Base64 не является дорогостоящей операцией, и вы можете хранить строки почти в любой БД без проблем.

ПРИМЕЧАНИЕ. Предыдущие версии Java не include Base64 в один из пакетов java.lang или java.util . Однако можно использовать кодеки из Apache Commons Codec , Bouncy Castle или Guava .

SecretKey to String:

 // CREATE NEW KEY // GET ENCODED VERSION OF KEY (THIS CAN BE STORED IN A DB) SecretKey secretKey; String stringKey; try {secretKey = KeyGenerator.getInstance("AES").generateKey();} catch (NoSuchAlgorithmException e) {/* LOG YOUR EXCEPTION */} if (secretKey != null) {stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT)} 

Строка в SecretKey:

 // DECODE YOUR BASE64 STRING // REBUILD KEY USING SecretKeySpec byte[] encodedKey = Base64.decode(stringKey, Base64.DEFAULT); SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); 

Чтобы показать, насколько интересно создавать некоторые функции, которые работают быстро, я написал следующие 3 функции.

Один создает ключ AES, один кодирует его и один декодирует. Эти три метода могут использоваться с Java 8 (вне зависимости от внутренних classов или внешних зависимостей):

 public static SecretKey generateAESKey(int keysize) throws InvalidParameterException { try { if (Cipher.getMaxAllowedKeyLength("AES") < keysize) { // this may be an issue if unlimited crypto is not installed throw new InvalidParameterException("Key size of " + keysize + " not supported in this runtime"); } final KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(keysize); return keyGen.generateKey(); } catch (final NoSuchAlgorithmException e) { // AES functionality is a requirement for any Java SE runtime throw new IllegalStateException( "AES should always be present in a Java SE runtime", e); } } public static SecretKey decodeBase64ToAESKey(final String encodedKey) throws IllegalArgumentException { try { // throws IllegalArgumentException - if src is not in valid Base64 // scheme final byte[] keyData = Base64.getDecoder().decode(encodedKey); final int keysize = keyData.length * Byte.SIZE; // this should be checked by a SecretKeyFactory, but that doesn't exist for AES switch (keysize) { case 128: case 192: case 256: break; default: throw new IllegalArgumentException("Invalid key size for AES: " + keysize); } if (Cipher.getMaxAllowedKeyLength("AES") < keysize) { // this may be an issue if unlimited crypto is not installed throw new IllegalArgumentException("Key size of " + keysize + " not supported in this runtime"); } // throws IllegalArgumentException - if key is empty final SecretKeySpec aesKey = new SecretKeySpec(keyData, "AES"); return aesKey; } catch (final NoSuchAlgorithmException e) { // AES functionality is a requirement for any Java SE runtime throw new IllegalStateException( "AES should always be present in a Java SE runtime", e); } } public static String encodeAESKeyToBase64(final SecretKey aesKey) throws IllegalArgumentException { if (!aesKey.getAlgorithm().equalsIgnoreCase("AES")) { throw new IllegalArgumentException("Not an AES key"); } final byte[] keyData = aesKey.getEncoded(); final String encodedKey = Base64.getEncoder().encodeToString(keyData); return encodedKey; } 

Вы не хотите использовать .toString() .

Обратите внимание, что SecretKey наследует от java.security.Key, который сам наследует Serializable. Итак, ключ здесь (не каламбур) состоит в том, чтобы сериализовать ключ в ByteArrayOutputStream, получить массив byte [] и сохранить его в db. Обратный процесс будет состоять в том, чтобы получить массив byte [] с db, создать ByteArrayInputStream из массива byte [] и десериализовать SecretKey от него …

… или даже проще, просто используйте метод .getEncoded() унаследованный от java.security.Key (который является родительским интерфейсом SecretKey). Этот метод возвращает закодированный массив byte [] из Key / SecretKey, который вы можете сохранить или получить из базы данных.

Это все предполагает, что реализация SecretKey поддерживает кодирование. В противном случае getEncoded() вернет значение null.

редактировать:

Вы должны посмотреть javadocs Key / SecretKey (ansible прямо в начале страницы google):

http://download.oracle.com/javase/6/docs/api/java/security/Key.html

Или это из CodeRanch (также найденного с тем же поиском google):

http://www.coderanch.com/t/429127/java/java/Convertion-between-SecretKey-String-or

На самом деле то, что предложил Луис, для меня не сработало. Мне нужно было выяснить другой путь. Это помогло мне. Могу вам помочь. Ссылки:

  1. * .getEncoded (): https://docs.oracle.com/javase/7/docs/api/java/security/Key.html

  2. Информация о кодировщике: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html

  3. Информация о декодере: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html

Фрагменты кода: для кодирования:

 String temp = new String(Base64.getEncoder().encode(key.getEncoded())); 

Для декодирования:

 byte[] encodedKey = Base64.getDecoder().decode(temp); SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES"); 

Преобразование SecretKeySpec в String и наоборот: вы можете использовать метод getEncoded() в byteArray , который даст byteArray , из которого вы можете использовать encodeToString() чтобы получить string значение SecretKeySpec в объекте Base64 .

Преобразование SecretKeySpec в String : использование decode() в Base64 даст byteArray , из которого вы можете создать экземпляр для SecretKeySpec с параметрами в качестве byteArray для воспроизведения вашего SecretKeySpec .

 String mAesKey_string; SecretKeySpec mAesKey= new SecretKeySpec(secretKey.getEncoded(), "AES"); //SecretKeySpec to String byte[] byteaes=mAesKey.getEncoded(); mAesKey_string=Base64.encodeToString(byteaes,Base64.NO_WRAP); //String to SecretKeySpec byte[] aesByte = Base64.decode(mAesKey_string, Base64.NO_WRAP); mAesKey= new SecretKeySpec(aesByte, "AES"); 

попробуйте это, это работает без Base64 (который включен только в JDK 1.8), этот код запускается также в предыдущей версии java 🙂

 private static String SK = "Secret Key in HEX"; // To Encrupt public static String encrypt( String Message ) throws Exception{ byte[] KeyByte = hexStringToByteArray( SK); SecretKey k = new SecretKeySpec(KeyByte, 0, KeyByte.length, "DES"); Cipher c = Cipher.getInstance("DES","SunJCE"); c.init(1, k); byte mes_encrypted[] = cipher.doFinal(Message.getBytes()); String MessageEncrypted = byteArrayToHexString(mes_encrypted); return MessageEncrypted; } // To Decrypt public static String decrypt( String MessageEncrypted )throws Exception{ byte[] KeyByte = hexStringToByteArray( SK ); SecretKey k = new SecretKeySpec(KeyByte, 0, KeyByte.length, "DES"); Cipher dcr = Cipher.getInstance("DES","SunJCE"); dc.init(Cipher.DECRYPT_MODE, k); byte[] MesByte = hexStringToByteArray( MessageEncrypted ); byte mes_decrypted[] = dcipher.doFinal( MesByte ); String MessageDecrypeted = new String(mes_decrypted); return MessageDecrypeted; } public static String byteArrayToHexString(byte bytes[]){ StringBuffer hexDump = new StringBuffer(); for(int i = 0; i < bytes.length; i++){ if(bytes[i] < 0) { hexDump.append(getDoubleHexValue(Integer.toHexString(256 - Math.abs(bytes[i]))).toUpperCase()); }else { hexDump.append(getDoubleHexValue(Integer.toHexString(bytes[i])).toUpperCase()); } return hexDump.toString(); } public static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return data; } 
  • Когда мне понадобится SecureString в .NET?
  • Шифрование / расшифровка classа NSData-AES в cocoa
  • Шифрование с несколькими разными ключами?
  • Хранение зашифрованных данных в Postgres
  • SQLite с защитой от шифрования / паролей
  • Быстрое и простое строковое шифрование / расшифровка в JAVA
  • Как расшифровать зашифрованную строку AES-256 из CryptoJS с помощью Java?
  • mcrypt устарел, какова альтернатива?
  • Java, Как реализовать Shift Cipher (Цезарский шифр)
  • Как зашифровать файл с SD-карты с помощью AES на Android?
  • «Заполнение недопустимо и не может быть удалено» с помощью AesManaged
  • Давайте будем гением компьютера.