Crypteron Documentation

Overview

Crypteron is a data security platform for .NET, Java and Scala server applications. Crypteron automatically handles encryption, tamper protection, key management and data migration for all types of data including SQL data, NoSQL objects, files, files streams, message queues and more.

This documentation will help your application have robust data encryption and key management in minutes - saving you months building tricky custom integrations or experiencing production accidents with your critical data. If you need help, please do not hesitate to contact us at support@crypteron.com.

Getting Started

Signup

Crypteron has two components - a Crypteron cloud hosted platform that handles management functionality and an agent library that you include in your application's code.

The first step is to sign up and create your free Crypteron account. After verifying your email, add your app to the Crypteron Dashboard by picking a name and selecting a plan. If you don't have an application to secure right now, just use the name "Sample App". We'll provide a sample application that you can use. Click Create App.

Create a new app

 

Get the App Secret (i.e. an API Key)

The Crypteron Dashboard creates an App Secret so you can securely connect it to your backend application. Click on the Show button to view your application's App Secret and then copy it to your clipboard:

App Secret

NOTE: Your App Secret is unrelated to any encryption keys but you should treat it like a password or a secret. If you think that its been compromised then you can reset it by clicking the App Secret refresh button

Put the App Secret in your app

You can add your App Secret to your .NET or Java application either by via configuration (i.e. in .XML files) or programmatically . If you don't have an application then you can download or clone a Sample .NET App or a Sample Java App from our GitHub repo.

App Secret Programmatically

You can plug-in your App Secret programmatically through code.

NOTE: You need to add a Crypteron Agent to your application for this to compile.

C#

.NET Core users can store their Crypteron AppSecret in any configuration provider of their choice (including appsettings.json), read it from there and program the AppSecret by using something like:

CrypteronConfig.Config.MyCrypteronAccount.AppSecret = "[App Secret Goes Here]";

Java

App Secret via Configuration

C# Configuration

.NET Framework users wanting to use the older app/web.config file can follow the following template for their app.config or web.config file:

<configuration>
  <configSections>
    <section 
        name="crypteronConfig" 
        type="Crypteron.CrypteronConfig, CipherCore" 
        requirePermission="false" />
  </configSections>

  <crypteronConfig>
    <myCrypteronAccount appSecret="[App Secret Goes Here]" />
  </crypteronConfig>
</configuration>
Java Configuration

Great - your app is now linked to the Crypteron platform!

Encrypting Application Data

Now that you've connected your app with the platform, lets look at how you can encrypt data in no time. Crypteron provides several .NET and Java agent libraries in NuGet and Maven for securing different types of data that we outline in the following sections. All of these agent libraries use the same security model defined in the Crypteron Dashboard. This lets you re-use security partitions, access control rules and key rotations across all types of data. And as long at they have the same AppSecret, data encrypted by any one agent can be decrypted by any other agent without any compatibility issues. For example: Data encrypted by the CipherDB C# Entity Framework agent can be decrypted by the CipherObject Java agent.

What sort of data do you need to protect?

  • For securing data stored in a database with an ORM such as Entity Framework, NHibernate, Hibernate or JPA,  jump to CipherDB.
  • For securing data in plain old C# or Java objects, including support for NoSQL, message queues, and JSON, jump to CipherObject.
  • For securing data in files or file streams, jump to CipherStor.

Database With ORM - CipherDB

Crypteron's CipherDB agent library secures data that is persisted using Microsoft Entity Framework, NHibernate, Hibernate, or JPA. If your database is compatible with any of these ORM solutions, we highly recommend you utilize one in your projects.  An ORM, or object-relational mapper, enables developers to work with relational data using domain-specific objects. It eliminates the need for most of the data-access code that developers usually need to write and it integrates with Crypteron effortlessly.

Get the agent library

All CipherDB .NET agent libraries are in NuGet. All CipherDB Java agent libraries are in Maven.

Indicate sensitive data

With CipherDB, you simply decorate your entity classes to specify which class properties contain sensitive data. Add a [Secure] attribute above each property in C# or a @Secure annotation in Java / Scala.

C# Example

public class Patient
{
    public int Id {get; set;}
    
    [Secure]
    public string FullName {get; set;}
    
    [Secure]
    public string SocialSecurityNumber {get; set;}
}

Java Example

