# How the Database Field Encryption Mechanism Works in ContiNew Admin

> Discover how ContiNew Admin automatically encrypts sensitive database fields using a MyBatis interceptor, RSA keys, and the FieldEncrypt annotation for enhanced security.

- Repository: [OpenContiNew/continew-admin](https://github.com/continew-org/continew-admin)
- Tags: internals
- Published: 2026-02-27

---

**ContiNew Admin automatically encrypts sensitive database fields before persistence and decrypts them on retrieval using a MyBatis interceptor, RSA key pairs, and the `@FieldEncrypt` annotation.**

The **database field encryption mechanism** in the [continew-org/continew-admin](https://github.com/continew-org/continew-admin) repository protects sensitive data such as passwords, emails, and phone numbers by ensuring they remain encrypted at rest. This system leverages the `continew-starter-encrypt-field` starter library to provide transparent encryption that requires minimal code changes in business logic.

## Core Components of the Encryption System

The encryption architecture consists of three primary parts that work together to secure data transparently.

### @FieldEncrypt Annotation

The **`@FieldEncrypt`** annotation marks entity fields or mapper method parameters for automatic encryption. When applied to entity fields in classes like [`UserDO.java`](https://github.com/continew-org/continew-admin/blob/main/UserDO.java), it instructs the MyBatis interceptor to transform the data before database operations. The annotation supports custom encryptors via the `encryptor` parameter, such as `PasswordEncoderEncryptor.class` for password hashing.

### EncryptHelper Utility

The **`EncryptHelper`** class provides static methods (`encrypt` and `decrypt`) for manual encryption when building query conditions. This utility is essential for operations like duplicate-checking, where raw values must be encrypted before comparison against stored ciphertext. According to the source code, this helper resides in the starter dependency at `top.continew.starter.encrypt.field.util.EncryptHelper`.

### RSA Key Configuration

**RSA asymmetric encryption** powers the cryptographic operations. The system uses a public key for encryption and a private key for decryption. These keys are externalized through Spring configuration properties and loaded at startup by [`RsaProperties.java`](https://github.com/continew-org/continew-admin/blob/main/RsaProperties.java), ensuring credentials never exist in the source code.

## How Field Encryption Works in Practice

### Encrypting Entity Fields

Entity classes annotate sensitive fields with `@FieldEncrypt`. In [`continew-system/src/main/java/top/continew/admin/system/model/entity/user/UserDO.java`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/model/entity/user/UserDO.java), the user entity declares encrypted columns:

```java
@FieldEncrypt(encryptor = PasswordEncoderEncryptor.class)
private String password;

@FieldEncrypt
private String email;

@FieldEncrypt
private String phone;

```

When MyBatis executes `INSERT` or `UPDATE` statements, the interceptor automatically encrypts these values using the configured RSA public key (or specified encryptor). During `SELECT` operations, the interceptor decrypts the ciphertext using the private key before returning the entity to the application layer.

### Encrypting Query Parameters

When services must query using raw values—such as checking if an email already exists—manual encryption is required before the value reaches MyBatis. In [`UserServiceImpl.java`](https://github.com/continew-org/continew-admin/blob/main/UserServiceImpl.java), the service calls `EncryptHelper.encrypt()` to prepare query parameters:

```java
// Check for duplicate emails during import
List<String> existEmails = listExistByField(
    importUserList,
    row -> EncryptHelper.encrypt(row)
);

```

Similarly, when building lambda queries, encrypted values ensure comparisons match the stored ciphertext:

```java
.lambdaQuery()
    .eq(UserDO::getEmail, EncryptHelper.encrypt(email))
    .eq(UserDO::getPhone, EncryptHelper.encrypt(phone));

```

### Mapper-Level Parameter Encryption

Mapper interfaces can annotate method parameters directly, allowing MyBatis to encrypt arguments automatically before executing the query. In [`continew-system/src/main/java/top/continew/admin/system/mapper/user/UserMapper.java`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/mapper/user/UserMapper.java):

```java
UserDO selectByPhone(@FieldEncrypt @Param("phone") String phone);
UserDO selectByEmail(@FieldEncrypt @Param("email") String email);

```

This approach eliminates the need for manual encryption in the service layer for these specific queries.

## RSA Key Management and Configuration

The cryptographic keys are defined in environment-specific YAML configuration files ([`application-dev.yml`](https://github.com/continew-org/continew-admin/blob/main/application-dev.yml) and [`application-prod.yml`](https://github.com/continew-org/continew-admin/blob/main/application-prod.yml)) and loaded by [`continew-common/src/main/java/top/continew/admin/common/config/RsaProperties.java`](https://github.com/continew-org/continew-admin/blob/main/continew-common/src/main/java/top/continew/admin/common/config/RsaProperties.java):

```yaml
continew-starter:
  encrypt:
    field:
      public-key: ${ENCRYPT_PUBLIC_KEY}
      private-key: ${ENCRYPT_PRIVATE_KEY}

```

The `RsaProperties` class reads these values at application startup:

```java
PUBLIC_KEY  = SpringUtil.getProperty("continew-starter.encrypt.field.public-key");
PRIVATE_KEY = SpringUtil.getProperty("continew-starter.encrypt.field.private-key");

```

By using environment variables (`${ENCRYPT_PUBLIC_KEY}` and `${ENCRYPT_PRIVATE_KEY}`), the system ensures keys remain outside version control and can be rotated without code changes.

## End-to-End Encryption Flow

The complete **database field encryption mechanism** follows this pipeline:

1. **Data Creation**: The service receives plaintext sensitive data (password, email, phone).
2. **Persistence Encryption**: MyBatis intercepts the `INSERT`/`UPDATE`, encrypts annotated fields with the RSA public key, and stores ciphertext.
3. **Storage**: Encrypted values reside in the database, protecting against direct data exposure.
4. **Retrieval Decryption**: MyBatis intercepts `SELECT` results, decrypts fields using the RSA private key, and returns plaintext entities to the application.
5. **Manual Query Encryption**: For custom queries, services use `EncryptHelper.encrypt()` to match against encrypted columns.

## Summary

- **Annotation-driven**: The `@FieldEncrypt` annotation marks fields for transparent encryption without boilerplate code.
- **Dual-mode operation**: Automatic encryption via MyBatis interceptor for entities, and manual encryption via `EncryptHelper` for query parameters.
- **RSA-based security**: Asymmetric encryption ensures data encrypted with the public key can only be decrypted with the private key.
- **Environment configuration**: Keys are externalized to YAML files using environment variables, supporting secure deployment practices.
- **Minimal intrusion**: The system works with standard MyBatis operations, requiring no changes to SQL mappers for basic CRUD operations.

## Frequently Asked Questions

### What types of fields should be encrypted in ContiNew Admin?

Sensitive personally identifiable information (PII) such as **email addresses**, **phone numbers**, and **passwords** should be encrypted. In the ContiNew Admin codebase, the `UserDO` entity demonstrates this pattern by annotating these exact fields with `@FieldEncrypt`, ensuring that user credentials and contact information remain protected even if the database is compromised.

### How does the encryption mechanism affect database queries?

The **database field encryption mechanism** requires special handling for query parameters. While `SELECT` operations automatically decrypt results, `WHERE` clauses comparing against encrypted columns must use the same encryption algorithm. Services call `EncryptHelper.encrypt(value)` to transform plaintext search terms into ciphertext before executing queries, ensuring the encrypted values match the stored data.

### Where are the RSA encryption keys stored?

The RSA public and private keys are stored as environment variables referenced in the Spring Boot configuration files ([`application-dev.yml`](https://github.com/continew-org/continew-admin/blob/main/application-dev.yml) and [`application-prod.yml`](https://github.com/continew-org/continew-admin/blob/main/application-prod.yml)). The `RsaProperties` class loads these values at runtime using `SpringUtil.getProperty()`, keeping the actual keys out of source code and version control. This supports secure key rotation and prevents credential leakage through repository access.

### Can I use a different encryption algorithm instead of RSA?

Yes, the `@FieldEncrypt` annotation accepts a custom `encryptor` parameter that specifies which encryption implementation to use. For example, passwords use `PasswordEncoderEncryptor.class` instead of the default RSA encryptor. You can implement the encryptor interface from the `continew-starter-encrypt-field` library to integrate alternative algorithms such as AES or custom hashing schemes while maintaining the same transparent interception behavior.