예제 #1
0
        public void XChaCha20Poly1305CheckTestVector()
        {
            byte[] message        = HexToBytes(@"4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e");
            byte[] key            = HexToBytes(@"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
            byte[] nonce          = HexToBytes(@"07000000404142434445464748494a4b0000000000000000");
            byte[] expectedCipher = HexToBytes(@"453c0693a7407f04ff4c56aedb17a3c0a1afff01174930fc22287c33dbcf0ac8b89ad929530a1bb3ab5e69f24c7f6070c8f840c9abb4f69fbfc8a7ff5126faeebbb55805ee9c1cf2ce5a57263287aec5780f04ec324c3514122cfc3231fc1a8b718a62863730a2702bb76366116bed09e0fd" + "d4c860b7074be894fac9697399be5cc1");

            ISymmetricEncryptionAlgorithm encryptor = new BouncyCastleXChaCha20();

            byte[] cipher = encryptor.Encrypt(message, key, nonce);
            Assert.IsTrue(expectedCipher.SequenceEqual(cipher));
        }
        /// <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);
        }
예제 #3
0
        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);
        }
        /// <inheritdoc/>
        public string Protect(byte[] unprotectedData)
        {
            // Encrypt the data with a new random key
            ISymmetricEncryptionAlgorithm encryptor = new BouncyCastleXChaCha20();

            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());
        }