2017-09-20 1 views
0

현재 C# 사이트의 암호 해독 부분에서 java의 암호화 된 문자열로 패딩에 문제가있는 문제가 있습니다. 닷넷 코드는 "패딩이 유효하지 않으므로 제거 할 수 없습니다"라는 오류를 발생시킵니다. _signKey 및 _encKey는 모두 64 바이트입니다.Java 암호화 후 C# AES256 암호 해독 HMACSHA256을 사용한 암호화가 유효하지 않습니다.

public String encryptString(String plainText) { 
     byte[] ciphertext; 
     byte[] iv = new byte[16]; 
     byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8); 
     String _signKey = "****************************************************************"; 
     String _encKey = "****************************************************************"; 



     try { 
      Mac sha256 = Mac.getInstance("HmacSHA256"); 
      SecretKeySpec shaKS = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); 
      sha256.init(shaKS); 

      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG"); 
      iv = new byte[cipher.getBlockSize()]; 
      randomSecureRandom.nextBytes(iv); 
      IvParameterSpec ivParams = new IvParameterSpec(iv); 
      byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8)); 
      // Perform Encryption 
      SecretKeySpec eks = new SecretKeySpec(sessionKey, "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, eks, ivParams); 

      ciphertext = cipher.doFinal(plainBytes); 
      System.out.println("ciphertext= " + new String(ciphertext)); 
      // Perform HMAC using SHA-256 on ciphertext 
      SecretKeySpec hks = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); 
      Mac mac = Mac.getInstance("HmacSHA256"); 
      mac.init(hks); 

      ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream(); 
      outputStream2.write(iv); 
      outputStream2.write(ciphertext); 
      outputStream2.flush(); 
      outputStream2.write(mac.doFinal(outputStream2.toByteArray())); 
      return Base64.encodeBase64String(outputStream2.toByteArray()); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return plainText; 
    } 

내가 알 수있는 한 올바르게 문자열을 암호화합니다. .Net 측에서 코드를 변경할 수 없으므로이 코드가 현재 사용되고 있습니다.

public static string DecryptString(string ciphertext) 
    { 
     using (HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_signKey))) 
     { 
      // Convert message to bytes 
      byte[] encBytes = Convert.FromBase64String(ciphertext); 

      // Get arrays for comparing HMAC tags 
      byte[] sentTag = new byte[sha256.HashSize/8]; 
      byte[] calcTag = sha256.ComputeHash(encBytes, 0, (encBytes.Length - sentTag.Length)); 

      // If message length is too small return null 
      if (encBytes.Length < sentTag.Length + _ivLength) { return null; } 

      // Copy tag from end of encrypted message 
      Array.Copy(encBytes, (encBytes.Length - sentTag.Length), sentTag, 0, sentTag.Length); 

      // Compare tags with constant time comparison, return null if no match 
      int compare = 0; 
      for (int i = 0; i < sentTag.Length; i++) { compare |= sentTag[i]^calcTag[i]; } 
      if (compare != 0) { return null; } 

      using (AesCryptoServiceProvider csp = new AesCryptoServiceProvider()) 
      { 
       // Set parameters 
       csp.BlockSize = _blockBits; 
       csp.KeySize = _keyBits; 
       csp.Mode = CipherMode.CBC; 
       csp.Padding = PaddingMode.PKCS7; 

       // Copy init vector from message 
       var iv = new byte[_ivLength]; 
       Array.Copy(encBytes, 0, iv, 0, iv.Length); 

       // Derive session key 
       byte[] sessionKey = sha256.ComputeHash(Encoding.UTF8.GetBytes(_encKey + iv)); 

       // Decrypt message 
       using (ICryptoTransform decrypt = csp.CreateDecryptor(sessionKey, iv)) 
       { 
        return Encoding.UTF8.GetString(decrypt.TransformFinalBlock(encBytes, iv.Length, encBytes.Length - iv.Length - sentTag.Length)); 
       } 
      } 
     } 
    } 