public class Patient
{
    private int Id;

    @Secure
    private String fullName;

    @Secure
    private String socialSecurityNumber;
}

Whenever one of these objects is persisted to the database CipherDB will automatically perform key management and encrypt the properties you tagged as secure. Conversely, CipherDB will decrypt and verify the integrity of these properties when the object is loaded back.

If you can't add annotations or attributes to your class properties because your classes were automatically generated using a database-first workflow, don't worry! Simply prefix your property names with the string Secure_ and CipherDB will take care of the rest. For example, if your Patient class was automatically generated from the schema in a Patients table, rename the FullName column to Secure_FullName. Simple!

Verify database column size

Encryption results in cipher-text expansion and there is also associated encryption meta data. So you need to make your database columns large enough to store encrypted data. We suggest using the database's maximum column size since this takes away all initial guess work and since modern databases don't actually allocate the max space unless necessary. This gives you flexibility while preserving performance and efficiency. For example, on SQL Server, we suggest using nvarchar(max) for column size. Only specific entries actually exceeding 8000 characters may have a slight overhead. Other modern databases have similar designs too,

If you're interested in the details, ciphertext length is the plaintext length plus about 80 characters for crypto-metadata. With base64 encoding, that can be longer and if you enable additional Crypteron features like searchable encryption, that storage overhead will be more, up to 140 or 160 characters more.

Java / Scala developers, you are now done - congrats!! C# developers, you just have one simple step listed below.

C# - Entity Framework Core Integration

To integrate with Entity Framework Core, simply add CipherDb.EFCore3.Entities.Activate(); to your app's regular EF Core DbContext.

public class AppDbContext : DbContext
{
    ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // NOTE: Crypteron.CrypteronConfig.Config.MyCrypteronAccount.AppSecret
        //       must be configured before this is executed. Depending on your 
        //       application logic, this configuration can be done using 
        //       dependency-injection or a factory method or through 
        //       the dbcontext's constructor
        CipherDb.EFCore3.Entities.Activate(modelBuilder); // add this line
    }
}

Then just use the AppDbContext as you would. Everything happens automatically behind the scenes.

C# - Entity Framework 6 Integration

C# developers, you have one tiny extra step in order for CipherDB to integrate with Entity Framework. Add Crypteron.CipherDb.Session.Create(this); to your app's DbContext constructor.

public class AppDbContext : DbContext
{
    public AppDbContext()
    {
        Crypteron.CipherDb.Session.Create(this);
    }
}

Then just use the AppDbContext as you would. Everything happens automatically behind the scenes.

You're done!

Congrats! At this point you are done and should have a functioning implementation.

For more details including advanced features such as multiple security partitions, key rotations, data migration, access control rules and more, check out the CipherDB .NET Developer's Guide. Also, download the sample apps and browse through the .NET API Documentation. And as always, contact us if you need help.

Data Objects - CipherObject

Crypteron's CipherObject agent library secures data in plain old C# or Java objects. This low level functionality gives you extreme flexibility since these secure objects are just like any other C# or Java object except that their sensitive data properties are undecipherable. This means you can take an object secured with CipherObject and serialize it as JSON, put it into a message queue, store it in a NoSQL database or anything else you can think of. And remember, all data secured by any Crypteron agent (e.g. C# CipherDB) is compatible with all other Crypteron agents (e.g. Java CipherObject), so you can mix and match for your ideal solution.

The syntax for specifying which class properties contain sensitive data is the same as CipherDB. Simply tag these properties with a [Secure] attribute in C# or a @Secure annotation in Java. When you're ready to securely seal the object, such as before serialization or persistence, use the Encrypt method (C#) or seal method (Java). Conversely, use the Decrypt (C#) or unseal (Java) method to unseal a secured object.

C# Example

// Attributes on data class
public class Patient
{
    public int Id {get; set;}
    
    [Secure]
    public string FullName {get; set;}
    
    [Secure]
    public string SocialSecurityNumber {get; set;}
}

// myPatient is of type Patient
// Encrypt and sign the object before sending
myPatient.Encrypt();

// Decrypt and verify the object after fetching
myPatient.Decrypt();

Java Example

// Annotations on data class
public class Patient
{
    private int Id

    @Secure
    private String fullName;

    @Secure
    private String socialSecurityNumber;
}

