[java] 비밀 키를 문자열로 또는 그 반대로 변환

키를 생성 중이며 DB에 저장해야하므로 문자열로 변환하지만 문자열에서 키를 다시 가져옵니다. 이를 수행하는 가능한 방법은 무엇입니까?

내 코드는

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

문자열에서 키를 어떻게 되 찾을 수 있습니까?



답변

SecretKey바이트 배열 ( byte[]) 로 변환 한 다음 Base64로 String. 다시 SecretKey, Base64 로 변환하려면 문자열을 디코딩하고 a SecretKeySpec에서 사용하여 원본을 다시 빌드합니다 SecretKey.

Java 8의 경우

문자열에 대한 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"); 

Java 7 이하 (Android 포함) :

참고 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;
}


답변

실제로 Luis가 제안한 것은 저에게 효과가 없었습니다. 나는 다른 방법을 찾아야했다. 이것이 나를 도왔습니다. 당신도 도울 수 있습니다. 연결:

  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");


답변

을 사용하고 싶지 않습니다 .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()stringSecretKeySpecBase64 객체 .

변환하는 동안 SecretKeySpecString: 사용 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;

} 


답변