/// <inheritdoc/> public byte[] Unprotect(string protectedData) { // Extract encrypted key and encrypted data string[] parts = protectedData.Split(Separator); if (parts.Length != 3) { throw new Exception("Invalid format of protected data"); } byte[] encryptedStoredKey = CryptoUtils.Base64StringToBytes(parts[0]); byte[] nonce = CryptoUtils.Base64StringToBytes(parts[1]); byte[] protectedDataPart = CryptoUtils.Base64StringToBytes(parts[2]); // Unprotect the random key with OS support byte[] storedKey = null; try { if (KeysExistInKeyStore()) { Cipher cipher = Cipher.GetInstance("RSA/ECB/PKCS1Padding"); // ECB mode is not used by RSA IKey privateKey = GetPrivateKeyFromKeyStore(); cipher.Init(CipherMode.DecryptMode, privateKey); storedKey = cipher.DoFinal(encryptedStoredKey); } } catch (Exception) { storedKey = null; } // Fallback to obfuscated key if (storedKey == null) { storedKey = CryptoUtils.Deobfuscate(encryptedStoredKey, CryptoUtils.StringToSecureString(Obcake)); } // Decrypt the data with the random key ISymmetricEncryptionAlgorithm decryptor; byte[] result; try { decryptor = new BouncyCastleXChaCha20(); result = decryptor.Decrypt(protectedDataPart, storedKey, nonce); } catch (Exception) { // Fallback to twofish, which was used before 3.2021 decryptor = new BouncyCastleTwofishGcm(); result = decryptor.Decrypt(protectedDataPart, storedKey, nonce); } return(result); }
public void EnsureCompatibilityToLibsodiumXChaCha20() { // Ensure that a once stored cipher can always be decrypted even after changes in the liberary. // This cypher was created with libsodium. string base64Cipher = "q8w/Zotsi3ZJp2eaAnFmMiAGgko+N2TkNgunS5+bDRNqrBBoN+XMQPSt7ojO4ODMP3Rf3aoYMNeJFL2/ZqK3AngIuQ=="; byte[] cipher = CryptoUtils.Base64StringToBytes(base64Cipher); ISymmetricEncryptionAlgorithm decryptor = new BouncyCastleXChaCha20(); ICryptoRandomService randomGenerator = CommonMocksAndStubs.CryptoRandomService(88); byte[] key = randomGenerator.GetRandomBytes(decryptor.ExpectedKeySize); byte[] nonce = randomGenerator.GetRandomBytes(decryptor.ExpectedNonceSize); string decryptedMessage = CryptoUtils.BytesToString(decryptor.Decrypt(cipher, key, nonce)); Assert.AreEqual("The brown fox jumps over the lazy 🐢🖐🏿 doc.", decryptedMessage); }