// myPatient is of type Patient
// Secure the object before sending
CipherObject.seal(myPatient);

// Decrypt and verify the object after fetching
CipherObject.unseal(myPatient);

After calling Encrypt (or seal) on an object, the properties tagged as sensitive will be signed and encrypted with AES-GCM. This adds privacy and tamper protection. Calling Decrypt (or unseal) on an object will decrypt the sensitive properties and verify that they weren't tampered with.

The CipherObject .NET agent library is in NuGet. The CipherObject Java agent library is in Maven.  Download and install the version that matches your environment:

NOTE: The CipherDB .NET Developers Guide contains more details on advanced features and configuration options that apply to all agent libraries, including Java.

Files and Streams - CipherStor

Crypteron's CipherStor agent library secures files and streams with AES-GCM encryption and tamper protection. This means you can store your sensitive files and streams on any network, cloud or storage provider that supports them, including Azure Blob Storage and Amazon S3, without any additional engineering.

Our straightforward API will encrypt and sign as well as decrypt and verify any file or stream with additional support for compression and native Azure Blob Storage integration. And like all the other Crypteron agent libraries, all aspects of key management happen transparently behind the scenes.

C# Example

var cipherStor = new CipherStorExt();

// Files
cipherStor.EncryptLocalFile(clearInFilename, encryptedOutFilename, compressFlag);
cipherStor.DecryptLocalFile(encryptedInFilename, clearOutFilename);

// Streams
cipherStor.EncryptStream(clearInputStream, encryptedOutputStream, compressFlag);
cipherStor.DecryptStream(encryptedOutputStream, clearInputStream);

Java Example

CipherStor cipherStor = new CipherStor();

// Files
cipherStor.encryptLocalFile(clearFile, encryptedFile, compressFlag);
cipherStor.decryptLocalFile(encryptedFile, clearFile);

// Streams
cipherStor.encryptStream(clearInputStream, encryptedOutputStream, compressFlag);
cipherStor.decryptStream(encryptedStream, clearOutputStream);

Key Management

Even the strongest encryption is weak unless coupled with proper key management. You could secure your home with the best lock in the world but if you leave the key under the mat, make too many copies or don't change your locks often someone is going to break in eventually. At the same time if you have to drive to the bank to fetch your keys from a vault every time you need to get into your house (and drive back every time you leave) you won't be able to get anything done.

Crypteron's key management system achieves a balance between these two extremes and, most importantly, does so completely automatically and transparently. Once you install any of our agent libraries - CipherDB, CipherObject or CipherStor - you're done; there are literally no further steps for key management. Our patented, API-less key management means there is no need to invoke any key management APIs. It just works.

In case you're curious, we've included some technical details below on what goes on behind the scenes but keep in mind that this is all automatic. For advanced features such as multiple security partitions, access control rules, key rotations / versioning, and data migration, please read the CipherDB .NET Developers Guide.

Key Storage

  • When you create an app in the Crypteron Dashboard a default Data Encryption Key (DEK) is created for your application.
  • The Data Encryption Key (DEK) is encrypted and signed using AES-256-GCM with a Key Encryption Key (KEK) and stored remotely on Crypteron's hosted platform. Enterprise customers have a self-hosted option to store these keys on-site.
    • The Key Encryption Key (KEK) is encrypted and signed using elliptic curve cryptography (secp521r1) with a Master Encryption Key (MEK) and a Master Signing Key (MSK).
  • The Master Encryption Key (MEK) and Master Signing Key (MSK) are secured in a hardened service certificate store.

NOTE: CipherStor goes one step further and generates a Media Encryption Key to encrypt each file. This key is encrypted by the Data Encryption Key (DEK) as described above.

key-management-heirarchy

Key Distribution and Caching

The following steps take place behind the scenes when your app needs to encrypt or decrypt a piece of data using CipherDB, CipherObject or CipherStor:

  • The Crypteron agent checks if there was a recent heartbeat. The heartbeat verifies that the App Secret is active and hasn't been revoked by you. It also verifies that your app has a valid license.
  • The agent determines which encryption keys are required. Paid plans include support for multiple security partitions as well as multiple key versions.
  • The agent checks if the required keys are already available in its local, short-term, in-memory cache.
  • If the encryption keys are not cached, the agent checks if there is already a pending network request to the Crypteron platform for the same keys on another application thread.
  • If no other network request for the same encryption keys is pending, the agent creates one over a secure Key Management REST API (security details below). The agent automatically handles timeouts and retries due to Internet latency or re-routing.
  • Once the requested keys are returned, the agent stores them in a local, short-term, in-memory cache. All keys are automatically purged after a few minutes.

