Giter Club home page Giter Club logo

client-encryption-csharp's Introduction

client-encryption-csharp

Table of Contents

Overview

Compatibility

.NET

  • ClientEncryption.Core targets .NET Standard 2.1
  • ClientEncryption.RestSharpV2 targets .NET Standard 2.1
  • ClientEncryption.RestSharp targets .NET Standard 2.1

.NET Standard versions supported by .NET implementations can be found in the following articles: .NET Standard, .NET Standard versions.

Strong Naming

Assemblies are strong-named as per Strong naming and .NET libraries. The SN key is available here: Identity.snk.

References

Versioning and Deprecation Policy

Usage

Prerequisites

Before using this library, you will need to set up a project in the Mastercard Developers Portal.

As part of this set up, you'll receive:

  • A public request encryption certificate (aka Client Encryption Keys)
  • A private response decryption key (aka Mastercard Encryption Keys)

Adding the Libraries to Your Project

Package Manager

Install-Package Mastercard.Developer.ClientEncryption.{Core|RestSharp|RestSharpV2}

.NET CLI

dotnet add package Mastercard.Developer.ClientEncryption.{Core|RestSharp|RestSharpV2}

Loading the Encryption Certificate

A System.Security.Cryptography.X509Certificates.X509Certificate object can be created from a file by calling EncryptionUtils.LoadEncryptionCertificate:

var encryptionCertificate = EncryptionUtils.LoadEncryptionCertificate("<insert certificate file path>");

Supported certificate formats: PEM, DER.

Loading the Decryption Key

From a PKCS#12 Key Store

A System.Security.Cryptography.RSA object can be created from a PKCS#12 key store by calling EncryptionUtils.LoadDecryptionKey the following way:

var decryptionKey = EncryptionUtils.LoadDecryptionKey(
                                    "<insert PKCS#12 key file path>", 
                                    "<insert key alias>", 
                                    "<insert key password>");

From an Unencrypted Key File

A System.Security.Cryptography.RSA object can be created from an unencrypted key file by calling EncryptionUtils.LoadDecryptionKey the following way:

var decryptionKey = EncryptionUtils.LoadDecryptionKey("<insert key file path>");

Supported RSA key formats:

  • PKCS#1 PEM (starts with "-----BEGIN RSA PRIVATE KEY-----")
  • PKCS#8 PEM (starts with "-----BEGIN PRIVATE KEY-----")
  • Binary DER-encoded PKCS#8

Performing Payload Encryption and Decryption

Introduction

This library supports two types of encryption/decryption, both of which support field level and entire payload encryption: JWE encryption and what the library refers to as Field Level Encryption (Mastercard encryption), a scheme used by many services hosted on Mastercard Developers before the library added support for JWE.

JWE Encryption and Decryption

• Introduction

This library uses JWE compact serialization for the encryption of sensitive data. The core methods responsible for payload encryption and decryption are EncryptPayload and DecryptPayload in the JweEncryption class.

  • EncryptPayload usage:
var encryptedRequestPayload = JweEncryption.EncryptPayload(requestPayload, config);
  • DecryptPayload usage:
var responsePayload = JweEncryption.DecryptPayload(encryptedResponsePayload, config);
• Configuring the JWE Encryption

Use the JweConfigBuilder to create JweConfig instances. Example:

var config = JweConfigBuilder.AJweEncryptionConfig()
    .WithEncryptionCertificate(encryptionCertificate)
    .WithDecryptionKey(decryptionKey)
    .WithEncryptionPath("$.path.to.foo", "$.path.to.encryptedFoo")
    .WithDecryptionPath("$.path.to.encryptedFoo", "$.path.to.foo")
    .WithEncryptedValueFieldName("encryptedValue")
    .Build();

See also:

• Performing JWE Encryption

Call JweEncryption.EncryptPayload with a JSON request payload and a JweConfig instance.

Example using the configuration above:

const string payload = "{" +
    "    \"path\": {" +
    "        \"to\": {" +
    "            \"foo\": {" +
    "                \"sensitiveField1\": \"sensitiveValue1\"," +
    "                \"sensitiveField2\": \"sensitiveValue2\"" +
    "            }" +
    "        }" +
    "    }" +
    "}";
var encryptedPayload = JweEncryption.EncryptPayload(payload, config);
Console.WriteLine(JObject.Parse(encryptedPayload));

Output:

{
    "path": {
        "to": {
            "encryptedFoo": {
                "encryptedValue": "eyJraWQiOiI3NjFiMDAzYzFlYWRlM….Y+oPYKZEMTKyYcSIVEgtQw"
            }
        }
    }
}
• Performing JWE Decryption

Call JweEncryption.DecryptPayload with a JSON response payload and a JweConfig instance.

Example using the configuration above:

