2014-04-25 4 views
0

PBKDF2WithHmacSHA1을 사용하는 Java 응용 프로그램의 데이터를 해독해야합니다. 자바 코드에 대한 제어권이 없지만 소스 사본이 있습니다. from java to C# PBKDF2WithHmacSHA1 채우기가 잘못되어 제거 할 수 없습니다.

내가이 예를 기반으로 한는 C# 부분

: http://steelmon.wordpress.com/2013/07/01/simple-interoperable-encryption-in-java-and-net/ 나는 C#을에서 암호화/해독,하지만 C#에서 암호를 해독 할 때, 그때는 "패딩이 유효 제거 할 수 없습니다 얻을 경우 그것은 잘 작동합니다. " 예외 ..

내가 찾은 모든 관련 예제를 시도했다. 소금과 키가 자바와 C#에서 동일하다는 것을 확인했다. 양쪽에서 PBKDF2를 사용하고 있고 내가 생각할 수있는 다른 것이 있는지 확인했다.

소금 : cdWSu23E9BLbNXWUTnrznFgc

키 gygp6yevKWKBUwFy4GXpuFwT

다음

자바 코드 : 여기

public class Cryption { 
private static int KEYLEN_BITS = 256; 
private static int ITERATIONS = 128; 

static private Log log = LogFactory.getLog(Cryption.class);  

private static SecretKeyFactory secretKeyFactory = null; 
private static Map<String, SecretKey> secretKeyMap = new HashMap<String, SecretKey>(); 

private String password = null; 
private SecretKey secretKey = null; 
private Cipher cipher = null; 

private synchronized static SecretKeyFactory createSecretKeyFactory() { 
    try { 
     if(secretKeyFactory == null) {      
      secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");   
     }  
    } catch(Exception e) { 
     log.error("createSecretKeyFactory", e); 
    } 
    return secretKeyFactory; 
} 

private static SecretKey createSecretKey(String password, byte []salt) { 
    SecretKey secretKey = secretKeyMap.get(password); 
    if(secretKey == null) { 
     try { 
      KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, KEYLEN_BITS); 
      SecretKey tmpSecretKey = createSecretKeyFactory().generateSecret(spec); 
      secretKey = new SecretKeySpec(tmpSecretKey.getEncoded(), "AES"); 
      secretKeyMap.put(password, secretKey); 
     } catch(Exception e) { 
      log.error("getSecretKey", e); 
     } 
    } 
    return secretKey; 
} 

private boolean createCipher(String password, byte []salt, byte[] iv, int mode) { 
    try { 
     this.password = password; 
     secretKey = createSecretKey(password, salt);  
     cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     if(iv != null) { 
      cipher.init(mode, secretKey, new IvParameterSpec(iv)); 
     } else { 
      cipher.init(mode, secretKey);    
     } 
    } catch(Exception e) { 
     log.error("getCipher", e); 
     return false; 
    } 
    return true; 
} 

public String getPassword() { 
    return password; 
} 

public byte[] getCipherIV() { 
    byte [] iv = null; 

    try {  
     AlgorithmParameters params = cipher.getParameters(); 
     iv = params.getParameterSpec(IvParameterSpec.class).getIV(); 
    } catch(Exception e) { 
     log.error("getCipherIV", e); 
    } 
    return iv; 
} 

public byte[] execute(byte []in) { 
    byte [] out = null; 

    try {  
     out = cipher.doFinal(in); 
    } catch(Exception e) { 
     log.error("execute", e); 
    } 
    return out; 
} 

static Cryption create(String password, byte[] salt, byte[] iv, int mode) { 
    Cryption cryption = new Cryption(); 

    cryption.createCipher(password, salt, iv, mode); 
    return cryption; 
} 

static void init(Cryption cryption, byte[] iv, int mode) { 
    try {  
     if(iv != null) { 
      cryption.cipher.init(mode, cryption.secretKey, new IvParameterSpec(iv)); 
     } else { 
      cryption.cipher.init(mode, cryption.secretKey);    
     } 
    } catch(Exception e) { 
     log.error("init", e); 
    } 
} 
} 