Key Management API Security

All key requests between the Crypteron agent and the Crypteron platform are made over a secure REST-based API with multiple layers of encryption:

  • The API traffic has multiple layers of encryption, starting with SSL (specifically TLS) as the outer layer
  • Within the encrypted SSL/TLS pipe, HTTP request headers and body are all signed and verified via an HMAC-SHA256 signature in the standard HTTP Authorization header.
    • The App Secret itself is never sent across the network, even in an encrypted form. It is only used as the key to the HMAC-SHA256 signatures
    • The server also confirms that you haven't previously revoked the App Secret or disabled or paused your App
  • Replay attacks are mitigated by validating a 128-bit nonce included in the Authorization header as well as a UTC time stamp in the HTTP Date Header
    • We allow a 15-minute tolerance to account for drifts in system clocks
  • The HTTP request body consists of the key request object, binary serialized using Protocol Buffers for CPU and space efficiency
  • The HTTP key response from the server is binary serialized, encrypted and signed using AES-GCM and then transmitted over SSL/TLS
    • This second layer of cryptographic security protects your traffic from known or unknown weaknesses in SSL/TLS (e.g. the infamous HeartBleed)
  • The Crypteron Dashboard allows you to easily reset your App Secret and rotate your encryption keys with a click of a button

REMINDER: All of the technical details in this section are to assure you of the robust security built into Crypteron's key management platform. Everything described above happens automatically and transparently.

 

Aren't you glad you don't have to code this yourself??

Training Videos

A video is worth a thousand words. This 3-minute video will show you the basics, including how to shutdown key management with a single click in the event of a data breach:

Java video tutorial

Sample Applications

Most developers learn best by looking at sample code so we put together a set of sample console applications for C# and Java. Both repos contain samples for all flavors of CipherDB, CipherObject and CipherStor. You can download, compile and run them on your own machine to see first hand how Crypteron works. Just be sure to Sign Up for a free Crypteron account first and copy your App Secret into the project first.

Advanced Features and Configuration

Security Partitions

Segmentation is a key component of robust data security. Security partitions are simply strings you define that Crypteron then uses to keep data cryptographically isolated with its own set of encryption keys, access control rules and audit log.

Typical use cases are

  1. Isolating sensitive data between your business customers, who could be competitors of each other and demand you always keep data separate. e.g. bank123 as one security partition and bankABC as another security partition.
  2. Isolating data at different compliance levels e.g. top-secret andconfidential could be two distinct security partitions.

To create or edit a security partition, log into the Crypteron Dashboard and choose your App. To use them from your code, please see the example below.

// Security partitions in CipherObject
myPatient.Encrypt();          // `default` security partition
myPatient.Encrypt("bank123"); // in Bank 123's partition

Access Control Rules

An access control rule limits how different user roles access data within a security partition. For example, you might create an access control rule that allows bank-manager to both encrypt and decrypt data within the bank123 security partition and create another that only allows customer-support agents to decrypt data (no encrypt/write access) within the bank123 partition.

To create or edit an access control rule, log into the Crypteron Dashboard, select your App and then select the Security Partition within which you want to create an access control rule. To use them from your code, please see the example below.

// in Bank 123's partition, as Bank Manager role
myPatient.Encrypt("bank123", "bank-manager"); 

Searchable Encryption

One of the fundamental objectives of strong encryption is to eradicate any and every pattern from your plain text as it’s encrypted to cipher text. However, when performing a search one is specifically looking for patterns to search efficiently. So intuitively, there is a natural tension between strong encryption and free-for-all-searching.

Crypteron builds an in-place, cryptographically secure, distributed search index to enable searches securely. Your data is protected with fully randomized, strong encryption. We describe additional nuances of searchable encryption in this blog post.

The syntax for specifying which class properties containing sensitive data should have searchable encryption enabled is built on the existing approach for CipherDB and CipherObject. Simply add a Opt.Search parameter to your [Secure] attribute in C# or opts = Opt.SEARCH to your @Secure annotation in Java. If you can't add annotations or attributes to your class properties because your classes were automatically generated using a database-first workflow, don't worry! Simply prefix your property names with the string SecureSearch_ and we will take care of the rest.

The example below demonstrates adding searchability to our Patient class allowing us to search for Patients given their Social Security Number.

C# Example

// Attributes on data class
public class Patient
{
    public int Id {get; set;}
    
    [Secure]
    public string FullName {get; set;}
    
    [Secure(Opt.Search)]
    public string SocialSecurityNumber {get; set;}
}

// To search for SSN 123-45-6789, 
// generate a search prefix
var searchPrefix = 
    SecureSearch.GetPrefix("123-45-6789");

// Use the search prefix in a query
var foundPatient = secDb.Patients.Where(p =>
    p.SocialSecurityNumber.StartsWith(searchPrefix)
)

Java Example

// Annotations on data class
public class Patient
{
    private int id

    @Secure
    private String fullName;

    @Secure(opts = Opt.SEARCH)
    private String socialSecurityNumber;
}

// To search for SSN 123-45-6789,
// generate a search prefix
final String searchPrefix = 
    SecureSearch.getPrefix("123-45-6789");

// Use the search prefix in a query:
final TypedQuery query =
    entityManager.createQuery("SELECT p FROM Patient p where p.socialSecurityNumber LIKE :searchPrefix", Patient.class);
query.setParameter("searchPrefix", searchPrefix + "%");
final Patient foundPatient = query.getSingleResult();

Data Masking

Masking basically hides part of the sensitive data, showing just enough to be useful while hiding most of it for privacy and compliance. For example: 123-45-6789 becomes *******6789

Example scenario

Your users may want to know which credit card is being used in a transaction. Decryption and working with the entire card number could be a security risk. You use masking and now only the last 4 digits come out from the data security layer. Masking remains a concern of the data security layer, compliance is simpler and there is no need to re-architect other portions.

Usage

To use masking,

  1. Log into your Crypteron dashboard and go to your desired security partition (example: your default security partition)
  2. Add a new role with masking enabled
  3. Finally, have your code read data as that role (details).

Note that masking doesn't overwrite the original, encrypted value, so your original data (encrypted of course!) is always there in your database. It's just that roles with masking enabled will only read partial values.

Additional customization

By default, the mask is 'show last 4 characters' i.e. "*4" but if you instead want 'show first 3 characters', you can simply add a Mask = "3*" parameter to your [Secure] attribute in C# or mask = "3*" to your @Secure annotation in Java. You can change the masking character by replacing * with x or - or anything else.

See the example below on masking the Social Security Number in a hypothetical Patient class

C# Example

// Attributes on data class
public class Patient
{
    public int Id {get; set;}
    
    [Secure]
    public string FullName {get; set;}
    
    [Secure(Mask = "3x")]
    public string SocialSecurityNumber {get; set;}
}

// When reading a Patient entity using a role that requires masking
// FullName will have all but the last four characters masked
// and SocialSecurityNumber will have all but the first three characters masked

// So a Patient with the name "Jane Smith" and SSN of "123-45-6789"
// would be read as a name of "******mith" and "123xxxxxxxx" for SSN
)

Java Example

// Annotations on data class
public class Patient
{
    private int id

    @Secure
    private String fullName;

    @Secure(mask = "3x")
    private String socialSecurityNumber;
}

// When reading a Patient entity using a role that requires masking
// FullName will have all but the last four characters masked
// and SocialSecurityNumber will have all but the first three characters masked

// So a Patient with the name "Jane Smith" and SSN of "123-45-6789"
// would be read as a name of "******mith" and "123xxxxxxxx" for SSN

Migrate Existing Data

It's very easy to migrate data into Crypteron. It's just a few lines of code - you just read the data as usual and write it back. For CipherObject users, simply invoke the Seal() method to encrypt the object and write it back as you otherwise would. CipherDB users, just add the unencrypted object to a CipherDB enabled database context and save it. An example of this is covered below.

NOTE: Encryption increases the length of the data, so make sure your database columns are wide enough to store the now-longer encrypted data. Refer to the verify database column size section in this document for details.

C# Example

