南大通用GBase 8c B兼容模式的加解密函数实践指南

原文链接:www.gbase.cn/community/p...

更多精彩内容尽在南大通用GBase技术社区,南大通用致力于成为用户最信赖的数据库产品供应商。

南大通用GBase 8c原生支持多兼容模式,可以辅助企业摆脱数字化转型时异构语法差异较大的困境,降低数据互通成本和迁移风险。GBase 8c目前可支持Oracle(A模式)、MySQL(B模式)、PostgreSQL(PG模式)、SQL Server(MSSQL模式)等数据库语法兼容。本文将对其中MySQL兼容模式下的加解密函数进行解析,辨明与MySQL加解密函数的区别,并通过示例验证其效果。

1、函数说明

在GBase 8c B兼容模式数据库中,aesencrypt和aesdecrypt函数可分别用于加解密。语法格式为:

  • aesencrypt(str, keystr, init_vector)

描述:基于AES算法,使用密钥字符串key_str和初始化向量init_vector对字符串str进行加密。

参数说明:

str:需要被加密的字符串。若str为NULL,函数返回NULL。

key_str:密钥字符串。若key_str为NULL,函数返回NULL。为了安全,对于128bit/192bit/256bit的密钥长度(由块加密模式block_encryption_mode确定),建议用户使用128bit/192bit/256bit的安全随机数作为密钥字符串。

init_vector:为需要它的块加密模式提供初始化变量,长度大于等于16字节(大于16的字节会被在自动忽略)。str和key_str均不为NULL时,该参数不可为NULL,否则报错。为了安全,建议用户在OFB模式下,保证每次加密IV值的唯一性;在CBC模式和CFB模式下,保证每次加密的IV值不可被预测。

返回值类型:text

  • aesdecrypt(passstr, keystr, initvector)

    描述:基于AES算法,使用密钥字符串key_str和初始化向量init_vector对字符串str进行解密。

    参数说明:

    pass_str:需要被解密的字符串。若pass_str为NULL,函数返回NULL。

    key_str: 密钥字符串。若key_str为NULL,函数返回NULL。为了安全,对于128bit/192bit/256bit的密钥长度(由块加密模式block_encryption_mode确定,默认参数为 aes-128-cbc ),建议用户使用128bit/192bit/256bit的安全随机数作为密钥字符串。

    init_vector:为需要它的块解密模式提供初始化变量,长度大于等于16字节(大于16的字节会被在自动忽略)。pass_str和key_str均不为NULL时,该参数不可为NULL,否则报错。为了安全,建议用户在OFB模式下,保证每次加密IV值的唯一性;在CBC模式和CFB模式下,保证每次加密的IV值不可被预测。

    返回值类型:text

GBase 8c数据库这两个函数与MySQL中函数的区别:

  • GBase8c 中的初始化向量initvector不能为空。
  • MySQL的加密模块blockencryptionmode 为aes-128-ecb,GBase 8c默认加密模块为aes-128-cbc。
  • GBase8c 中该函数仅在MY兼容模式时(即sqlcompatibility = 'B')有效,其他类型不支持该函数。
  • 初始化向量init_vector需要大于16字节

2、函数算法说明 (Java实现示例)

部分代码参考: www.cnblogs.com/yscec/p/181...

aes-128-cbc 加解密对应的java代码如下:

ini 复制代码
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Base64;
/**
* 测试 AES-128-CBC 加解密 (base64、hex)
*/
public class Aes128CbcEncryptForGBaseDemo {
   /**
    * 加密
    * select hex(aes_encrypt('hello,world_hex', 'GBase8c123456789','1234567890123456')) from dual;
    * select to_base64(aes_encrypt('hello,world_base64', 'GBase8c123456789','1234567890123456')) from dual;
    * 解密
    * select aes_decrypt(TRIM(unhex(data)),'GBase8c123456789', '1234567890123456') AS decrypted_data FROM encrypted_data_hex;
    * select aes_decrypt(TRIM(from_base64(data)),'GBase8c123456789', '1234567890123456') AS decrypted_data FROM encrypted_data_base64;
    *
    * CREATE TABLE encrypted_data_hex (
    *     id SERIAL PRIMARY KEY,
    *     data TEXT
    * );
    * CREATE TABLE encrypted_data_base64 (
    *     id SERIAL PRIMARY KEY,
    *     data TEXT
    * );
    */
   private static String DB_URL = "jdbc:gbase://*.*.*.*:15400/gbase?currentSchema=t_encrypted";
   private static String DB_USER = "gbase8c";
   private static String DB_PASSWORD = "Password@123";
   // AES加密密钥
   private static String KEY = "GBase8c123456789";
   // AES加密向量
   private static String IV = "1234567890123456";
   // 使用Base64进行加密
   public static String encryptToBase64(String data, String key, String iv) throws Exception {
       try {
           // 创建AES加密器
           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
           SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
           IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
           // 初始化加密器
           cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
           // 执行加密操作
           byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
           // 将加密结果转换为Base64字符串并返回
           return base64Encode(encrypted);
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
   // 使用Base64进行解密
   public static String desEncryptFromBase64(String data, String key, String iv) throws Exception {
       try {
           // 将Base64字符串解码为字节数组
           byte[] encrypted = base64Decode(data);
           // 创建AES解密器
           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
           SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
           IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
           // 初始化解密器
           cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
           // 执行解密操作
           byte[] original = cipher.doFinal(encrypted);
           // 将解密结果转换为字符串并返回
           return new String(original, StandardCharsets.UTF_8).trim();
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
   // 使用16进制进行加密
   public static String encryptToHex(String data, String key, String iv) throws Exception {
       try {
           // 创建AES加密器
           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
           SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
           IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
           // 初始化加密器
           cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
           // 执行加密操作
           byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
           // 将加密结果转换为16进制字符串并返回
           return bytesToHex(encrypted);
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
   // 使用16进制进行解密
   public static String desEncryptFromHex(String data, String key, String iv) throws Exception {
       try {
           // 将16进制字符串转换为字节数组
           byte[] encrypted = hexStringToByteArray(data);
           // 创建AES解密器
           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
           SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
           IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
           // 初始化解密器
           cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
           // 执行解密操作
           byte[] original = cipher.doFinal(encrypted);
           // 将解密结果转换为字符串并返回
           return new String(original, StandardCharsets.UTF_8).trim();
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
   // 将字节数组转换为16进制字符串
   public static String bytesToHex(byte[] bytes) {
       StringBuilder sb = new StringBuilder();
       for (byte b : bytes) {
           sb.append(String.format("%02X", b));
       }
       return sb.toString();
   }
   // 将16进制字符串转换为字节数组
   public static byte[] hexStringToByteArray(String s) {
       int len = s.length();
       byte[] data = new byte[len / 2];
       for (int i = 0; i < len; i += 2) {
           data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
       }
       return data;
   }
   // 使用Base64进行编码
   public static String base64Encode(byte[] bytes) {
       return Base64.getEncoder().encodeToString(bytes);
   }
   // 使用Base64进行解码
   public static byte[] base64Decode(String str) {
       return Base64.getDecoder().decode(str);
   }
   public static void storeBase64EncryptedData(String data) {
       try {
           Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
           String encryptedData = encryptToBase64(data, KEY, IV);
           String query = "INSERT INTO encrypted_data_base64(data) VALUES(?)";
           PreparedStatement statement = conn.prepareStatement(query);
           statement.setString(1, encryptedData);
           statement.executeUpdate();
           conn.close();
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
   public static String retrieveBase64DecryptedData() {
       String decryptedData = null;
       try {
           Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
           String query = "SELECT data FROM encrypted_data_base64";
           PreparedStatement statement = conn.prepareStatement(query);
           ResultSet resultSet = statement.executeQuery();
           if (resultSet.next()) {
               String encryptedData = resultSet.getString("data");
               decryptedData = desEncryptFromBase64(encryptedData, KEY, IV);
           }
           conn.close();
       } catch (Exception e) {
           e.printStackTrace();
       }
       return decryptedData;
   }
   public static void storeHexEncryptedData(String data) {
       try {
           Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
           String encryptedData = encryptToHex(data, KEY, IV);
           String query = "INSERT INTO encrypted_data_hex(data) VALUES(?)";
           PreparedStatement statement = conn.prepareStatement(query);
           statement.setString(1, encryptedData);
           statement.executeUpdate();
           conn.close();
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
   public static String retrieveHexDecryptedData() {
       String decryptedData = null;
       try {
           Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
           String query = "SELECT data FROM encrypted_data_hex";
           PreparedStatement statement = conn.prepareStatement(query);
           ResultSet resultSet = statement.executeQuery();
           if (resultSet.next()) {
               String encryptedData = resultSet.getString("data");
               decryptedData = desEncryptFromHex(encryptedData, KEY, IV);
           }
           conn.close();
       } catch (Exception e) {
           e.printStackTrace();
       }
       return decryptedData;
   }
   public static void main(String[] args) throws Exception {
       String data_hex = "hello,world_hex";
       storeHexEncryptedData(data_hex);
       String decryptedHexData = retrieveHexDecryptedData();
       System.out.println("Decrypted Hex Data: " + decryptedHexData);
       String data_base64 = "hello,world_base64";
       storeBase64EncryptedData(data_base64);
       String decryptedBase64Data = retrieveBase64DecryptedData();
       System.out.println("Decrypted Base64 Data: " + decryptedBase64Data);
   }
}

3、生产环境最佳实践

在生产环境中,可结合密钥管理方案增强,利用密码卡存储主密钥,并实施密钥轮换策略,进行分层加密:

应用层密钥 → 加密数据库密钥 → 加密数据

此外,还可以结合GBase 8c其他安全功能达到最佳数据防护。例如:

  • 透明数据加密(TDE)
ini 复制代码
CREATE TABLESPACE secure_ts
   LOCATION '/data/secure'
   WITH (encryption = 'on', 
         key_secret = 'AES-256-KEY');
  • 动态数据脱敏
sql 复制代码
CREATE MASKING POLICY phone_mask ON (users.phone)
   USING '111-1111' || RIGHT(aesdecrypt(phone_enc, key, iv), 4);

实际生产部署时,请根据具体业务需求调整安全策略。

原文链接:www.gbase.cn/community/p...

更多精彩内容尽在南大通用GBase技术社区,南大通用致力于成为用户最信赖的数据库产品供应商。

相关推荐
isolusion15 分钟前
Redis 主从复制详解:实现高可用与数据备份
数据库·redis·缓存
极客先躯1 小时前
高级java每日一道面试题-2025年2月18日-数据库篇-MySQL 如何做到高可用方案?
java·数据库·mysql·架构·高可用
墨香染城城2 小时前
Mmybatis xml 连接数据库的方法
xml·数据库
不要小看我们之间的羁绊啊2 小时前
PostgreSQL 多数据库集簇配置及多数据库复制方法【流程+代码实例】
数据库·postgresql
坐山龟2 小时前
PostgreSQL16 的双向逻辑复制
数据库·笔记·postgresql
武帝为此3 小时前
【MyBatis Plus 逻辑删除详解】
数据库·oracle·mybatis
白总Server3 小时前
Bash和Zsh的主要差异是?
开发语言·网络·数据库·stm32·安全·bash·xss
佩奇搞IT3 小时前
孔夫子根剧关键字获取在售商品 API
数据库
CodeJourney.3 小时前
DeepSeek一键生成可视化看板
数据库·人工智能·算法·能源
小兔崽子去哪了4 小时前
初试 Elasticsearch
数据库·elasticsearch