/// <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); }
/// <inheritdoc/> public string Protect(byte[] unprotectedData) { // Encrypt the data with a new random key BouncyCastleTwofishGcm encryptor = new BouncyCastleTwofishGcm(); byte[] randomKey = _randomService.GetRandomBytes(encryptor.ExpectedKeySize); byte[] nonce = _randomService.GetRandomBytes(encryptor.ExpectedNonceSize); byte[] protectedData = encryptor.Encrypt(unprotectedData, randomKey, nonce); // Protect the random key with the OS support byte[] encryptedRandomKey; try { if (!KeysExistInKeyStore()) { CreateKeyPairInKeyStore(); } Cipher cipher = Cipher.GetInstance("RSA/ECB/PKCS1Padding"); // ECB mode is not used by RSA IKey publicKey = GetPublicKeyFromKeyStore(); cipher.Init(CipherMode.EncryptMode, publicKey); encryptedRandomKey = cipher.DoFinal(randomKey); } catch (Exception) { // Seems there are exotic devices, which do not support the keystore properly. // The least we can do is obfuscating the key. encryptedRandomKey = CryptoUtils.Obfuscate(randomKey, CryptoUtils.StringToSecureString(Obcake), _randomService); } // Combine the encrypted random key and the encrypted data StringBuilder result = new StringBuilder(); result.Append(CryptoUtils.BytesToBase64String(encryptedRandomKey)); result.Append(Separator); result.Append(CryptoUtils.BytesToBase64String(nonce)); result.Append(Separator); result.Append(CryptoUtils.BytesToBase64String(protectedData)); return(result.ToString()); }