java - ejemplo - private jlabel
Conversión de clave secreta en una cadena y viceversa (6)
En realidad, lo que Luis propuso no funcionó para mí. Tuve que encontrar otra manera. Esto es lo que me ayudó. Podría ayudarte también. Campo de golf:
* .getEncoded (): https://docs.oracle.com/javase/7/docs/api/java/security/Key.html
Información del codificador: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html
Información del decodificador: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html
Fragmentos de código: para la codificación:
String temp = new String(Base64.getEncoder().encode(key.getEncoded()));
Para la decodificación:
byte[] encodedKey = Base64.getDecoder().decode(temp);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES");
Estoy generando una clave y necesito almacenarla en DB, así que la convierto en una Cadena, pero para recuperar la clave de la Cadena. ¿Cuáles son las formas posibles de lograr esto?
Mi código es,
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);
¿Cómo puedo recuperar la clave de String?
No desea usar .toString()
.
Observe que SecretKey hereda de java.security.Key, que a su vez hereda de Serializable. Así que la clave aquí (sin juego de palabras) es serializar la clave en ByteArrayOutputStream, obtener la matriz byte [] y almacenarla en la base de datos. El proceso inverso sería sacar la matriz byte [] de la base de datos, crear una estructura ByteArrayInputStream de la matriz byte [] y deserializar la clave secreta fuera de ella ...
... o incluso más simple, solo use el método .getEncoded()
heredado de java.security.Key (que es una interfaz principal de SecretKey). Este método devuelve el byte codificado [] array de Key / SecretKey, que puede almacenar o recuperar de la base de datos.
Todo esto supone que su implementación de SecretKey admite la codificación. De lo contrario, getEncoded()
devolverá nulo.
editar:
Debería ver los javadocs Key / SecretKey (disponibles al inicio de una página de google):
http://download.oracle.com/javase/6/docs/api/java/security/Key.html
O esto de CodeRanch (también encontrado con la misma búsqueda de Google):
http://www.coderanch.com/t/429127/java/java/Convertion-between-SecretKey-String-or
Para mostrar lo divertido que es crear algunas funciones que fallan rápidamente , he escrito las siguientes 3 funciones.
Uno crea una clave AES, una la codifica y otra la descifra. Estos tres métodos se pueden usar con Java 8 (sin dependencia de clases internas o dependencias externas):
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;
}
Puede convertir la SecretKey
en una matriz de bytes ( byte[]
), luego Base64 codificar eso en una String
. Para convertir de nuevo a un SecretKey
, Base64 decodifica el String y lo usa en un SecretKeySpec
para reconstruir su SecretKey
original.
Para 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());
Cadena a 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");
Para Java 7 y versiones anteriores (incluido Android):
NOTA I: puede omitir la parte de codificación / decodificación Base64 y simplemente almacenar el byte[]
en SQLite. Dicho esto, realizar codificación / decodificación Base64 no es una operación costosa y puede almacenar cadenas en casi cualquier base de datos sin problemas.
NOTA II: Las versiones anteriores de Java no incluyen un Base64 en uno de los paquetes java.lang
o java.util
. Sin embargo, es posible usar códecs de Apache Commons Codec , Bouncy Castle o 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)}
Cadena a 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");
intente esto, es trabajo sin Base64 (que se incluye solo en JDK 1.8), este código se ejecuta también en la versión anterior de 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;
}
Convirtiendo SecretKeySpec en Cadena y viceversa: puede usar el método getEncoded()
en SecretKeySpec
que dará byteArray
, desde allí puede usar encodeToString()
para obtener el valor de string
de SecretKeySpec
en el objeto Base64
.
Al convertir SecretKeySpec
en String
: use decode()
en Base64
obtendrá byteArray
, desde allí se puede crear una instancia para SecretKeySpec
con los params como byteArray
para reproducir su 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");