const string encryptedPayload = "{" +
    "    \"path\": {" +
    "        \"to\": {" +
    "            \"encryptedFoo\": {" +
    "                \"encryptedValue\": \"eyJraWQiOiI3NjFiMDAzYzFlYWRlM….Y+oPYKZEMTKyYcSIVEgtQw\"" +
    "            }" +
    "        }" +
    "    }" +
    "}";
var payload = JweEncryption.DecryptPayload(encryptedPayload, config);
Console.WriteLine(JObject.Parse(payload));

Output:

{
    "path": {
        "to": {
            "foo": {
                "sensitiveField1": "sensitiveValue1",
                "sensitiveField2": "sensitiveValue2"
            }
        }
    }
}
• Encrypting Entire Payloads

Entire payloads can be encrypted using the "$" operator as encryption path:

var config = JweConfigBuilder.AJweEncryptionConfig()
    .WithEncryptionCertificate(encryptionCertificate)
    .WithEncryptionPath("$", "$")
    // …
    .Build();

Example:

const string payload = "{" +
    "    \"sensitiveField1\": \"sensitiveValue1\"," +
    "    \"sensitiveField2\": \"sensitiveValue2\"" +
    "}";
var encryptedPayload = JweEncryption.EncryptPayload(payload, config);
Console.WriteLine(JObject.Parse(encryptedPayload));

Output:

{
    "encryptedValue": "eyJraWQiOiI3NjFiMDAzYzFlYWRlM….Y+oPYKZEMTKyYcSIVEgtQw"
}
• Decrypting Entire Payloads

Entire payloads can be decrypted using the "$" operator as decryption path:

var config = JweConfigBuilder.AJweEncryptionConfig()
    .WithDecryptionKey(decryptionKey)
    .WithDecryptionPath("$", "$")
    // …
    .Build();

Example:

const string encryptedPayload = "{" +
    "  \"encryptedValue\": \"eyJraWQiOiI3NjFiMDAzYzFlYWRlM….Y+oPYKZEMTKyYcSIVEgtQw\"" +
    "}";
var payload = JweEncryption.DecryptPayload(encryptedPayload, config);
Console.WriteLine(JObject.Parse(payload));

Output:

{
    "sensitiveField1": "sensitiveValue1",
    "sensitiveField2": "sensitiveValue2"
}

Mastercard Encryption and Decryption

• Introduction

The core methods responsible for payload encryption and decryption are EncryptPayload and DecryptPayload in the FieldLevelEncryption class.

  • EncryptPayload usage:
var encryptedRequestPayload = FieldLevelEncryption.EncryptPayload(requestPayload, config);
  • DecryptPayload usage:
var responsePayload = FieldLevelEncryption.DecryptPayload(encryptedResponsePayload, config);
• Configuring the Mastercard Encryption

Use the FieldLevelEncryptionConfigBuilder to create FieldLevelEncryptionConfig instances. Example:

var config = FieldLevelEncryptionConfigBuilder.AFieldLevelEncryptionConfig()
    .WithEncryptionCertificate(encryptionCertificate)
    .WithDecryptionKey(decryptionKey)
    .WithEncryptionPath("$.path.to.foo", "$.path.to.encryptedFoo")
    .WithDecryptionPath("$.path.to.encryptedFoo", "$.path.to.foo")
    .WithOaepPaddingDigestAlgorithm("SHA-256")
    .WithEncryptedValueFieldName("encryptedValue")
    .WithEncryptedKeyFieldName("encryptedKey")
    .WithIvFieldName("iv")
    .WithValueEncoding(FieldValueEncoding.Hex)
    .Build();

See also:

• Performing Mastercard Encryption

Call FieldLevelEncryption.EncryptPayload with a JSON request payload and a FieldLevelEncryptionConfig instance.

Example using the configuration above:

const string payload = "{" +
    "    \"path\": {" +
    "        \"to\": {" +
    "            \"foo\": {" +
    "                \"sensitiveField1\": \"sensitiveValue1\"," +
    "                \"sensitiveField2\": \"sensitiveValue2\"" +
    "            }" +
    "        }" +
    "    }" +
    "}";
var encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, config);
Console.WriteLine(JObject.Parse(encryptedPayload));

Output:

{
    "path": {
        "to": {
            "encryptedFoo": {
                "iv": "7f1105fb0c684864a189fb3709ce3d28",
                "encryptedKey": "67f467d1b653d98411a0c6d3c…ffd4c09dd42f713a51bff2b48f937c8",
                "encryptedValue": "b73aabd267517fc09ed72455c2…dffb5fa04bf6e6ce9ade1ff514ed6141"
            }
        }
    }
}
• Performing Mastercard Decryption

Call FieldLevelEncryption.DecryptPayload with a JSON response payload and a FieldLevelEncryptionConfig instance.

Example using the configuration above:

