2010-08-13 5 views
4

현재 비밀번호를 인코딩 중입니다. 암호를 해독해야합니다. 다음은 인코딩 할 코드입니다. 원본 암호를 비교하려고합니다. MessageDigest에 대해 일방적 인 방법이라고 연구했습니다. 원본 메시지를받는 방법을 모릅니다. 우리는 디코드 방법을 가지고 있지만 원래 암호 인 Base64.decode를 제공하지 않습니다.MessageDigest, Base64로 디코딩하는 방법

public static synchronized String getMD5_Base64(String input) { 
     if (!isInited) { 
      isInited = true; 
      try { 
       digest = MessageDigest.getInstance("MD5"); 
      } catch (Exception ex) { 
      } 
     } 
     if (digest == null) 
      return input; 

     // now everything is ok, go ahead 
     try { 
      digest.update(input.getBytes("UTF-8")); 
     } catch (java.io.UnsupportedEncodingException ex) { 
     } 
     byte[] rawData = digest.digest(); 
     byte[] encoded = Base64.encode(rawData); 
     String retValue = new String(encoded); 
     return retValue; 
    } 
} 

답변

8

원래 암호를 가져올 수 없습니다. 다이제스트 및 Base64 인코딩은 완전히 다른 두 가지 작업을 수행합니다. MD5 다이제스트는 제공된 데이터의 암호화 해시를 만듭니다. 이것은 되돌릴 수 없습니다. Base64는 데이터 (인쇄 할 수없는 바이너리 데이터를 포함 할 수 있음)를 인쇄 가능한 문자 만 포함하도록 보장되는 문자열로 변환하는 인코딩 메커니즘입니다. 이 단계는 되돌릴 수 있습니다.

암호를 확인하는 표준 방법은 원래 암호를 디코딩하고 일반 텍스트를 비교하는 것이 아닙니다. 원래 암호에서 수행 한 인코딩 (MD5 해시 후 Base64 인 코드)을 취하여 새로 제공된 암호에 적용해야합니다. 그런 다음 저장된 인코딩 된 버전을 새로 인코딩 된 버전과 비교하십시오. 암호가 같으면 암호가 일치합니다.

이 디자인은 암호를 해독 할 수있는 것보다 더 안전한 메커니즘입니다. 이렇게하면 누군가가 귀하의 암호 데이터베이스를 도용하면 사용자의 모든 암호에 자동으로 액세스 할 수 없습니다. 시스템에 침입하기 위해서는 동일한 값으로 암호화 된 암호를 찾아야합니다. MD5와 같은 암호화 해시의 핵심은이를 매우 어렵게 만드는 것입니다. 반면에 MD5는 더 이상 안전한 해시로 간주되지 않습니다. SHA1 또는 SHA256을 사용하는 것이 더 나을 것입니다. 그러나 기존 암호를 원래 암호없이 MD5 해시에서 다른 해시로 변경할 수는 없습니다. 즉, 원래 암호를 변경하지 않아도됩니다. 저장된 암호의 데이터베이스).

+0

안녕 Jherico. 문제는 현재 암호에서 이전 암호의 연속 문자가 4 개가 아니므로 MD5 Base64의 패턴을 얻으려는 시도가 잘못되었다는 것입니다. 그래서 나는 원래 암호로 돌아가서 비교하려고 노력하고있었습니다. – Perry

+0

이전 암호를 해독하고 MD5를 새 암호로 만들고 MD5가 만든 내용을 비교하면 궁금합니다. 내가 어떻게해야하는지 잘 모르겠다. :) – Perry

+0

불가능합니다. 암호화 해시의 포인트는 모든 출력 비트가 모든 입력 비트의 영향을받을 수 있다는 것입니다.보유하고있는 데이터와 비교할 수있는 비교 방법은 없습니다. – Jherico

3

MD5 해시 알고리즘은 모든 해시 알고리즘과 마찬가지로 단방향입니다. 원래 암호를 복구하는 유일한 방법은 MD5 해시가 사용자가받은 것과 일치 할 때까지 모든 가능성을 시도하는 것입니다.

+2

이것은 (반드시) 원래 암호를 실제로 찾지는 않습니다. 오히려 해시 충돌을 발견하게 될 것입니다. 허락은 128 비트이고 일반적으로 사용되는 패스워드의 도메인 크기는 아마도 실제 패스워드를 찾았을 가능성이 거의 없기 때문에 가능합니다. – Jherico

1

새 암호의 내용을 이전 암호와 비교하려고하면 MD5 해시를 사용할 수 없습니다. Jherico가 지적했듯이, MD5 (및 모든 해시)는 원래 텍스트를 얻을 수 없다는 단방향 의미입니다.

비교를 수행하려면 암호의 원래 값을 어딘가에 유지해야합니다. 가장 좋은 방법은 데이터베이스에 저장하기 전에 암호화하여 결과를 base64하는 것입니다. 그런 다음 비교를 수행하기 위해 각각의 값을 해독하고 원하는 작업을 수행하십시오.

사용자의 암호를 되돌릴 수있는 모든 형식으로 저장하면 위험 할 수 있습니다.

5

MessageDigest with MD5는 편도 해시입니다. 따라서, 쉽게 암호화하고 해독 할 수있는 javax.crypto을 사용하지 마십시오. 다음은 그 예입니다.

import java.security.spec.KeySpec; 
import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.DESedeKeySpec; 
import org.apache.commons.codec.binary.Base64; 

public class EncryptDecrypt { 
    private static final String UNICODE_FORMAT = "UTF8"; 
    public static final String DESEDE_ENCRYPTION_SCHEME = "DESede"; 
    private KeySpec ks; 
    private SecretKeyFactory skf; 
    private Cipher cipher; 
    byte[] arrayBytes; 
    private String myEncryptionKey; 
    private String myEncryptionScheme; 
    SecretKey key; 

    public EncryptDecrypt() throws Exception { 
     myEncryptionKey = "ThisIsSpartaThisIsSparta"; 
     myEncryptionScheme = DESEDE_ENCRYPTION_SCHEME; 
     arrayBytes = myEncryptionKey.getBytes(UNICODE_FORMAT); 
     ks = new DESedeKeySpec(arrayBytes); 
     skf = SecretKeyFactory.getInstance(myEncryptionScheme); 
     cipher = Cipher.getInstance(myEncryptionScheme); 
     key = skf.generateSecret(ks); 
    } 


    public String encrypt(String unencryptedString) { 
     String encryptedString = null; 
     try { 
      cipher.init(Cipher.ENCRYPT_MODE, key); 
      byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT); 
      byte[] encryptedText = cipher.doFinal(plainText); 
      encryptedString = new String(Base64.encodeBase64(encryptedText)); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return encryptedString; 
    } 


    public String decrypt(String encryptedString) { 
     String decryptedText=null; 
     try { 
      cipher.init(Cipher.DECRYPT_MODE, key); 
      byte[] encryptedText = Base64.decodeBase64(encryptedString.getBytes()); 
      byte[] plainText = cipher.doFinal(encryptedText); 
      decryptedText= new String(plainText); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return decryptedText; 
    } 


    public static void main(String args []) throws Exception 
    { 
     EncryptDecrypt td= new EncryptDecrypt(); 

     String target="[email protected]"; 
     String encrypted=td.encrypt(target); 
     String decrypted=td.decrypt(encrypted); 

     System.out.println("String To Encrypt: "+ target); 
     System.out.println("Encrypted String: " + encrypted); 
     System.out.println("Decrypted String: " + decrypted); 

    } 
} 
관련 문제