Entschlüsseln von Strings in C#, die verschlüsselt wurde, mit PHP openssl_encrypt
Ich habe einen Kunden verschlüsseln einen string in PHP mit dem folgenden code:
$password = 'Ty63rs4aVqcnh2vUqRJTbNT26caRZJ';
$method = 'AES-256-CBC';
texteACrypter = 'Whether you think you can, or you think you can\'t--you\'re right. - Henry Ford';
$encrypted = openssl_encrypt($texteACrypter, $method, $password);
die Ergebnisse in dieser verschlüsselten Ausgabe: MzVWX4tH4yZWc/w75zUagUMEsP34ywSYISsIIS9fj0W3Q/lR0hBrHmdvMOt106PlKhN/1zXFBPbyKmI6nWC5BN54GuGFSjkxfuansJkfoi0=
Wenn ich versuche zu entschlüsseln, dass Strings in C# gibt es mir einen Haufen von junk-etwa so: Z�o�}'*2��I4y�J6S��
��xz���{9^�ED�fF
�}��گs�)�Q���i��$)�
Ich habe versucht, die änderung der Polsterung, mit AesManaged statt RijndaelManaged, ändern die keysize, mit einem anderen Schlüssel, etc. Alle Ergebnisse in entweder verschiedenen junk-E-Saiten oder verschiedene Ausnahmen. Ich muss fehlt etwas wirklich grundlegendes hier, aber ich bin mir nicht sicher, was anderes zu versuchen, an dieser Stelle.
Hier ist mein Entschlüsselungs-code (die ich schamlos kopiert aus einem anderen stackoverflow-Frage: openssl mit nur .NET-Klassen)
class Program
{
//https://stackoverflow.com/questions/5452422/openssl-using-only-net-classes
static void Main(string[] args)
{
var secret = "Ty63rs4aVqcnh2vUqRJTbNT26caRZJ";
var encrypted = "MzVWX4tH4yZWc/w75zUagUMEsP34ywSYISsIIS9fj0W3Q/lR0hBrHmdvMOt106PlKhN/1zXFBPbyKmI6nWC5BN54GuGFSjkxfuansJkfoi0=";
var yeah = OpenSSLDecrypt(encrypted, secret);
Console.WriteLine(yeah);
Console.ReadKey();
}
public static string OpenSSLDecrypt(string encrypted, string passphrase)
{
//base 64 decode
byte[] encryptedBytesWithSalt = Convert.FromBase64String(encrypted);
//extract salt (first 8 bytes of encrypted)
byte[] salt = new byte[8];
byte[] encryptedBytes = new byte[encryptedBytesWithSalt.Length - salt.Length - 8];
Buffer.BlockCopy(encryptedBytesWithSalt, 8, salt, 0, salt.Length);
Buffer.BlockCopy(encryptedBytesWithSalt, salt.Length + 8, encryptedBytes, 0, encryptedBytes.Length);
//get key and iv
byte[] key, iv;
DeriveKeyAndIV(passphrase, salt, out key, out iv);
return DecryptStringFromBytesAes(encryptedBytes, key, iv);
}
private static void DeriveKeyAndIV(string passphrase, byte[] salt, out byte[] key, out byte[] iv)
{
//generate key and iv
List<byte> concatenatedHashes = new List<byte>(48);
byte[] password = Encoding.UTF8.GetBytes(passphrase);
byte[] currentHash = new byte[0];
MD5 md5 = MD5.Create();
bool enoughBytesForKey = false;
//See http://www.openssl.org/docs/crypto/EVP_BytesToKey.html#KEY_DERIVATION_ALGORITHM
while (!enoughBytesForKey)
{
int preHashLength = currentHash.Length + password.Length + salt.Length;
byte[] preHash = new byte[preHashLength];
Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
Buffer.BlockCopy(password, 0, preHash, currentHash.Length, password.Length);
Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + password.Length, salt.Length);
currentHash = md5.ComputeHash(preHash);
concatenatedHashes.AddRange(currentHash);
if (concatenatedHashes.Count >= 48)
enoughBytesForKey = true;
}
key = new byte[32];
iv = new byte[16];
concatenatedHashes.CopyTo(0, key, 0, 32);
concatenatedHashes.CopyTo(32, iv, 0, 16);
md5.Clear();
}
static string DecryptStringFromBytesAes(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("iv");
//Declare the RijndaelManaged object
//used to decrypt the data.
RijndaelManaged aesAlg = null;
//Declare the string used to hold
//the decrypted text.
string plaintext;
//Create a RijndaelManaged object
//with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
//Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
//Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
//Read the decrypted bytes from the decrypting stream
//and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}
}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gut, das war lustig zu erarbeiten und die erforderlichen Sprünge in den PHP-source-code mit einigen interessanten Ergebnissen. Erstens ist PHP nicht auch einen Schlüssel verwenden, Ableitung Algorithmus nur dauert die bytes der passphrase und pads it out mit null auf die erforderliche Länge. Das bedeutet, dass die gesamte DeriveKeyAndIV Methode ist nicht notwendig.
Aufgrund der oben genannten das bedeutet, dass die IV verwendet wird, ist ein 16-Länge byte-array mit Nullen.
Schließlich das einzige, was falsch mit Ihrem code, dass die Quelle, die Sie kopiert aus einem Salz in Ihrer Umsetzung zu verschlüsseln, die dann entfernt werden musste, PHP-oder Sie tun dies, damit das entfernen der salt-bytes ist falsch.
Also, die all dies zusammen bedeutet, dass Sie ändern müssen, die
OpenSSLDecrypt
Methode auf diese.Und sehr schließlich der resultierende string hat einige zusätzliche chars am Ende nämlich ein Satz von 3 ETX char aber diese sollte leicht genug sein, heraus zu filtern. Kann ich eigentlich nicht herausfinden, wo diese herkommen.
Dank @neubert für den Hinweis auf das padding ist ein Teil der standard-PKCS-padding-wenn Sie möchten, den Rahmen zu entfernen Sie diese nur angeben, dass als Polsterung-Modus bei der Instanziierung des
RijndaelManaged
Objekt.