const string encryptedPayload = "{" +
    "    \"path\": {" +
    "        \"to\": {" +
    "            \"encryptedFoo\": {" +
    "                \"iv\": \"e5d313c056c411170bf07ac82ede78c9\"," +
    "                \"encryptedKey\": \"e3a56746c0f9109d18b3a2652b76…f16d8afeff36b2479652f5c24ae7bd\"," +
    "                \"encryptedValue\": \"809a09d78257af5379df0c454dcdf…353ed59fe72fd4a7735c69da4080e74f\"" +
    "            }" +
    "        }" +
    "    }" +
    "}";
var payload = FieldLevelEncryption.DecryptPayload(encryptedPayload, config);
Console.WriteLine(JObject.Parse(payload));

Output:

{
    "path": {
        "to": {
            "foo": {
                "sensitiveField1": "sensitiveValue1",
                "sensitiveField2": "sensitiveValue2"
            }
        }
    }
}
• Encrypting Entire Payloads

Entire payloads can be encrypted using the "$" operator as encryption path:

var config = FieldLevelEncryptionConfigBuilder.AFieldLevelEncryptionConfig()
    .WithEncryptionCertificate(encryptionCertificate)
    .WithEncryptionPath("$", "$")
    // …
    .Build();

Example:

const string payload = "{" +
    "    \"sensitiveField1\": \"sensitiveValue1\"," +
    "    \"sensitiveField2\": \"sensitiveValue2\"" +
    "}";
var encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, config);
Console.WriteLine(JObject.Parse(encryptedPayload));

Output:

{
    "iv": "1b9396c98ab2bfd195de661d70905a45",
    "encryptedKey": "7d5112fa08e554e3dbc455d0628…52e826dd10311cf0d63bbfb231a1a63ecc13",
    "encryptedValue": "e5e9340f4d2618d27f8955828c86…379b13901a3b1e2efed616b6750a90fd379515"
}
• Decrypting Entire Payloads

Entire payloads can be decrypted using the "$" operator as decryption path:

var config = FieldLevelEncryptionConfigBuilder.AFieldLevelEncryptionConfig()
    .WithDecryptionKey(decryptionKey)
    .WithDecryptionPath("$", "$")
    // …
    .Build();

Example:

const string encryptedPayload = "{" +
    "  \"iv\": \"1b9396c98ab2bfd195de661d70905a45\"," +
    "  \"encryptedKey\": \"7d5112fa08e554e3dbc455d0628…52e826dd10311cf0d63bbfb231a1a63ecc13\"," +
    "  \"encryptedValue\": \"e5e9340f4d2618d27f8955828c86…379b13901a3b1e2efed616b6750a90fd379515\"" +
    "}";
var payload = FieldLevelEncryption.DecryptPayload(encryptedPayload, config);
Console.WriteLine(JObject.Parse(payload));

Output:

{
    "sensitiveField1": "sensitiveValue1",
    "sensitiveField2": "sensitiveValue2"
}
• Using HTTP Headers for Encryption Params

In the sections above, encryption parameters (initialization vector, encrypted symmetric key, etc.) are part of the HTTP payloads.

Here is how to configure the library for using HTTP headers instead.

Configuration for Using HTTP Headers

Call With{Param}HeaderName instead of With{Param}FieldName when building a FieldLevelEncryptionConfig instance. Example:

var config = FieldLevelEncryptionConfigBuilder.AFieldLevelEncryptionConfig()
    .WithEncryptionCertificate(encryptionCertificate)
    .WithDecryptionKey(decryptionKey)
    .WithEncryptionPath("$", "$")
    .WithDecryptionPath("$", "$")
    .WithOaepPaddingDigestAlgorithm("SHA-256")
    .WithEncryptedValueFieldName("data")
    .WithIvHeaderName("x-iv")
    .WithEncryptedKeyHeaderName("x-encrypted-key")
    // …
    .WithValueEncoding(FieldValueEncoding.Hex)
    .Build();

See also:

Encrypting Using HTTP Headers

Encryption can be performed using the following steps:

  1. Generate parameters by calling FieldLevelEncryptionParams.Generate:
var parameters = FieldLevelEncryptionParams.Generate(config);
  1. Update the request headers:
request.SetHeader(config.IvHeaderName, parameters.IvValue);
request.SetHeader(config.EncryptedKeyHeaderName, parameters.EncryptedKeyValue);
// …
  1. Call EncryptPayload with params:
FieldLevelEncryption.EncryptPayload(payload, config, parameters);

Example using the configuration above:

const string payload = "{" +
    "    \"sensitiveField1\": \"sensitiveValue1\"," +
    "    \"sensitiveField2\": \"sensitiveValue2\"" +
    "}";
var encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, config, parameters);
Console.WriteLine(JObject.Parse(encryptedPayload));

Output:

{
    "data": "53b5f07ee46403af2e92abab900853…d560a0a08a1ed142099e3f4c84fe5e5"
}
Decrypting Using HTTP Headers

