2011-08-16 12 views
14

Sto provando a leggere un valore Base64-Encoded da una tabella Database gestita sul lato Linux. In quella tabella c'è una colonna chiamata first_name. Sul lato Linux posso decifrare questo facilmente utilizzando il seguente comando in PHP:Come decrittografare un valore MCRYPT_RIJNDAEL_256 crittografato in C#, crittografato da mcrypt in PHP?

$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, "patient_fn_salt", 
         base64_decode("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="), 
         MCRYPT_MODE_ECB); 

Comunque cerco il più possibile di duplicare questa logica sul lato C# e tutto quello che ottiene è senza senso.

mio codice C# è al di sotto, spero che tu abbia qualche suggerimento perché ho finito di idee :(

byte [] cipherText = 
     Convert.FromBase64String("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="); 
byte [] key = Encoding.UTF8.GetBytes("patient_fn_salt"); 
Array.Resize(ref key, 32); 
byte [] iv = new byte[32]; 

string fname = Utilities.Decrypt(cipherText, key, iv); 


public static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV) 
    { 
    // Check arguments. 
    if (cipherText == null || cipherText.Length <= 0) 
    throw new ArgumentNullException("cipherText"); 
    if (Key == null || Key.Length <= 0) 
    throw new ArgumentNullException("Key"); 
    if (IV == null || IV.Length <= 0) 
    throw new ArgumentNullException("Key"); 

    // TDeclare the streams used 
    // to decrypt to an in memory 
    // array of bytes. 
    MemoryStream msDecrypt = null; 
    CryptoStream csDecrypt = null; 
    StreamReader srDecrypt = null; 

    // Declare the AesManaged object 
    // used to decrypt the data. 
    RijndaelManaged rj = new RijndaelManaged(); 

    // Declare the string used to hold 
    // the decrypted text. 
    string plaintext = null; 

    try 
    { 
    // Create an AesManaged object 
    // with the specified key and IV. 

    rj.Mode = CipherMode.ECB; 
    rj.BlockSize = 256; 
    rj.KeySize = 256; 
    rj.Padding = PaddingMode.Zeros; 

    rj.Key = Key; 
    rj.GenerateIV(); 
    //rj.IV = IV; 


    // Create a decrytor to perform the stream transform. 
    ICryptoTransform decryptor = rj.CreateDecryptor(rj.Key, rj.IV); 

    // Create the streams used for decryption. 
    msDecrypt = new MemoryStream(cipherText); 
    csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read); 
    srDecrypt = new StreamReader(csDecrypt); 

    // Read the decrypted bytes from the decrypting stream 
    // and place them in a string. 
    plaintext = srDecrypt.ReadToEnd(); 
    } 
    finally 
    { 
    // Clean things up. 

    // Close the streams. 
    if (srDecrypt != null) 
    srDecrypt.Close(); 
    if (csDecrypt != null) 
    csDecrypt.Close(); 
    if (msDecrypt != null) 
    msDecrypt.Close(); 

    // Clear the AesManaged object. 
    if (rj != null) 
    rj.Clear(); 
    } 
    return plaintext; 
    } 
} 
+0

Forse questo può aiutare. http://stackoverflow.com/questions/202011/encrypt-decrypt-string-in-net –

+1

Solo una nota: il parametro 'IV' non è utilizzato nel metodo ... e la modalità ECB non ha vettori di inizializzazione. (Ma non credo che questo si riferisca al tuo problema.) –

risposta

5

Come dice Paolo, la modalità BCE non fa uso di una flebo. Se C# insiste su uno quindi utilizzare tutti a zero byte.

Il tasto "patient_fn_salt" è di 15 caratteri, 120 bit. La vostra funzione di decifratura si aspettava 256 bit di chiave. devi essere molto assicurarsi che i bit extra sono identici in entrambi i sistemi e sono in corso aggiunto nello stesso posto in entrambi i sistemi: anche un singolo bit sbagliato comporterà la decifratura dei rifiuti. Leggi il documento PHP la documentazione con molta attenzione per determinare esattamente come "patient_fn_salt" è espanso su una chiave a 256 bit. In particolare, controllare se la chiave effettiva è SHA256("patient_fn_salt").

Per inciso, la modalità ECB non è sicura. Preferire la modalità CTR o CBC. La modalità CTR non richiede il riempimento, quindi probabilmente significherà meno testo cifrato da memorizzare.

ETA: su un'altra lettura, noto che il lato C# è riempito di zeri. Quale padding usa il lato PHP? Zero padding non è una buona idea, in quanto non può riconoscere una decifratura difettosa. Il padding PKCS7 ha una possibilità molto migliore di riconoscere un output difettoso. Meglio specificare esplicitamente il padding su entrambe le estremità piuttosto che fare affidamento sui valori predefiniti.

+0

La [documentazione dice] (http://www.php.net/manual/en/function.mcrypt-decrypt.php): * Se è più piccola di il keysize richiesto, è riempito con '\ 0'. * ... e Array.Resize sembra come se facesse lo stesso. Ma forse il riempimento esplicito è più sicuro. –

+0

Sarebbe utile controllare direttamente il contenuto dei due array di byte, se possibile. In caso contrario, vale sicuramente la pena provare il riempimento esplicito. – rossum

3

Post è vecchio, ma questo potrebbe aiutare qualcuno in futuro. Questa funzione cifrare esattamente come mcrypt_encrypt con i parametri MCRYPT_RIJNDAEL_256 e MCRYPT_MODE_ECB

static byte[] EncryptStringToBytes(string plainText, byte[] key) 
    { 
     if (plainText == null || plainText.Length <= 0) 
      throw new ArgumentNullException("plainText"); 
     if (key == null || key.Length <= 0) 
      throw new ArgumentNullException("key"); 

     byte[] encrypted; 
     using (var rijAlg = new RijndaelManaged()) 
     { 
      rijAlg.BlockSize = 256; 
      rijAlg.Key = key; 
      rijAlg.Mode = CipherMode.ECB; 
      rijAlg.Padding = PaddingMode.Zeros; 
      rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

      ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV); 
      using (var msEncrypt = new MemoryStream()) 
       using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 
       { 
        using (var swEncrypt = new StreamWriter(csEncrypt)) 
         swEncrypt.Write(plainText); 
        encrypted = msEncrypt.ToArray(); 
       } 
     } 
     return encrypted; 
    } 

E qui è la funzione per decifrare

 static string DecryptStringFromBytes(byte[] cipherText, byte[] key) 
    { 
     if (cipherText == null || cipherText.Length <= 0) 
      throw new ArgumentNullException("cipherText"); 
     if (key == null || key.Length <= 0) 
      throw new ArgumentNullException("key"); 

     string plaintext; 
     using (var rijAlg = new RijndaelManaged()) 
     { 
      rijAlg.BlockSize = 256; 
      rijAlg.Key = key; 
      rijAlg.Mode = CipherMode.ECB; 
      rijAlg.Padding = PaddingMode.Zeros; 
      rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

      ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV); 
      using (var msDecrypt = new MemoryStream(cipherText)) 
       using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) 
        using (var srDecrypt = new StreamReader(csDecrypt)) 
         plaintext = srDecrypt.ReadToEnd(); 
     } 
     return plaintext; 
    } 
+1

Spero che questo non sia utile a nessuno, dal momento che se lo è, significa che stanno usando una crittografia piuttosto discutibile. – CodesInChaos

Problemi correlati