키를 생성 중이며 DB에 저장해야하므로 문자열로 변환하지만 문자열에서 키를 다시 가져옵니다. 이를 수행하는 가능한 방법은 무엇입니까?
내 코드는
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);
문자열에서 키를 어떻게 되 찾을 수 있습니까?
키를 생성 중이며 DB에 저장해야하므로 문자열로 변환하지만 문자열에서 키를 다시 가져옵니다. 이를 수행하는 가능한 방법은 무엇입니까?
내 코드는
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);
문자열에서 키를 어떻게 되 찾을 수 있습니까?
답변:
를 SecretKey
바이트 배열 ( byte[]
) 로 변환 한 다음 Base64로 String
. 다시 SecretKey
, Base64 로 변환하려면 문자열을 디코딩하고 a SecretKeySpec
에서 사용하여 원본을 다시 빌드합니다 SecretKey
.
문자열에 대한 SecretKey :
// 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");
참고 I : Base64 인코딩 / 디코딩 부분을 건너 뛰고 byte[]
SQLite에 저장할 수 있습니다. 즉, Base64 인코딩 / 디코딩을 수행하는 것은 비용이 많이 드는 작업이 아니며 거의 모든 DB에 문제없이 문자열을 저장할 수 있습니다.
참고 II : 이전 Java 버전은 java.lang
또는 java.util
패키지 중 하나에 Base64를 포함하지 않습니다 . 그러나 Apache Commons Codec , Bouncy Castle 또는 Guava의 코덱을 사용할 수 있습니다 .
문자열에 대한 SecretKey :
// 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");
빠르게 실패 하는 일부 함수를 만드는 것이 얼마나 재미 있는지 보여주기 위해 다음 세 가지 함수를 작성했습니다.
하나는 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;
}
getEncoded()
사용할 수없는 다른 위치)에있는 경우 키 저장 / 검색이 작동 하지 않을 수 있습니다.
실제로 Luis가 제안한 것은 저에게 효과가 없었습니다. 나는 다른 방법을 찾아야했다. 이것이 나를 도왔습니다. 당신도 도울 수 있습니다. 연결:
* .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");
을 사용하고 싶지 않습니다 .toString()
.
SecretKey는 Serializable에서 상속되는 java.security.Key에서 상속됩니다. 따라서 여기서 핵심은 (말장난이 아님) 키를 ByteArrayOutputStream으로 직렬화하고 byte [] 배열을 가져 와서 db에 저장하는 것입니다. 반대 프로세스는 db에서 byte [] 배열을 가져오고, byte [] 배열의 ByteArrayInputStream을 만들고, SecretKey를 deserialize하는 것입니다.
... 또는 더 간단하게 .getEncoded()
java.security.Key (SecretKey의 부모 인터페이스)에서 상속 된 메서드를 사용하십시오 . 이 메서드는 데이터베이스에서 저장하거나 검색 할 수있는 Key / SecretKey에서 인코딩 된 byte [] 배열을 반환합니다.
이것은 모두 SecretKey 구현이 인코딩을 지원한다고 가정합니다. 그렇지 않으면 getEncoded()
null을 반환합니다.
Key / 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
SecretKeySpec을 String으로 또는 그 반대로 변환 :getEncoded()
in 값 을 가져 오는 데 사용할 수있는, SecretKeySpec
제공
하는 메서드를 byteArray
사용할 수 있습니다 .encodeToString()
string
SecretKeySpec
Base64
객체 .
변환하는 동안 SecretKeySpec
에 String
: 사용 decode()
에하는 Base64
줄 것이다 byteArray
, 그에서 당신을 위해 인스턴스를 만들 수 있습니다 SecretKeySpec
(가)로 PARAMS와 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;
}
String
키 객체와 바이트 배열을 지울 수있는 동안 Java에서 인스턴스 를 삭제하는 명시적인 방법은 없습니다 . 이는 키가 더 오랜 기간 동안 메모리 내에서 사용 가능한 상태를 유지할 수 있음을 의미합니다. (비밀번호 보호) 사용KeyStore
, 가급적 런타임 시스템 / OS 또는 하드웨어에 의해 지원되는 것이 선호되어야합니다.