Decryption can be performed using the following steps:

  1. Read the response headers:
var ivValue = response.GetHeader(config.IvHeaderName);
var encryptedKeyValue = response.GetHeader(config.EncryptedKeyHeaderName);
// …
  1. Create a FieldLevelEncryptionParams instance:
var parameters = new FieldLevelEncryptionParams(config, ivValue, encryptedKeyValue,);
  1. Call DecryptPayload with params:
FieldLevelEncryption.DecryptPayload(encryptedPayload, config, parameters);

Example using the configuration above:

const string encryptedPayload = "{" +
    "  \"data\": \"53b5f07ee46403af2e92abab900853…d560a0a08a1ed142099e3f4c84fe5e5\"" +
    "}";
var payload = FieldLevelEncryption.DecryptPayload(encryptedPayload, config, parameters);
Console.WriteLine(JObject.Parse(payload));

Output:

{
    "sensitiveField1": "sensitiveValue1",
    "sensitiveField2": "sensitiveValue2"
}

Integrating with OpenAPI Generator API Client Libraries

OpenAPI Generator generates API client libraries from OpenAPI Specs. It provides generators and library templates for supporting multiple languages and frameworks.

This project provides you with some interceptor classes you can use when configuring your API client. These classes will take care of encrypting request and decrypting response payloads, but also of updating HTTP headers when needed.

Generators currently supported:

csharp-netcore

OpenAPI Generator

Client libraries can be generated using the following command:

openapi-generator-cli generate -i openapi-spec.yaml -g csharp-netcore -c config.json -o out

config.json:

{ "targetFramework": "netstandard2.1" }

See also:

Usage of the RestSharpEncryptionInterceptor

RestSharpEncryptionInterceptor is located in the ClientEncryption.RestSharpV2 package.

Usage
  1. Create a new file (for instance, MastercardApiClient.cs) extending the definition of the generated ApiClient class:
partial class ApiClient
{
    private readonly Uri _basePath;
    private readonly RestSharpSigner _signer;
    private readonly RestSharpEncryptionInterceptor _encryptionInterceptor;

    /// <summary>
    /// Construct an ApiClient which will automatically:
    /// - Sign requests
    /// - Encrypt/decrypt requests and responses
    /// </summary>
    public ApiClient(RSA signingKey, string basePath, string consumerKey, EncryptionConfig config)
    {
        _baseUrl = basePath;
        _basePath = new Uri(basePath);
        _signer = new RestSharpSigner(consumerKey, signingKey);
        _encryptionInterceptor = RestSharpEncryptionInterceptor.From(config);
    }

    partial void InterceptRequest(RestRequest request)
    {
        _encryptionInterceptor.InterceptRequest(request);
        _signer.Sign(_basePath, request);
    }
}
  1. Configure your ApiClient instance the following way:
var client = new ApiClient(SigningKey, BasePath, ConsumerKey, config);
var serviceApi = new ServiceApi() { Client = client };
// …

csharp (deprecated)

OpenAPI Generator

Client libraries can be generated using the following command:

openapi-generator-cli generate -i openapi-spec.yaml -g csharp -c config.json -o out

config.json:

{ "targetFramework": "netstandard2.1" }

⚠️ v5.0 was used for targetFramework in OpenAPI Generator versions prior 5.0.0.

See also:

Usage of the RestSharpFieldLevelEncryptionInterceptor

RestSharpFieldLevelEncryptionInterceptor is located in the ClientEncryption.RestSharp package.

Usage:
  1. Create a new file (for instance, MastercardApiClient.cs) extending the definition of the generated ApiClient class:
partial class ApiClient
{
    public RestSharpFieldLevelEncryptionInterceptor EncryptionInterceptor { private get; set; }
    partial void InterceptRequest(RestRequest request) => EncryptionInterceptor.InterceptRequest(request);
    partial void InterceptResponse(RestRequest request, RestResponse response) => EncryptionInterceptor.InterceptResponse(response);
}
  1. Configure your ApiClient instance the following way:
var config = Configuration.Default;
config.BasePath = "https://sandbox.api.mastercard.com";
config.ApiClient.RestClient.Authenticator = new RestSharpOAuth1Authenticator(ConsumerKey, signingKey, new Uri(config.BasePath));
var encryptionConfig = FieldLevelEncryptionConfigBuilder
    .AFieldLevelEncryptionConfig()
    // …
    .Build();
config.ApiClient.EncryptionInterceptor = new RestSharpFieldLevelEncryptionInterceptor(encryptionConfig);
var serviceApi = new ServiceApi(config);
// …

client-encryption-csharp's People

Contributors

biggo89 avatar danny-gallagher avatar dependabot[bot] avatar ech0s7r avatar jaaufauvre avatar karen-avetisyan-mc avatar latompa avatar talha-api avatar viathefalcon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

