Example #1
0
        /// <inheritdoc/>
        public byte[] Encrypt(
            byte[] message,
            SecureString password,
            KeyDerivationCostType costType,
            string encryptorName,
            string kdfName     = Pbkdf2.CryptoKdfName,
            string compression = null)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            ValidatePassword(password);
            if (_randomSource == null)
            {
                throw new ArgumentNullException(nameof(_randomSource));
            }
            if (string.IsNullOrWhiteSpace(encryptorName))
            {
                encryptorName = BouncyCastleXChaCha20.CryptoAlgorithmName;
            }
            if (string.IsNullOrWhiteSpace(kdfName))
            {
                encryptorName = Pbkdf2.CryptoKdfName;
            }
            ISymmetricEncryptionAlgorithm encryptor = new SymmetricEncryptionAlgorithmFactory().CreateAlgorithm(encryptorName);
            IKeyDerivationFunction        kdf       = new KeyDerivationFactory().CreateKdf(kdfName);

            // Prepare header
            CryptoHeader header = new CryptoHeader();

            header.PackageName   = PackageName;
            header.AlgorithmName = encryptor.Name;
            header.Nonce         = _randomSource.GetRandomBytes(encryptor.ExpectedNonceSize);
            header.KdfName       = kdf.Name;
            header.Salt          = _randomSource.GetRandomBytes(kdf.ExpectedSaltSizeBytes);
            int cost = kdf.RecommendedCost(costType);

            header.Cost        = cost.ToString();
            header.Compression = compression;

            try
            {
                if (string.Equals(CompressionGzip, header.Compression, StringComparison.InvariantCultureIgnoreCase))
                {
                    message = CompressUtils.Compress(message);
                }

                byte[] key    = kdf.DeriveKeyFromPassword(password, encryptor.ExpectedKeySize, header.Salt, cost);
                byte[] cipher = encryptor.Encrypt(message, key, header.Nonce);
                return(CryptoHeaderPacker.PackHeaderAndCypher(header, cipher));
            }
            catch (Exception ex)
            {
                throw new CryptoException("An unexpected error occured, while encrypting the message.", ex);
            }
        }
        /// <summary>
        /// Encrypts a message with a user password, and adds a header containing all information
        /// necessary for the decryption (algorithm, nonce, salt, ...).
        /// </summary>
        /// <param name="message">Plain text message to encrypt.</param>
        /// <param name="password">Password to use for encryption, minimum length is 7 characters.</param>
        /// <param name="costType">The cost type to use for encryption.</param>
        /// <param name="randomSource">A cryptographically safe random source.</param>
        /// <param name="encryptorName">The name of an encryption algorithm which shall be used to
        /// do the encryption.</param>
        /// <param name="kdfName">The name of a key derivation function, which can convert the
        /// password to a key.</param>
        /// <returns>A binary array containing the cipher.</returns>
        public byte[] Encrypt(
            byte[] message,
            string password,
            KeyDerivationCostType costType,
            ICryptoRandomSource randomSource,
            string encryptorName,
            string kdfName = Pbkdf2.CryptoKdfName)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            ValidatePassword(password);
            if (randomSource == null)
            {
                throw new ArgumentNullException("randomSource");
            }
            if (string.IsNullOrWhiteSpace(encryptorName))
            {
                encryptorName = BouncyCastleAesGcm.CryptoAlgorithmName;
            }
            if (string.IsNullOrWhiteSpace(kdfName))
            {
                encryptorName = Pbkdf2.CryptoKdfName;
            }
            ISymmetricEncryptionAlgorithm encryptor = new SymmetricEncryptionAlgorithmFactory().CreateAlgorithm(encryptorName);
            IKeyDerivationFunction        kdf       = new KeyDerivationFactory().CreateKdf(kdfName);

            // Prepare header
            CryptoHeader header = new CryptoHeader();

            header.AppName       = _appName;
            header.AlgorithmName = encryptor.Name;
            header.Nonce         = randomSource.GetRandomBytes(encryptor.ExpectedNonceSize);
            header.KdfName       = kdf.Name;
            header.Salt          = randomSource.GetRandomBytes(kdf.ExpectedSaltSizeBytes);
            int cost = kdf.RecommendedCost(costType);

            header.Cost = cost.ToString();

            try
            {
                byte[] key    = kdf.DeriveKeyFromPassword(password, encryptor.ExpectedKeySize, header.Salt, cost);
                byte[] cipher = encryptor.Encrypt(message, key, header.Nonce);
                return(CryptoHeaderPacker.PackHeaderAndCypher(header, cipher));
            }
            catch (Exception ex)
            {
                throw new CryptoException("An unexpected error occured, while encrypting the message.", ex);
            }
        }
Example #3
0
        /// <inheritdoc />
        public int RecommendedCost(KeyDerivationCostType costType)
        {
            switch (costType)
            {
            case KeyDerivationCostType.Low:
                return(1000);

            case KeyDerivationCostType.High:
                return(10000);    // measured 225ms (targeting ⅕s) on a mid-range mobile device in 2021

            default:
                throw new ArgumentOutOfRangeException("costType");
            }
        }
Example #4
0
        /// <inheritdoc />
        public int RecommendedCost(KeyDerivationCostType costType)
        {
            switch (costType)
            {
            case KeyDerivationCostType.Low:
                return(1000);

            case KeyDerivationCostType.High:
                return(10000);

            default:
                throw new ArgumentOutOfRangeException("costType");
            }
        }