HarmonyOS 7 AES-XTS 存储加密边界封面

HarmonyOS 7 AES-XTS 解密成功就安全?API 26 存储加密不替你验真

我第一次看到 HarmonyOS 7 / API 26 的 AES-XTS 示例时,最容易误判的地方不是 createCipher 怎么写,而是“加密后还能解密”被当成了完整的安全验收。XTS 适合保护存储单元的机密性,但不提供数据或来源的认证。把它直接拿来加密请求报文、订单状态或需要防篡改的配置,然后宣称“解密成功所以内容可信”,是选错了模式。

华为在 2026-09-08 更新的指导中明确:API 26.0.0 起支持 XTS;示例用 createSymKeyGenerator('AES256') 得到 256 位组合密钥,再用 createCipher('AES128|XTS') 加解密。这个搭配并不矛盾:XTS 需要两段 AES-128 密钥,组合长度是 256 位。NIST 的 XTS-AES 推荐也把用途放在存储设备的保密性,并明确它不提供认证。

验证边界:下文在本机 Node.js/OpenSSL 跑通了 XTS 模式实验,没有在 HarmonyOS API 26 SDK 或真实设备上编译运行 CryptoArchitectureKit。本机结果只能解释模式行为,不能代替鸿蒙端实现、密钥保护和跨设备互通验收。

先确定是不是 XTS 的使用场景

需求XTS 是否合适原因
块存储或固定数据单元的保密可以评估它面向存储数据单元,密文长度通常不扩张
消息传输时同时要发现内容被改不能只靠 XTSXTS 不产生类似 GCM 的认证标签
登录令牌、金额、配置完整性保护不能把 XTS 当完整方案需要明确的数据认证和密钥管理设计

这里不是说“XTS 不安全”。它是一个目标明确的模式:保护存储介质上的数据保密。问题在于我们不能拿它完成它本来就没有承诺的认证任务。如果你的目标是应用消息的加密加认证,需要评估合适的认证加密方案,而不是把 XTS 解密成功当验真。

AES-XTS 保密与认证边界图

案例一:同一份数据换个存储单元,密文为什么不同

XTS 的第二个输入可以理解为数据单元的调整值(tweak)。同一密钥、相同数据,用不同单元标识计算,密文应不同。华为示例的 IvParamsSpec 装着 16 字节参数;实际存储协议必须明确定义哪个数据单元使用哪个调整值,以及解密端如何得到相同的值。不要把它和 GCM“每条消息随机 nonce”的规则直接混为一谈。

为了复现现象,下面用 Node.js 标准库的 aes-128-xts。它不是鸿蒙接口,但可以在开发机上独立运行。sector 设成 512 字节,是一个便于观察的实验数据单元;不是在断言所有应用都必须用 512 字节。

import assert from 'node:assert/strict';
import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';

const key = randomBytes(32); // aes-128-xts uses two 128-bit AES keys.
const sector = Buffer.alloc(512, 0x41);

function tweak(index) {
  const value = Buffer.alloc(16);
  value.writeUInt32LE(index, 0);
  return value;
}

function encrypt(data, unit) {
  const cipher = createCipheriv('aes-128-xts', key, tweak(unit));
  return Buffer.concat([cipher.update(data), cipher.final()]);
}

function decrypt(data, unit) {
  const cipher = createDecipheriv('aes-128-xts', key, tweak(unit));
  return Buffer.concat([cipher.update(data), cipher.final()]);
}

const a = encrypt(sector, 7);
const b = encrypt(sector, 8);
assert.notDeepEqual(a, b);
assert.deepEqual(decrypt(a, 7), sector);
assert.deepEqual(decrypt(b, 8), sector);
console.log('case 1: same data, different storage units, different ciphertext');

const changed = Buffer.from(a);
changed[12] ^= 1;
const output = decrypt(changed, 7);
assert.notDeepEqual(output, sector);
console.log('case 2: modified ciphertext decrypts without an auth-tag failure');

assert.throws(() => createCipheriv('aes-128-xts', randomBytes(16), tweak(7)));
console.log('case 3: a 16-byte key is insufficient for aes-128-xts');

保存为 xts-storage-check.mjs,运行 node xts-storage-check.mjs。本机三个断言组通过。第一次说明不同数据单元的密文不同,且用各自调整值能还原原文;不要用单元 8 的调整值去解单元 7 的密文。也不要把这个例子理解成“同一数据单元每次写入都要生成随机调整值”:XTS 的单元编号/调整值管理要跟真实存储布局一起设计。

案例二:改掉密文一个字节,为什么没有“认证失败”

实验把密文第 13 个字节翻转一位后再解密,Node/OpenSSL 返回了不同的数据,而没有 GCM 那样的认证标签失败。这正对应 NIST 对 XTS 的用途边界:保密不等于认证。这里的结果不表示攻击者能精确控制所有解密内容,只说明“只看解密函数返回”不足以证明内容未被改。

假设应用把一个 JSON 配置文件直接用 XTS 加密,打开文件后马上读取 isAdminprice 或开关状态:就算字节被更改,XTS 本身也不会替你判定“这份数据是谁写的、有没有被篡改”。业务层要另行设计完整性保护和失败拒绝机制,不能默默消费可能损坏的内容。若本来就是块设备层加密,也要清楚文件系统、访问控制和更上层校验各自负责什么,不要把责任全部记在 XTS 名下。

HarmonyOS API 26 接口该怎样对照

华为官方示例的关键连接是:

const generator = cryptoFramework.createSymKeyGenerator('AES256');
const symKey = await generator.generateSymKey();
const params: cryptoFramework.IvParamsSpec = {
  algName: 'IvParamsSpec',
  iv: cryptoFramework.createRandom().generateRandomSync(16)
};
const cipher = cryptoFramework.createCipher('AES128|XTS');
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, params);
const cipherText = await cipher.doFinal(plainText);

这段只摘出类型与参数关系,省略了 cryptoFramework 导入、plainText 构造、解密、错误处理和安全持久化。不要原样当成完整工程运行。真实实现至少要验证:

  1. AES128|XTS 使用的组合密钥长度是否是 256 位,而不是误传单个 AES-128 的 16 字节密钥。
  2. 加密与解密对同一存储单元使用相同调整值;不同单元的映射可追踪,重启后不会丢。
  3. 数据单元长度、分片边界和错误返回符合目标 SDK 文档;不要凭一个短字符串 Demo 推断大文件行为。
  4. 对篡改、损坏和异常断电设计上层检测与恢复。XTS 不会自动给出认证标签,也不负责审计是谁改了文件。

本机脚本最后的 16 字节密钥拒绝测试,不代表所有鸿蒙错误码与 Node/OpenSSL 相同;它只帮助开发者在设计阶段记住“XTS 密钥长度加倍”这个边界。鸿蒙端最终还要跑真实 API 26 编译、设备加解密与损坏数据测试。

我会怎样选方案

如果需要的是存储层固定数据单元保密,且有完善的单元映射、密钥存放、备份恢复和上层完整性方案,才把 XTS 放进候选。若需求是应用层消息、共享文件交换或配置内容同时要求防篡改,我不会因为 API 26 新增了 XTS 就硬套进去;优先评估能够提供认证的方案。模式的“新”,不能替代需求的“对”。

验收时我会把测试拆成两张清单:功能清单检查不同单元、覆盖写入、恢复后解密;安全清单检查篡改后的拒绝策略、密钥生命周期和数据来源可信度。两张都过,才能说系统满足目标,而不是只说 doFinal 没报错。

参考资料(核对日期:2026-09-18):

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