Je génère une clé et je dois la stocker dans une base de données. Je la convertis donc en chaîne, mais je récupère la clé de la chaîne. Quels sont les moyens possibles pour y parvenir?
Mon code est,
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);
Comment puis-je récupérer la clé de la chaîne?
Vous pouvez convertir la variable SecretKey
en un tableau d'octets (byte[]
), puis l'encoder en Base64 en une variable String
. Pour reconvertir en une SecretKey
, Base64 décode la chaîne et l'utilise dans une SecretKeySpec
pour reconstruire votre SecretKey
d'origine.
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());
Chaîne vers 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");
NOTE I: vous pouvez ignorer la partie encodage/décodage Base64 et simplement stocker le byte[]
dans SQLite. Cela dit, le codage/décodage Base64 n’est pas une opération onéreuse et vous pouvez stocker des chaînes dans presque toutes les bases de données sans problème.
NOTE II: Les versions antérieures de Java n'incluent pas de Base64 dans l'un des packages Java.lang
ou Java.util
. Il est toutefois possible d’utiliser des codecs de Apache Commons Codec , Bouncy Castle ou Goyave .
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)}
Chaîne vers 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");
Pour montrer à quel point il est amusant de créer des fonctions qui sont échouent rapidement j'ai écrit les 3 fonctions suivantes.
On crée une clé AES, on la code et l’autre la décode. Ces trois méthodes peuvent être utilisées avec Java 8 (sans dépendance de classes internes ni de dépendances externes):
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;
}
Vous ne voulez pas utiliser .toString()
.
Notez que SecretKey hérite de Java.security.Key, qui hérite lui aussi de Serializable. Donc, la clé ici (sans jeu de mots) est de sérialiser la clé dans un ByteArrayOutputStream, d’obtenir le tableau byte [] et de le stocker dans la base de données. Le processus inverse consisterait à extraire le tableau byte [] de la base de données, à créer un ByteArrayInputStream offf le tableau byte [] et à désérialiser la clé secrète ...
... ou même plus simple, utilisez simplement la méthode .getEncoded()
héritée de Java.security.Key (qui est une interface parent de SecretKey). Cette méthode renvoie le tableau d'octets [] hors Key/SecretKey, que vous pouvez stocker ou extraire de la base de données.
Tout cela en supposant que votre implémentation SecretKey prenne en charge le codage. Sinon, getEncoded()
retournera null.
Vous devriez regarder les javadocs Key/SecretKey (disponibles au début d'une page Google):
http://download.Oracle.com/javase/6/docs/api/Java/security/Key.html
Ou ceci de CodeRanch (également trouvé avec la même recherche de Google):
http://www.coderanch.com/t/429127/Java/java/Convertion-between-SecretKey-String-or
Conversion de SecretKeySpec en String et inversement: Vous pouvez utiliser la méthode getEncoded()
dans SecretKeySpec
qui donnera byteArray
, à partir de laquelle vous pouvez utiliser encodeToString()
pour obtenir la valeur string
de SecretKeySpec
dans Base64
objet.
Lors de la conversion de SecretKeySpec
en String
: utiliser decode()
dans Base64
donnera byteArray
, à partir de laquelle vous pouvez créer une instance pour SecretKeySpec
avec les paramètres comme byteArray
pour reproduire votre 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");
En fait, ce que Luis a proposé n'a pas fonctionné pour moi. Je devais trouver un autre moyen. C'est ce qui m'a aidé. Pourrait vous aider aussi. Liens:
* .getEncoded (): https://docs.Oracle.com/javase/7/docs/api/Java/security/Key.html
Informations sur le codeur: https://docs.Oracle.com/javase/8/docs/api/Java/util/Base64.Encoder.html
Informations du décodeur: https://docs.Oracle.com/javase/8/docs/api/Java/util/Base64.Decoder.html
Extraits de code: Pour l'encodage:
String temp = new String(Base64.getEncoder().encode(key.getEncoded()));
Pour le décodage:
byte[] encodedKey = Base64.getDecoder().decode(temp);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES");