Преобразование секретного ключа в строку и наоборот
я генерирую ключ и должен хранить его в БД, поэтому я конвертирую его в строку, но чтобы получить ключ из строки. Каковы возможные пути достижения этой цели?
мой код,
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);
Как я могу получить ключ от строки?
6 ответов:
вы можете преобразовать
SecretKey
в байт-массив (byte[]
), затем Base64 кодирует это вString
. Чтобы преобразовать обратно вSecretKey
, Base64 декодирует строку и использует ее вSecretKeySpec
чтобы восстановить свой оригиналSecretKey
.Для Java 8
секретный ключ к строке:
// create new key SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey(); // get base64 encoded version of the key String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
String to 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):
Примечание. Я: вы можете пропустить часть кодирования/декодирования Base64 и просто сохранить
byte[]
в SQLite. Тем не менее, выполнение кодирования/декодирования Base64 не является дорогостоящей операцией, и вы можете хранить строки практически в любой БД без проблем.ПРИМЕЧАНИЕ II: более ранние версии Java не включают Base64 в один из
java.lang
илиjava.util
пакеты. Однако можно использовать кодеки из Apache Commons Codec,Надувной Замок или гуавы.секретный ключ к строке:
// 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)}
String to 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 (без зависимости от внутренних классов или внешних зависимостей):
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.безопасность.Ключ, который сам наследует от Сериализуемого. Таким образом, ключ здесь (без каламбура) состоит в том, чтобы сериализовать ключ в ByteArrayOutputStream, получить массив byte[] и сохранить его в БД. Обратный процесс будет заключаться в том, чтобы получить массив byte[] из БД, создать ByteArrayInputStream из массива byte[] и десериализовать секретный ключ от него...
... или еще проще, просто используйте элемент
.getEncoded()
метод наследуется от Java.безопасность.Ключ (который является родительским интерфейсом SecretKey). Этот метод возвращает закодированный массив byte[] off Key / SecretKey, который можно сохранить или извлечь из базы данных.Это все при условии, что ваша реализация SecretKey поддерживает кодирование. В противном случае,
getEncoded()
вернет null.edit:
вы должны посмотреть на ключ / SecretKey javadocs (доступно прямо в начале 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
На самом деле то, что предложил Луис, не сработало для меня. Я должен был придумать другой способ. Вот что мне помогло. Может и тебе помочь. Ссылки:
*.getEncoded(): https://docs.oracle.com/javase/7/docs/api/java/security/Key.html
информация кодировщика: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html
информация о декодере: 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 в строку и наоборот: вы можете использовать
getEncoded()
методSecretKeySpec
что дастbyteArray
, от этого вы можете использоватьencodeToString()
иstring
стоимостьюSecretKeySpec
на
попробуйте это, это работа без 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; }