client-encryption-csharp's Issues

[BUG] The specified nonce is not a valid size for this algorithm.

Bug Report Checklist
Have you provided a code sample to reproduce the issue?
Have you tested with the latest release to confirm the issue still exists?
Have you searched for related issues/PRs?
What's the actual output vs expected output?
Description
I am having an issue when trying to decrypt using the payload encryption library C# is not able to decrypt the payload with a Private Key. This is with Mastercard PTS sandbox kit.

Payload Encryption Flows:

• C# encrypt request -> Mastercard > C# decrypt response

This flow fails every time on the C# decrypt response, Java has no issues C# seems to not be able to decrypt it

Stack:

Mastercard.Developer.ClientEncryption.Core.Encryption.EncryptionException: Payload decryption failed!
---> System.ArgumentException: The specified nonce is not a valid size for this algorithm. (Parameter 'nonce')
at System.Security.Cryptography.AesGcm.CheckParameters(ReadOnlySpan1 plaintext, ReadOnlySpan1 ciphertext, ReadOnlySpan1 nonce, ReadOnlySpan1 tag)
at System.Security.Cryptography.AesGcm.Decrypt(Byte[] nonce, Byte[] ciphertext, Byte[] tag, Byte[] plaintext, Byte[] associatedData)
at Mastercard.Developer.ClientEncryption.Core.Encryption.AES.AesGcm.Decrypt(Byte[] secretKeyBytes, JweObject jweObject) in C:\Users\MohamedAShaheedMadan\source\repos\stcpay-middleware-dotnet\StcPay.Middleware\Common\Mastercard.Developer.ClientEncryption.Core\Encryption\AES\AesGcm.cs:line 33
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweObject.Decrypt(JweConfig config) in C:\Users\MohamedAShaheedMadan\source\repos\stcpay-middleware-dotnet\StcPay.Middleware\Common\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweObject.cs:line 38
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayloadPath(JToken payload, String jsonPathIn, String jsonPathOut, JweConfig config) in C:\Users\MohamedAShaheedMadan\source\repos\stcpay-middleware-dotnet\StcPay.Middleware\Common\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweEncryption.cs:line 77
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayload(String payload, JweConfig config) in C:\Users\MohamedAShaheedMadan\source\repos\stcpay-middleware-dotnet\StcPay.Middleware\Common\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweEncryption.cs:line 50
--- End of inner exception stack trace ---
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayload(String payload, JweConfig config) in C:\Users\MohamedAShaheedMadan\source\repos\stcpay-middleware-dotnet\StcPay.Middleware\Common\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweEncryption.cs:line 56
at PTSCommunicationWarper.Controllers.PTSCommController.Decrypt(EncryptRequest request) in C:\Users\MohamedAShaheedMadan\source\repos\stcpay-middleware-dotnet\StcPay.Middleware\PTSCommunicationWarper\Controllers\PTSCommController.cs:line 76
at lambda_method1(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

To Reproduce:

var config = JweConfigBuilder.AJweEncryptionConfig()
.WithEncryptionCertificate(encryptionCertificate)
.WithDecryptionKey(decryptionKey).WithEncryptionPath("$", "$").WithDecryptionPath("$.encryptedValue", "$").WithEncryptedValueFieldName(encryptedValueFieldName: "encryptedValue")
.Build();
var dec = JweEncryption.DecryptPayload(response.Body, config);

Related issues/PRs
Has a similar issue/PR been reported/opened before?

Suggest a fix/enhancement
If you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit), or simply make a suggestion.

If this is a Feature request, please check out this.

Missing netstandard.dll correct version

Our project use framework 4.7.1 and we are using C# coding
I try use both MasterCard client encryption “core” DLL downloaded from NuGet

Version 1.3 unfortunately when I reach to the encryption “payload” I got an error that zero padding not supported with version <2.0
Version 2 , when am trying to set the configuration an exception raised directly “netstandard dll version conflict” I try to download this dll with v2.1 but I couldn’t get it😢
how can I solve this problem
Pleas help m
with_mastercard_clientencryption_core_v1 3
download_nuget_netstandardref_to_get_netstandardv21_error
Mastercard_client_encryption_core_v2_before_cofigalso
Mastercard_clientencryption_Cofigration_v1 3_pass
e

[BUG] Error 400! Request is not encrypted. Payload is already encrypted

Hello! @latompa @swaj @jkenn99 @DRuggeri I'm encountering this error, payload is already encrypted.
Error 400 status code
{"Errors":{"Error":[{"Source":"VALIDATION_ERROR","ReasonCode":"ENCRYPTION_ERROR","Description":"-3001","Recoverable":false,"Details":"Request is not encrypted"}]}}

Expected behavior
Should return 200 status code.

Screenshots
Payload encryption
image
Http request
image

