nie dostarczyły wiele szczegółów o swoim przypadku użycia, ale chciałbym powiedzieć, że to się dzieje, ponieważ nie są przy użyciu tych samych ustawień szyfrowania podczas operacji szyfrowania i deszyfrowania. Szyfrowanie symetryczne wymaga użycia dokładnie takich samych ustawień/parametrów podczas szyfrowania danych, a także odszyfrowywania. Na przykład dla AES CBC trzeba użyć dokładnie tego samego klucza, IV, trybu szyfrowania i dopełnienia na obu urządzeniach. Najlepiej jest, aby ustawić te ustawienia bezpośrednio w kodzie:
System.Security.Cryptography.RijndaelManaged aes = new System.Security.Cryptography.RijndaelManaged();
aes.Key = new byte[] { ... };
aes.IV = new byte[] { ... };
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
Jeżeli jesteś pewien, że są przy użyciu tych samych ustawień następnie należy również rozważyć scenariusz, że niektóre dane zostaną uszkodzone lub zmienione podczas transferu sieciowego.
Edit po niektóre fragmenty kodu zostały dostarczone:
metody deszyfrowania podałeś nie działa dla mnie w ogóle więc mam połączyć wszystkie próbki i zwrócił je do kodu, który robi to samo jako twój, ale używa IMO nieco czystszego podejścia. Na przykład ten kod używa bardziej niezawodnego "wyprowadzania klucza" (proszę mi wybaczyć cryptoguys), a także przeszedł podstawową analizę kodu.
Powinieneś być w stanie łatwo użyć metody publiczne zrobić to, czego potrzebujesz:
string plainData = "This information should be encrypted";
string encryptedData = EncryptStringified(plainData);
string decryptedData = DecryptStringified(encryptedData);
if (plainData != decryptedData)
throw new Exception("Decryption failed");
Wdrożenie i metody prywatne następująco:
/// <summary>
/// Encrypts string with the key derived from device ID
/// </summary>
/// <returns>Base64 encoded encrypted data</returns>
/// <param name="stringToEncrypt">String to encrypt</param>
public string EncryptStringified(string stringToEncrypt)
{
if (stringToEncrypt == null)
throw new ArgumentNullException("stringToEncrypt");
byte[] key = DeviceIdToDesKey();
byte[] plainData = Encoding.UTF8.GetBytes(stringToEncrypt);
byte[] encryptedData = Encrypt(key, plainData);
return Convert.ToBase64String(encryptedData);
}
/// <summary>
/// Decrypts Base64 encoded data with the key derived from device ID
/// </summary>
/// <returns>Decrypted string</returns>
/// <param name="b64DataToDecrypt">Base64 encoded data to decrypt</param>
public string DecryptStringified(string b64DataToDecrypt)
{
if (b64DataToDecrypt == null)
throw new ArgumentNullException("b64DataToDecrypt");
byte[] key = DeviceIdToDesKey();
byte[] encryptedData = Convert.FromBase64String(b64DataToDecrypt);
byte[] decryptedData = Decrypt(key, encryptedData);
return Encoding.UTF8.GetString(decryptedData);
}
private byte[] DeviceIdToDesKey()
{
TelephonyManager telephonyMgr = Application.Context.GetSystemService(Context.TelephonyService) as TelephonyManager;
string deviceId = telephonyMgr.DeviceId ?? "UNAVAILABLE";
// Compute hash of device ID so we are sure enough bytes have been gathered for the key
byte[] bytes = null;
using (SHA1 sha1 = SHA1.Create())
bytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(deviceId));
// Get last 8 bytes from device ID hash as a key
byte[] desKey = new byte[8];
Array.Copy(bytes, bytes.Length - desKey.Length, desKey, 0, desKey.Length);
return desKey;
}
private byte[] Encrypt(byte[] key, byte[] plainData)
{
if (key == null)
throw new ArgumentNullException("key");
if (plainData == null)
throw new ArgumentNullException("plainData");
using (DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider())
{
if (!desProvider.ValidKeySize(key.Length * 8))
throw new CryptographicException("Key with invalid size has been specified");
desProvider.Key = key;
// desProvider.IV should be automatically filled with random bytes when DESCryptoServiceProvider instance is created
desProvider.Mode = CipherMode.CBC;
desProvider.Padding = PaddingMode.PKCS7;
using (MemoryStream encryptedStream = new MemoryStream())
{
// Write IV at the beginning of memory stream
encryptedStream.Write(desProvider.IV, 0, desProvider.IV.Length);
// Perform encryption and append encrypted data to the memory stream
using (ICryptoTransform encryptor = desProvider.CreateEncryptor())
{
byte[] encryptedData = encryptor.TransformFinalBlock(plainData, 0, plainData.Length);
encryptedStream.Write(encryptedData, 0, encryptedData.Length);
}
return encryptedStream.ToArray();
}
}
}
private byte[] Decrypt(byte[] key, byte[] encryptedData)
{
if (key == null)
throw new ArgumentNullException("key");
if (encryptedData == null)
throw new ArgumentNullException("encryptedData");
using (DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider())
{
if (!desProvider.ValidKeySize(key.Length * 8))
throw new CryptographicException("Key with invalid size has been specified");
desProvider.Key = key;
if (encryptedData.Length <= desProvider.IV.Length)
throw new CryptographicException("Too short encrypted data has been specified");
// Read IV from the beginning of encrypted data
// Note: New byte array needs to be created because data written to desprovider.IV are ignored
byte[] iv = new byte[desProvider.IV.Length];
Array.Copy(encryptedData, 0, iv, 0, iv.Length);
desProvider.IV = iv;
desProvider.Mode = CipherMode.CBC;
desProvider.Padding = PaddingMode.PKCS7;
// Remove IV from the beginning of encrypted data and perform decryption
using (ICryptoTransform decryptor = desProvider.CreateDecryptor())
return decryptor.TransformFinalBlock(encryptedData, desProvider.IV.Length, encryptedData.Length - desProvider.IV.Length);
}
}
Jest naprawdę trudno powiedzieć, co dokładnie było problemu z Twój kod, ponieważ twoja metoda odszyfrowywania nie działa dla mnie w ogóle - najprawdopodobniej dlatego, że używa CryptoStream w trybie zapisu do odszyfrowania, co wydaje mi się trochę dziwne.
Tyle za kod. Teraz przejdźmy do szyfrowania, które jest naprawdę bardzo słabe. Jest to po prostu zaciemnienie, które powinno chronić dane przed przypadkowym wyświetlaniem w formie zwykłego tekstu (niektórzy używają kodowania BASE64 dla tej samej rzeczy). Główną przyczyną tego jest stosunkowo stary algorytm szyfrowania i łatwy do przewidzenia klucz szyfrowania. AFAIK każda aplikacja działająca na tym samym urządzeniu może odczytywać identyfikator urządzenia bez żadnych uprawnień. Oznacza to, że każda aplikacja może odszyfrować dane. Oczywiście twoja baza danych SQLite jest prawdopodobnie dostępna tylko dla twojej aplikacji, ale to nie może być już prawdą, jeśli usuniesz kartę SD lub rootujesz telefon.Aby uczynić to nieco lepszym, można na przykład poprosić użytkownika o podanie hasła, a następnie użyć go do uzyskania unikalnego klucza szyfrowania, ale jest to zupełnie inny problem. W każdym razie nie jestem pewien, co próbujesz osiągnąć za pomocą tego szyfrowania - może być w pełni wystarczający dla twoich potrzeb, nawet jeśli można go uznać za słaby.
Mam nadzieję, że to pomoże.
Jaki szyfr blokowy i tryb działania? Czy możesz dostarczyć kopię wiadomości, której nie udało się odszyfrować? 147 wydaje się dziwną długością. To * zwykle * powinno być wielokrotnością długości bloku szyfru blokowego (często 16). Jednak tryby takie jak CTS i CTR nie mają tego wymogu. Zakładając tryb taki jak CBC, wygląda na to, że przetwarzana jest niekompletna wiadomość. – jww
Dodałem kod do mojego originalquestion =) –
na podstawie Twojej edycji i kodu przy użyciu DES, 147 *** jest źle. Rozmiar bloku DES wynosi 8 bajtów, więc wiadomość musi być wielokrotnością 8 bajtów. Znajdź brakujące 3 bajty (powinno to być 152 bajty), a twój problem zostanie rozwiązany. Powinieneś także używać 'byte []', a nie 'String', aby zaszyfrować dane. Zaszyfrowane dane mogą zawierać bajt 0x00, co może powodować problemy. Lub Base64 danych, aby obsłużyć bajty NULL. – jww