/// <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);
        }
Exemplo n.º 2
0
        /// <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());
        }