Additional context
Encrypted payload
{
"path": {
"to": {
"encryptedFoo": {
"encryptedValue": "81316b9d66dccded47c9f9bfdb06a9591304c3cc6be4cd69c9723b5083de4cc00e3a55575a2071cb0fd7db2d2038aad6e2a507175e69e740a66cf312a23d06b467bb2d53ea3ec718bab674eeb9a17ec1df929cdb507d5448477495b6ff2c9aa23f47fab0f36e3ab82ce9c3703d4847335ce6300105b8c9328df52c5c623a149869b5a9f020698cda0fa594bd7848a7fac713699f394237ad346424e1d7c659fa19f8e5d7feaeefd0d4e7681de08a3a5b3462910ae30048ad38bfcdb5996570795d53e9675d1d53f45ebd726432fbc93778045636004bdfb69cdebb8728f4ce1e47bb68163fc81d4c634ad9d6eb04934dd7cdc47b66f1f2fdc03ad7b9c64bcd9e65b9a41e8d2749eb1ba59774cf4688ece71c3687091aed35a6b5f24f574f9e7d07670e56bdfd407c543c8ef563813fe19f2f476b6a4e51be1519eb4098a7f3f9754f2b31fa7e8af7a0f923110f8a0bf0642da8b5ee88f3b0d51c28855e626b70d1e281a7ab47d9aa530f8597df6c9b7432c6205b9b7b3e0f76fc5b112984d7b1c4dbc786bf5813693f82b77c7c025e00cf38fb73e7d635e5c49b632625583b59308479badfc014b3886221f500cd3d0f7f39a0bdc3fe8824453351ebe87161ca6f7fd86619cf8bc8cb541df0d6f4025217747b84ff98d7cb90b4ee3529b72db1",
"iv": "bf5ec87ae3710845f361171b1c2dab94",
"encryptedKey": "6923dd05261923c386ca1b74f00f9ee22009c19ce60e01aaa9c1c1b40203b823fba9aab8159598afdf37e3f740eb4cf89f58e3401013ab45bf7e96101a94eeb77c436b136b05c967deab976de6b936e7c023ed0e67f4703c017664c22fab5c755b0ec1ef509a4814062e86f9bca2e41ff2d369e54e4f5912e3adc44b7d9d99d50565d13dca580625a56a332a8080237993747870b1e10aba3bf1e014487ac6f0b8466f012ac16b04c97e2c79b060e4c60ffc89a0a03788ee023298bc3e84b35480289cf553dd835c0310a43e28f918063786882b3aae78182687fea4610d36692a991c26d29653fd4dda5bfb7eb3e024d5fdb295cd554e470d671c299f53cc7f"
}
}
}
}

[REQ] Moving back to .NetStandard2.0 for backward compatibility

Not able to use the latest version with .net Full Framework 4.8.

the latest version of the lib, with the fix related to the umlaut characters, is not compatible with .net Framework 4.8

Describe the solution you'd like

Can you move back to .net Standard 2.0 that sill support .net Framework 4.8?

[BUG] Description

Bug Report Checklist

  • Have you provided a code sample to reproduce the issue?
  • Have you tested with the latest release to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?

Description
A clear and concise description of what is the question, suggestion, or issue and why this is a problem for you.

To Reproduce
Steps to reproduce the behavior.

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here (OS, language version, etc..).

Related issues/PRs
Has a similar issue/PR been reported/opened before?

Suggest a fix/enhancement
If you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit), or simply make a suggestion.

If this is a Feature request, please check out this.

[BUG] Umaut Characters not supported

Bug Report Checklist

  • Have you provided a code sample to reproduce the issue?
  • Have you tested with the latest release to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?

Description
German Character not supported due to ASCII encoding

To Reproduce
Encrypt any payload with umlauts characters then the decrypted one is with a question mark in place of umlaut

[REQ] Feature Request Description

Is your feature request related to a problem? Please describe.

When I use EncryptionUtils.LoadDecryptionKey, I don't always have an actual key file (apps run in containers, kube clusters etc).

Describe the solution you'd like

Add a new LoadDecryptionKey method that can take a byte array. This byte array would be injected by the app's environment/secrets.

Describe alternatives you've considered

no alternatives

Additional context

Add any other context or screenshots about the feature request here.

[BUG] JWE for .net framework

Description

When using this plugin in .net framework 4.8 it gives an error.

AES/GCM/NoPadding is unsupported on .NET Standard < 2.1

To Reproduce

JweEncryption.encryptPayload(requestPayload, config);

Expected behavior

encryption should work as this plugin is targeting less than 2.1

Missing parent object in JWE encrypted payload

Configuration:

var config = JweConfigBuilder.AJweEncryptionConfig()
  //...
  .WithEncryptionPath("$", "$.encryptedDataParent")
  .Build();

Input:

{"data": {}}