using (var secDb = new CrypteronDbContext())
using (var plainDb = new PlainDbContext())
{
    // Read unencrypted rows from plain db context ..
    foreach (var user in plainDb.Users)
    {
        // .. add to secured DbContext
        secDb.Users.Add(user);
        secDb.Entry(user).State = System.Data.Entity.EntityState.Modified;
    }
    secDb.SaveChanges();
}

We can improve this core idea by

  1. Saving periodically
  2. Batching the entire job and
  3. Skipping already encrypted rows for cases where we stop-restart a migration job.

For the last part, we use the heuristic that any Crypteron encrypted field (any language, any agent library) has a header starting with 0xCDB3 (for binary fields) or zbM (for text fields - it's just 0xcdb3 in Base64). This gives us the following:

using (var secDb = new CrypteronDbContext())
using (var db = new PlainDbContext())
{
    int count = 0;
    foreach (var user in db.Users
        .Take(5000) // batches of 5000
        .Where(u => !u.Secure_LegacyPIN.StartsWith("zbM")) // skip already encrypted
        )
    {
        secDb.Users.Add(user);
        secDb.Entry(user).State = System.Data.Entity.EntityState.Modified;
        if ((++count % 500) == 0)
            db.SaveChanges(); // save periodically
    }
    secDb.SaveChanges();
}

Want to avoid in-place migration?

We've had very cautious customers avoid an in-place migration by temporarily storing both clear and encrypted data during the migration (e.g. have both user.ssn and user.secure_ssn). This approach involved modifying the database schema and is documented here.

Finally, we always recommend backing up your production database before any major operation.

Additional Advanced Features

The purpose of this documentation is to get you up and running as quickly as possible with all of the Crypteron agent libraries. There are additional advanced features and configuration options that weren't covered including:

  • Key rotations
  • Data migration after a key rotation
  • One-click data breach response
  • Searchable encryption
  • Name mapping
  • Stored procedures
  • Performance

For a more comprehensive overview of these features, please view the following resources:

  1. CipherDB .NET Developers Guide - this guide goes well beyond CipherDB and .NET to cover options that apply to all agent libraries, including Java
  2. Searchable Encryption Blog Post
  3. CipherDB Performance Benchmarks
  4. CipherStor Performance Benchmarks
  5. Sample Apps - many advanced features are covered in the samples above
  6. Contact Us - we're pretty fanatical about support and we love helping our customers. If there's something complicated that you are trying to accomplish, don't hesitate to ask for help!

API Reference

Our C# / .NET and Java API references for all of our agent libraries are below.

NOTE: the Crypteron Dashboard is API driven as well with a REST endpoint for all key management functionality including creating new Apps, Security Partitions and Access Control Rules as well as pausing key management in the event of a data breach, executing a key rotation or refreshing the App Secret. You can read the Management REST API documentation here.

Recent blog posts

Migrating existing live data into Crypteron

You’re already live in production. And you have sensitive in the clear. Read this article to see how Crypteron can help.

Encryption, Entity Framework and Projections

Projections in Entity Framework live outside the entity lifecycle. Read more to learn how your can use Crypteron to secure such data.

PCI DSS and key rotations simplified

PCI compliance requires data encryption keys to be changed frequently. Here is how you can do it easily.

Your data-center is not secure and what you can do about it

There is no secure perimeter anymore. Neither in your corporate network nor in your data center. Fight a winning battle armed with self-protecting data rather than a losing one trying to protecting the infrastructure.

Introducing the Crypteron Startup Innovators Program

Qualifying startups get up to 50% off all plans. Tell us how you’re changing the world and the our Startup Innovators Program will support your journey.

6 encryption mistakes that lead to data breaches

If encryption is so unbreakable, why do businesses and governments keep getting hacked? Six common encryption mistakes that lead to data breaches.

Announcing the new Crypteron Community Edition

Starting today you can now sign up for the Crypteron Community Edition for free with no performance limitations.

Data breach response – One click to save your business

Get breathing room – when you need it the most. Respond to a data breach with a single click.

Why We Need Proper Data-At-Rest Encryption: 191M U.S. Voters’ Data Exposed

Adding security at the application level is a large step forward in protecting data from the constant threat of data breaches

How to encrypt large files

CipherStor is blazingly fast! Here we show how to use it within your data-flow pipeline to maintain high performance when encrypting large files.