튀어 나와있는 것이 있다면 답장을 보내 주시면 감사하겠습니다.

+0

일반적으로 잘못된 채우기 오류는 실제로 암호 해독에 실패했으며 키, 암호화 된 데이터, IV 등이 올바르지 않으며 인코딩이 구현과 일치하지 않는다는 것을 의미합니다. – zaph

+0

정말 저를 혼란스럽게합니다. 위의 비교를 통해 태그가 올바른지 확인합니다. 그리고 저는 벡터를 우리가 자바에서 보내는 것과 비교해 보았습니다. 이것이 내가 어슬렁 거리는 이유입니다. 귀하의 의견에 감사드립니다. – TiltMasterFlex

답변

0

나는 자바에서 모든 코드 만이 줄을 읽어 보지 않았 :

byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8)); 

이 유용하거나 분별 아무것도하지 않는다. "+"연산자는 문자열 연결을 수행하지만 ivbyte[]이며 문자열이 아닙니다. 그래서 java는 iv.toString()을 사용합니다.이 문맥에서는 의미가없는 [[email protected]과 같은 것을 포함하는 String을 반환합니다.

+0

실제로 감사합니다. 나는 자바에 상당히 익숙해 졌으므로 나는 이것을 알아 냈다. .Net 부분에서 우리는 이것을 사용하고 있습니다 // 세션 키를 도출합니다 byte [] sessionKey = sha256.ComputeHash (Encoding.UTF8.GetBytes (_encKey + iv)); 저는 .NET 측에서 이것을 모방하려고합니다. 그게 도움이된다면. Java에서 동일한 작업을 수행하는 방법에 대한 아이디어가 있습니까? – TiltMasterFlex

+0

그건 그렇고 알아 냈어. 도와 주셔서 감사합니다.말 그대로 System.Byte []를 끝에 추가하여 제대로 작동하게해야했습니다. 우리의 .Net 측은 사람들이 생각한 것처럼 올바르게 작동하지 않았습니다. – TiltMasterFlex

-2

네 개의 자바 코드와 후에 .NET 코드를 참조하십시오 : 당신은 본질적으로 다른 패딩을 사용하는

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Java 
csp.Padding = PaddingMode.PKCS7; //.Net 

, 즉 오류의 가능성 소스입니다; 그러나, 당신이 'AES는/CBC/PKCS7Padding'는 PKCS # 7 패딩 구현이없는 통지하는 경우 deafult 오라클 JVM 구현 are here

지원하는 대체보기, Refer this great postthis for general fundamentals on padding

encode 방식이있다 sun.security 패키지 refer this에서 사용할 수 있습니다. 그렇지 않으면 Bouncy Castle 패키지를 사용할 수 있습니다. Bouncy Castle은 com.sun 패키지가 일반적으로 지원되지 않는 것으로 간주되므로 사용하는 것이 좋습니다.

+0

PKCS # 7 및 PKCS # 5 패딩은 실제로 정의상의 차이점과 동일합니다. "[PKCS # 7 패딩] (https://en.wikipedia.org/wiki/Padding_ (cryptography) # PKCS7)을 참조하십시오."* PKCS # 5 패딩은 PKCS # 7 패딩과 동일하지만 실제로 64 비트 (8 바이트) 블록 크기를 사용하는 블록 암호에 대해 정의되었습니다. 실제로이 두 가지는 서로 바꿔서 사용할 수 있습니다. " 많은 구현은 AES를 추가 할 때 n PKCS # 7 정의를 포함하는 것을 게으른 것이 었으며 이와 같은 혼란을 추가하기 위해 PKCS # 5 정의를 사용하기로 결정했습니다. – zaph

+1

이 정답을 삭제하십시오. – zaph

+0

@Zaph 답장을 보내 주셔서 감사합니다. 나는 잠시 전에 이것을 깨달았다. 위에 제공된 대답이 정확하지 않습니다. – TiltMasterFlex

관련 문제