그리고 내가

 private void btnDecrypt_Click(object sender, EventArgs e) 
    { 
     byte[] salt = Encoding.UTF8.GetBytes("cdWSu23E9BLbNXWUTnrznFgc"); 
     int iterations = 128; 
     Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes("gygp6yevKWKBUwFy4GXpuFwT", salt, iterations); 
     byte[] key = rfc2898.GetBytes(24); 


     AesManaged aesCipher = new AesManaged(); 
     aesCipher.KeySize = 256; 
     aesCipher.BlockSize = 128; 
     aesCipher.Mode = CipherMode.CBC; 
     aesCipher.Padding = PaddingMode.PKCS7; 
     aesCipher.Key = key; 

     String cipherB64 = "cFSGQv/mEnzaU9fAKIyFTvlIMxKnN8yRgzXm/E7MLoBF3g8iE6tloBcI84po+cT3r2Yz+wothDhYoM02yppPLHcv8Mj0FLF3frtAlOGq3TormcbwmSzx3JdB+GtFtliZkxNCyeTiGWi3jqnHsTRo7G3lQPEEUXEt03kFjErZfqEf8IwcD+PNqwtsU1fCn0gNgVvcvJck795U304QfDCOfkVEjNomGhbz4hTy4HPgokXUSWOEQEihTjz3j70+JZvLhsYGRnIxmRad8gsn7sVBr8vfG9KnL8i1CUh9vKuGLjiZCIhz7r00j4bmQYrjoj9yoKJmPVQsxW7FfTnOJFwlYw=="; 
     String ivB64 = "wWJLcuahcy4ZLLkW6CIqaA=="; 
     byte[] cipherText = Convert.FromBase64String(cipherB64); 
     aesCipher.IV = Convert.FromBase64String(ivB64); 

     ICryptoTransform decryptTransform = aesCipher.CreateDecryptor(); 
     byte[] plainText = decryptTransform.TransformFinalBlock(cipherText, 0, cipherText.Length); 
     txtOutput.Text = System.Text.Encoding.UTF8.GetString(plainText); 
    } 

답변

0

자바와 C#의 암호에 정확히 같은 입력을 사용하는 것은 의심 스럽습니다. 우선 #에 생성 한 키는 24 바이트 (196 비트)이지만 256의 키 크기를 지정하십시오. 권리.

 Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes("gygp6yevKWKBUwFy4GXpuFwT", salt, iterations); 
>>> byte[] key = rfc2898.GetBytes(24);  

    AesManaged aesCipher = new AesManaged(); 
>>> aesCipher.KeySize = 256; 
    aesCipher.BlockSize = 128; 
    aesCipher.Mode = CipherMode.CBC; 
    aesCipher.Padding = PaddingMode.PKCS7; 
>>> aesCipher.Key = key; 

는 모두 자바 ( tmpSecretKey.getEncoded()의 바이트)와 C#을 ( byte[] key의 값)과 비교에 생성 된 키에서 원시 인쇄를 수행합니다. 일치하지만 여전히 일치하지 않는 경우 암호화 할 데이터의 iv 및 바이트 값과 동일하게 작업하십시오.

+0

당신은 남자입니다! 나는 그 (DOH!)를 놓쳐 버리기 위해 눈이 멀었을 것임에 틀림 없다 는 32 바이트의 키를 바꿨다. 그리고 그것은 예상대로 작동한다. – user3572984

0

암호화는 암호 해독에 사용하는 C# 코드입니다 매개 변수가 일치하지 않으면 실패하도록 설계되었습니다. 암호화와 암호 해독 방법 모두에 대해 의 모든 입력이 동일한 지 확인해야합니다. 이것은 Base64 문자를 검사하는 것이 아니라 두 가지 주요 생성 방법 및 IV 변환의 byte[] 출력을 확인하는 것입니다. 바이트 배열은 비트와 정확히 일치해야합니다. 단일 비트 오류조차도 암호 해독을 망칠 것이기 때문입니다.

코드 부분을 단순화하는 것으로 시작하십시오. 명시 적으로 코드화 된 키를 사용 :

byte[] myKey = new byte[] {0x00, 0x01, 0x02 ... 0x0F};

두 키 생성 방법에서 차이를 제거합니다. 매개 변수의 기본 설정에 의존 할 수 없도록 시스템간에 이동하고 있습니다. 양쪽 매개 변수를 명시 적으로 설정해야합니다.

관련 문제