2016-09-08 4 views
2

나는 C#으로 암호화 및 C++로 해독 싶지만 어떤 인코딩 문제가 있습니다암호화 C# 암호 해독 AES CBC 256

예를 들어 변수 :

키 : g OtIPaL 버전-vS5UAnJbPqsDZSf, yJ1 IVString을 : g OtIPaL 버전-VS5

내 C# 코드 :

public static string EncryptString(string message, string KeyString, string IVString) 
    { 
     byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString.Substring(0,32)); 
     byte[] IV = UTF8Encoding.UTF8.GetBytes(IVString); 

     string encrypted = null; 
     RijndaelManaged rj = new RijndaelManaged(); 
     rj.Key = Key; 
     rj.IV = IV; 
     rj.Mode = CipherMode.CBC; 
     rj.Padding = PaddingMode.PKCS7; 
     try 
     { 
      MemoryStream ms = new MemoryStream(); 

      using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write)) 
      { 
       using (StreamWriter sw = new StreamWriter(cs)) 
       { 
        sw.Write(message); 
        sw.Close(); 
       } 
       cs.Close(); 
      } 
      byte[] encoded = ms.ToArray(); 
      encrypted = Convert.ToBase64String(encoded); 

      ms.Close(); 
     } 
     catch (CryptographicException e) 
     { 
      Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (UnauthorizedAccessException e) 
     { 
      Console.WriteLine("A file error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("An error occurred: {0}", e.Message); 
     } 
     finally 
     { 
      rj.Clear(); 
     } 
     return encrypted; 
    } 
,

암호화를 시도 할 때 키에 ASCII 문자가 아닌 바이트 수가 있습니다. 문자열의 길이보다 깁니다.

어떻게 인코딩합니까? C++에서는 EVP (기본 패딩은 PKCS7 임)를 사용합니다. 해당 문자열에서 32 문자이 없기 때문에

static string decryptEX(string KS, string ctext) 
{ 
EVP_CIPHER_CTX* ctx; 
ctx = EVP_CIPHER_CTX_new(); 
string IV = KS.substr(0, 16); 
int rc = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (byte*)&KS[0], (byte*)&IV[0]); 
std::string rtext; 
rtext.resize(ctext.size()); 

int out_len1 = (int)rtext.size(); 
rc = EVP_DecryptUpdate(ctx, (byte*)&rtext[0], &out_len1, (const byte*)&ctext[0], (int)ctext.size()); 


int out_len2 = (int)rtext.size() - out_len1; 
rc = EVP_DecryptFinal_ex(ctx, (byte*)&rtext[0] + out_len1, &out_len2); 
try 
{ 
    rtext.resize(out_len1 + out_len2); 
} 
catch (exception e) 
{ 

} 
return rtext; 

}

+1

문자열이 포함 된 null 값을 운반하는 매우 행복하지 경향을, 0x00 바이트는 키와 IV 모두에 나타날 수 있으므로 텍스트 표현이 필요한 경우 일반적으로 Base64를 사용해야합니다. 동일한 메시지가 같은 방식으로 암호화되기 때문에 키에 고정 IV가 없어야합니다. IV가 대개 메시지와 함께 전송되기 때문에 실제로는 키와 바이트를 (의도적으로) 공유해서는 안됩니다. – bartonjs

답변

1

귀하의 전화

byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString.Substring(0,32)); 

에 실패합니다. 예. 문자열이 UTF8로 인코딩 된 경우 32 바이트가됩니다. 그러나 하위 문자열은 문자 수를 사용합니다.

byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString); 

해당 라인 변경은 32 바이트 길이의 키를 제공한다.

KeyString에 대한 올바른 입력을 신뢰할 수 없으므로 이후에 키 길이가 충분히 길면 을 확인할 수 있습니다. 당신이 당신이 필요로 무엇을해야 할 필요 키, IV 및 블록 크기 가정에서

byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString); 
if (Key.Length < 32) 
    throw new KeyLengthException("some useful info as to why this was thrown"); // or some other appropriate Exception type you create or resuse. 

내가 정확 해요 경우 :

public static string EncryptString(string message, string KeyString, string IVString) 
    { 
     byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString).Take(32).ToArray(); 
     if (Key.Length < 32) 
      throw new Exception("KeyString not at least 32 bytes."); 
     byte[] IV = UTF8Encoding.UTF8.GetBytes(IVString).Take(16).ToArray(); 
     if (Key.Length < 32) 
      throw new Exception("IVString not at least 16 bytes."); 
     string encrypted = null; 
     RijndaelManaged rj = new RijndaelManaged(); 
     rj.KeySize = 128; 
     rj.BlockSize = 128; 
     rj.Key = Key; 
     rj.IV = IV; 
     rj.Mode = CipherMode.CBC; 
     rj.Padding = PaddingMode.PKCS7; 
     try 
     { 
      MemoryStream ms = new MemoryStream(); 

      using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write)) 
      { 
       using (StreamWriter sw = new StreamWriter(cs)) 
       { 
        sw.Write(message); 
        sw.Close(); 
       } 
       cs.Close(); 
      } 
      byte[] encoded = ms.ToArray(); 
      encrypted = Convert.ToBase64String(encoded); 

      ms.Close(); 
     } 
     catch (CryptographicException e) 
     { 
      Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (UnauthorizedAccessException e) 
     { 
      Console.WriteLine("A file error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("An error occurred: {0}", e.Message); 
     } 
     finally 
     { 
      rj.Clear(); 
     } 
     return encrypted; 
    } 
+0

a) Rijndael 대신 Aes를 사용하십시오. b) 구현을 선택하는 대신 Aes.Create()를 사용하십시오. c) KeySize와 Key를 모두 설정하면 중복됩니다. d) 일단 Aes 128로 전환하면 합법적 인 BlockSize 만 e) Aes (또는 Rijndael) 객체는 IDisposable이므로 try/finally {Clear()} 대신 using 문에있을 수 있습니다. – bartonjs

+0

@bartonjs : 감사합니다. 모두 아주 좋은 점. "이 오류를 수정하는 방법"이 아니라면이 코드는 codereview.stackexchange의 훌륭한 후보가 될 것입니다. – hometoast

관련 문제