Expected output:

{
  "encryptedDataParent": {
    "encryptedData": "ew0KICAia2lkIjogIjc2M...nrs60sQQQdvYxLPwq9g"
  }
}

Actual output:

{
  "encryptedData": "ew0KICAia2lkIjogIjc2M...nrs60sQQQdvYxLPwq9g"
}

JsonReaderException when encrypting/decrypting arrays

Configuration:

var config = JweConfigBuilder.AJweEncryptionConfig()
  //...
  .WithEncryptionPath("$", "$")
  .Build();

Input:

[
	{},
	{}
]

Expected output:

{
  "encryptedData": "ew0KICAia2lkIjogIjc2M...nrs60sQQQdvYxLPwq9g"
}

Actual output:

Mastercard.Developer.ClientEncryption.Core.Encryption.EncryptionException: 
Payload encryption failed! ---> Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.

[BUG] The specified nonce is not a valid size for this algorithm. (Parameter 'nonce')

Bug Report Checklist

  • Have you provided a code sample to reproduce the issue?
  • Have you tested with the latest release to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?

Description
I am having an issue when trying to decrypt using the payload encryption library when Java encrypts with a Public Key, C# is not able to decrypt the payload with a Private Key.

Payload Encryption Flows:

• C# encrypt request -> Java decrypt request -> Java encrypt response -> C# decrypt response

This flow fails every time on the C# decrypt response, Java has no issue reading the encrypted request, just when it is sent back, C# seems to not be able to decrypt it

• Java encrypt request -> Java decrypt request -> Java encrypt response -> Java decrypt response

This works every time

• C# encrypt request -> C# decrypt request -> C# encrypt response -> C# decrypt response

This works every time

To Reproduce
Using a self signed PKCS12 public / private key.

-- Java

    String data = "{\"Hello\" : \"World\"}";
    
    String encryptedPayload = encryptData(getPublicKey(ks), data);
    System.out.println(encryptedPayload); // This is the json payload encrypted from mastercard lib

    private static X509Certificate getPublicKey(KeyStore ks) throws KeyStoreException
{
	String alias = ks.aliases().nextElement();
	X509Certificate cert = (X509Certificate) ks.getCertificate(alias); 

	return cert;
}


    private static String encryptData(X509Certificate cert, String data) throws ParseException, CertificateException, EncryptionException, IOException
{
	// Fetch the public Cert from the service, so the payload can be encrypted
	JweConfig jweConfig = JweConfigBuilder.aJweEncryptionConfig()
            .withEncryptionCertificate(  cert  )
            .withEncryptionPath("$", "$")
            .withEncryptedValueFieldName("encryptedValue")
            .build();

             String encryptedValue = JweEncryption.encryptPayload(data, jweConfig);
	
	return encryptedValue;
}

-- C#

        RSA privateKey = LoadDecryptionKey("CertName.pfx", null, payloadEncryptionPassword);


        String javaEncryptedData = "{\"encryptedValue\":\"eyJraWQiOiJlYmFiMzgwOWRkZjhjYmYzZmE2YzQwZjk3NjU1ZDg4YThjZGQ0M2JkY2FiZjQxOTc4YTVmNWExOTAzYzFjZDQ0IiwiY3R5IjoiYXBwbGljYXRpb24vanNvbiIsImVuYyI6IkEyNTZHQ00iLCJhbGciOiJSU0EtT0FFUC0yNTYifQ.hchoaYMxp2grF1NcYiGPHgYxzPipjltj0foSFpcg-O4y-mU7gqMcvsyx_7cy4iOxFsYZz16HE5FV4AcwJB8XQAa1TKz_t072isuHfaBeN2MC5ikgCUAg9wdKjCkmpr5l_yU6MOygsm23Zh0_VOgwhHCMWpNddDfxkS1G-_NLmmKAAb-pk46ni6T_uSU4iXYY408Xeww6tl9HJNB1IHUGh-ev5FMakf7Ey1MsswnLDNwzoFmOHivKWOeueYHeqep84UhWKp6oIHwm_Dqb7Q5xVV9KS0_MIx8XYcqKglw52Lw1iEQ7_Agiy_Xdjhoot0X9iSraeH2rfET-rOvMivG5Uw.RFtola7NDnkDdmIBmXKveg.GvyOaL7to-5vB3j4vzk.gh_IIQSOjAWsuH5xH_EP6Q\"}\r\n";  // This would be the payload that Java Producted

        String decryptedData = decryptData(privateKey, javaEncryptedData);  // Never gets here


    public static RSA LoadDecryptionKey(string pkcs12KeyFilePath, string decryptionKeyAlias, string decryptionKeyPassword,
        X509KeyStorageFlags keyStorageFlags = X509KeyStorageFlags.DefaultKeySet)
    {
        if (pkcs12KeyFilePath == null) throw new ArgumentNullException(nameof(pkcs12KeyFilePath));
        var certificate = new X509Certificate2(pkcs12KeyFilePath, decryptionKeyPassword, keyStorageFlags);
        return certificate.GetRSAPrivateKey();
    }

    private static String decryptData(RSA privateKey, String data)
    {
        JweConfig jweConfig = JweConfigBuilder.AJweEncryptionConfig()
            .WithDecryptionKey(privateKey)
            .WithDecryptionPath("$.encryptedValue", "$").Build();

        String decrypted = JweEncryption.DecryptPayload(data, jweConfig);  // Error happens here

        return decrypted;
    }

