public FieldLevelEncryptionParams(FieldLevelEncryptionConfig config, string ivValue, string encryptedKeyValue, string oaepPaddingDigestAlgorithmValue = null)
 {
     IvValue           = ivValue;
     EncryptedKeyValue = encryptedKeyValue;
     OaepPaddingDigestAlgorithmValue = oaepPaddingDigestAlgorithmValue;
     Config = config;
 }
        /// <summary>
        /// Generate encryption parameters.
        /// </summary>
        /// <exception cref="EncryptionException"/>
        public static FieldLevelEncryptionParams Generate(FieldLevelEncryptionConfig config)
        {
            // Generate a random IV
            var ivBytes = GenerateIv();
            var ivValue = EncodingUtils.EncodeBytes(ivBytes, config.ValueEncoding);

            // Generate an AES secret key
            var secretKeyBytes = GenerateSecretKey();

            // Encrypt the secret key
            var encryptedSecretKeyBytes = RsaEncryption.WrapSecretKey(config.EncryptionCertificate.GetRSAPublicKey(), secretKeyBytes, config.OaepPaddingDigestAlgorithm);
            var encryptedKeyValue       = EncodingUtils.EncodeBytes(encryptedSecretKeyBytes, config.ValueEncoding);

            // Compute the OAEP padding digest algorithm
            var oaepPaddingDigestAlgorithmValue = config.OaepPaddingDigestAlgorithm.Replace("-", string.Empty);

            return(new FieldLevelEncryptionParams
            {
                IvValue = ivValue,
                EncryptedKeyValue = encryptedKeyValue,
                OaepPaddingDigestAlgorithmValue = oaepPaddingDigestAlgorithmValue,
                Config = config,
                SecretKeyBytes = secretKeyBytes,
                IvBytes = ivBytes
            });
        }
Exemple #3
0
        /// <summary>
        /// Decrypt parts of a JSON payload using the given parameters and configuration.
        /// </summary>
        /// <param name="payload">A JSON string</param>
        /// <param name="config">A <see cref="FieldLevelEncryptionConfig"/> instance</param>
        /// <param name="parameters">A <see cref="FieldLevelEncryptionParams"/> instance</param>
        /// <returns>The updated payload</returns>
        /// <exception cref="EncryptionException"/>
        public static string DecryptPayload(string payload, FieldLevelEncryptionConfig config, FieldLevelEncryptionParams parameters = null)
        {
            if (payload == null)
            {
                throw new ArgumentNullException(nameof(payload));
            }
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            try
            {
                // Parse the given payload
                var payloadToken = JToken.Parse(payload);

                // Perform decryption (if needed)
                foreach (var jsonPathIn in config.DecryptionPaths.Keys)
                {
                    var jsonPathOut = config.DecryptionPaths[jsonPathIn];
                    payloadToken = DecryptPayloadPath(payloadToken, jsonPathIn, jsonPathOut, config, parameters);
                }

                // Return the updated payload
                return(payloadToken.ToString());
            }
            catch (EncryptionException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new EncryptionException("Payload decryption failed!", e);
            }
        }
Exemple #4
0
 internal static byte[] WrapSecretKey(FieldLevelEncryptionConfig config, byte[] keyBytes)
 {
     try
     {
         var publicEncryptionKey = config.EncryptionCertificate.GetRSAPublicKey();
         return(publicEncryptionKey.Encrypt(keyBytes,
                                            "SHA-256".Equals(config.OaepPaddingDigestAlgorithm)
                 ? RSAEncryptionPadding.OaepSHA256
                 : RSAEncryptionPadding.OaepSHA512));
     }
     catch (Exception e)
     {
         throw new EncryptionException("Failed to wrap secret key!", e);
     }
 }
Exemple #5
0
        internal static byte[] UnwrapSecretKey(FieldLevelEncryptionConfig config, byte[] keyBytes, string oaepDigestAlgorithm)
        {
            try
            {
                if (!oaepDigestAlgorithm.Contains("-"))
                {
                    oaepDigestAlgorithm = oaepDigestAlgorithm.Replace("SHA", "SHA-");
                }

                var decryptionKey = config.DecryptionKey;
                return(decryptionKey.Decrypt(keyBytes,
                                             "SHA-256".Equals(oaepDigestAlgorithm)
                        ? RSAEncryptionPadding.OaepSHA256
                        : RSAEncryptionPadding.OaepSHA512));
            }
            catch (Exception e)
            {
                throw new EncryptionException("Failed to unwrap secret key!", e);
            }
        }