Expected behavior
To be able to use payload encryption between Java and C#. This currently works when C# sends Java encrypted data, but when Java sends a response back C# can't extract the payload.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here (OS, language version, etc..).

Stack Trace

System.ArgumentException
HResult=0x80070057
Message=The specified nonce is not a valid size for this algorithm. (Parameter 'nonce')
Source=System.Security.Cryptography.Algorithms
StackTrace:
at System.Security.Cryptography.AesGcm.CheckParameters(ReadOnlySpan1 plaintext, ReadOnlySpan1 ciphertext, ReadOnlySpan1 nonce, ReadOnlySpan1 tag)
at System.Security.Cryptography.AesGcm.Decrypt(Byte[] nonce, Byte[] ciphertext, Byte[] tag, Byte[] plaintext, Byte[] associatedData)
at Mastercard.Developer.ClientEncryption.Core.Encryption.AES.AesGcm.Decrypt(Byte[] secretKeyBytes, JweObject jweObject) in C:\Git\client-encryption-csharp\Mastercard.Developer.ClientEncryption.Core\Encryption\AES\AesGcm.cs:line 33
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweObject.Decrypt(JweConfig config) in C:\Git\client-encryption-csharp\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweObject.cs:line 36
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayloadPath(JToken payload, String jsonPathIn, String jsonPathOut, JweConfig config) in C:\Git\client-encryption-csharp\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweEncryption.cs:line 77
at Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayload(String payload, JweConfig config) in C:\Git\client-encryption-csharp\Mastercard.Developer.ClientEncryption.Core\Encryption\JWE\JweEncryption.cs:line 50

This exception was originally thrown at this call stack:
[External Code]
Mastercard.Developer.ClientEncryption.Core.Encryption.AES.AesGcm.Decrypt(byte[], Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweObject) in AesGcm.cs
Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweObject.Decrypt(Mastercard.Developer.ClientEncryption.Core.Encryption.JweConfig) in JweObject.cs
Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayloadPath(Newtonsoft.Json.Linq.JToken, string, string, Mastercard.Developer.ClientEncryption.Core.Encryption.JweConfig) in JweEncryption.cs
Mastercard.Developer.ClientEncryption.Core.Encryption.JWE.JweEncryption.DecryptPayload(string, Mastercard.Developer.ClientEncryption.Core.Encryption.JweConfig) in JweEncryption.cs

Class where the issue is: Mastercard.Developer.ClientEncryption.Core.Encryption.AES.AesGcm

This issue is happens when calling aes.Decrypt specifically. It appears that the Decrypt method is not happy about the size of the nonce byte array which is 16 characters. I was doing some research and thought this should be 12 characters instead or 96 bits according to the NIST, which might explain why Decrypt is not happy with this size.

   internal static byte[] Decrypt(byte[] secretKeyBytes, JweObject jweObject)
    {

#if NETSTANDARD2_1
byte[] plaintext;
using (var aes = new System.Security.Cryptography.AesGcm(secretKeyBytes))
{
byte[] nonce = Base64Utils.URLDecode(jweObject.Iv);
byte[] aad = Encoding.ASCII.GetBytes(jweObject.RawHeader);
byte[] authTag = Base64Utils.URLDecode(jweObject.AuthTag);
byte[] ciphertext = Base64Utils.URLDecode(jweObject.CipherText);
plaintext = new byte[ciphertext.Length];

            aes.Decrypt(nonce, ciphertext, authTag, plaintext, aad);
        }
        return plaintext;

#else
throw new EncryptionException("AES/GCM/NoPadding is unsupported on .NET Standard < 2.1");
#endif
}

Related issues/PRs
Has a similar issue/PR been reported/opened before?

Suggest a fix/enhancement
If you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit), or simply make a suggestion.

If this is a Feature request, please check out this.

Support Operating system-agnostic version

The current implementation is relying on the underlying operating system to extract and use keys from X509 certificates.
With the expanding popularity of serverless deployment, it would be nice to have an Operating system-agnostic version.

My advice would be to extend the library and enable encryption / decryption based on public/private keys (not only an X509 certificate) in the FieldLevelEncryptionConfigBuilder.

The user can provide the keys in a custom way, without the need to use operation system services.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.