Exemple #6
0
        private static JToken DecryptPayloadPath(JToken payloadToken, string jsonPathIn, string jsonPathOut,
                                                 FieldLevelEncryptionConfig config, FieldLevelEncryptionParams parameters)
        {
            if (payloadToken == null)
            {
                throw new ArgumentNullException(nameof(payloadToken));
            }
            if (jsonPathIn == null)
            {
                throw new ArgumentNullException(nameof(jsonPathIn));
            }
            if (jsonPathOut == null)
            {
                throw new ArgumentNullException(nameof(jsonPathOut));
            }

            var inJsonToken = payloadToken.SelectToken(jsonPathIn);

            if (inJsonToken == null)
            {
                // Nothing to decrypt
                return(payloadToken);
            }

            // Read and remove encrypted data and encryption fields at the given JSON path
            JsonUtils.AssertIsObject(inJsonToken, jsonPathIn);
            var encryptedValueJsonToken = ReadAndDeleteJsonKey(inJsonToken, config.EncryptedValueFieldName);

            if (IsNullOrEmptyJson(encryptedValueJsonToken))
            {
                // Nothing to decrypt
                return(payloadToken);
            }

            if (!config.UseHttpPayloads() && parameters == null)
            {
                throw new InvalidOperationException("Encryption params have to be set when not stored in HTTP payloads!");
            }

            if (parameters == null)
            {
                // Read encryption params from the payload
                var oaepDigestAlgorithmJsonToken = ReadAndDeleteJsonKey(inJsonToken, config.OaepPaddingDigestAlgorithmFieldName);
                var oaepDigestAlgorithm          = IsNullOrEmptyJson(oaepDigestAlgorithmJsonToken) ? config.OaepPaddingDigestAlgorithm : oaepDigestAlgorithmJsonToken;
                var encryptedKeyJsonToken        = ReadAndDeleteJsonKey(inJsonToken, config.EncryptedKeyFieldName);
                var ivJsonToken = ReadAndDeleteJsonKey(inJsonToken, config.IvFieldName);
                ReadAndDeleteJsonKey(inJsonToken, config.EncryptionCertificateFingerprintFieldName);
                ReadAndDeleteJsonKey(inJsonToken, config.EncryptionKeyFingerprintFieldName);
                parameters = new FieldLevelEncryptionParams(config, ivJsonToken, encryptedKeyJsonToken, oaepDigestAlgorithm);
            }

            // Decrypt data
            var encryptedValueBytes = EncodingUtils.DecodeValue(encryptedValueJsonToken, config.ValueEncoding);
            var decryptedValueBytes = DecryptBytes(parameters.GetSecretKeyBytes(), parameters.GetIvBytes(), encryptedValueBytes);

            // Add decrypted data at the given JSON path
            var decryptedValue = JsonUtils.SanitizeJson(Encoding.UTF8.GetString(decryptedValueBytes));

            if ("$".Equals(jsonPathOut))
            {
                // The decrypted JSON is the new body
                return(JToken.Parse(decryptedValue));
            }
            else
            {
                JsonUtils.CheckOrCreateOutObject(payloadToken, jsonPathOut);
                JsonUtils.AddDecryptedDataToPayload(payloadToken, decryptedValue, jsonPathOut);

                // Remove the input if now empty
                inJsonToken = payloadToken.SelectToken(jsonPathIn);
                if (inJsonToken.Type == JTokenType.Object && !inJsonToken.HasValues)
                {
                    inJsonToken.Parent.Remove();
                }
            }

            return(payloadToken);
        }
Exemple #7
0
        private static JToken EncryptPayloadPath(JToken payloadToken, string jsonPathIn, string jsonPathOut,
                                                 FieldLevelEncryptionConfig config, FieldLevelEncryptionParams parameters)
        {
            if (payloadToken == null)
            {
                throw new ArgumentNullException(nameof(payloadToken));
            }
            if (jsonPathIn == null)
            {
                throw new ArgumentNullException(nameof(jsonPathIn));
            }
            if (jsonPathOut == null)
            {
                throw new ArgumentNullException(nameof(jsonPathOut));
            }

            var inJsonToken = payloadToken.SelectToken(jsonPathIn);

            if (inJsonToken == null)
            {
                // Nothing to encrypt
                return(payloadToken);
            }

            if (parameters == null)
            {
                // Generate encryption params
                parameters = FieldLevelEncryptionParams.Generate(config);
            }

            // Encrypt data at the given JSON path
            var inJsonString        = JsonUtils.SanitizeJson(inJsonToken.ToString());
            var inJsonBytes         = Encoding.ASCII.GetBytes(inJsonString);
            var encryptedValueBytes = EncryptBytes(parameters.GetSecretKeyBytes(), parameters.GetIvBytes(), inJsonBytes);
            var encryptedValue      = EncodingUtils.EncodeBytes(encryptedValueBytes, config.ValueEncoding);

            // Delete data in clear
            if (!"$".Equals(jsonPathIn))
            {
                inJsonToken.Parent.Remove();
            }
            else
            {
                // We need a JObject (we can't work with a JArray for instance)
                payloadToken = JObject.Parse("{}");
            }

            // Add encrypted data and encryption fields at the given JSON path
            JsonUtils.CheckOrCreateOutObject(payloadToken, jsonPathOut);
            var outJsonToken = payloadToken.SelectToken(jsonPathOut) as JObject;

            JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.EncryptedValueFieldName, encryptedValue);
            if (!string.IsNullOrEmpty(config.IvFieldName))
            {
                JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.IvFieldName, parameters.IvValue);
            }
            if (!string.IsNullOrEmpty(config.EncryptedKeyFieldName))
            {
                JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.EncryptedKeyFieldName, parameters.EncryptedKeyValue);
            }
            if (!string.IsNullOrEmpty(config.EncryptionCertificateFingerprintFieldName))
            {
                JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.EncryptionCertificateFingerprintFieldName, config.EncryptionCertificateFingerprint);
            }
            if (!string.IsNullOrEmpty(config.EncryptionKeyFingerprintFieldName))
            {
                JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.EncryptionKeyFingerprintFieldName, config.EncryptionKeyFingerprint);
            }
            if (!string.IsNullOrEmpty(config.OaepPaddingDigestAlgorithmFieldName))
            {
                JsonUtils.AddOrReplaceJsonKey(outJsonToken, config.OaepPaddingDigestAlgorithmFieldName, parameters.OaepPaddingDigestAlgorithmValue);
            }

            return(payloadToken);
        }