使用ECIES混合加解密(ArkTS)
从API版本26.0.0开始,支持ECIES算法,ECIES是一种基于椭圆曲线密码学的加密算法。
约束条件:
- 密钥协商算法支持ECC256、ECC384、ECC521。
- 密钥派生算法仅支持X963KDF,摘要算法支持SHA1、SHA256、SHA384、SHA512。
- 对称加密算法支持AES128、AES192、AES256。
- 分组模式仅支持GCM。
开发步骤
加密
-
调用cryptoFramework.createAsyKeyGenerator和SymKeyGenerator.generateKeyPair,使用ECC算法生成密钥对。
-
调用cryptoFramework.createKeyAgreement和KeyAgreement.generateSecret,基于本端的私钥(KeyPair.priKey)与对端的公钥(KeyPair.pubKey)进行密钥协商,返回共享密钥。
-
X963KDF密钥派生,调用cryptoFramework.createKdf和Kdf.generateSecret,基于协商的共享密钥(Secret)进行密钥派生,返回派生后的密钥。
-
调用cryptoFramework.createCipher,指定字符串参数'AES128|GCM',创建对称密钥类型为AES128、分组模式为GCM的Cipher实例,用于完成加密操作。
-
调用Cipher.init,设置模式为加密(cryptoFramework.CryptoMode.ENCRYPT_MODE),指定加密密钥(SymKey)和GCM模式对应的加密参数(GcmParamsSpec),初始化加密Cipher实例。
-
调用Cipher.update,更新数据(明文)。
-
调用Cipher.doFinal,获取加密后的数据。
-
读取GcmParamsSpec.authTag作为解密的认证信息。
解密
-
调用cryptoFramework.createAsyKeyGenerator和SymKeyGenerator.generateKeyPair,使用ECC算法生成密钥对。
-
调用cryptoFramework.createKeyAgreement和KeyAgreement.generateSecret,基于本端的私钥(KeyPair.priKey)与对端的公钥(KeyPair.pubKey)进行密钥协商,返回共享密钥。
-
X963KDF密钥派生,调用cryptoFramework.createKdf和Kdf.generateSecret,基于协商的共享密钥(Secret)进行密钥派生,返回派生后的密钥。
-
调用cryptoFramework.createCipher,指定字符串参数'AES128|GCM',创建对称密钥类型为AES128、分组模式为GCM的Cipher实例,用于完成解密操作。
-
调用Cipher.init,设置模式为解密(cryptoFramework.CryptoMode.DECRYPT_MODE),指定解密密钥(SymKey)和GCM模式对应的解密参数(GcmParamsSpec),初始化解密Cipher实例。
-
调用Cipher.update,更新数据(密文)。
-
调用Cipher.doFinal,获取解密后的数据。
示例代码
-
异步方法示例:
import { cryptoFramework } from '@kit.CryptoArchitectureKit'; import { buffer } from '@kit.ArkTS'; namespace ECIES { function generateGcmParamsSpec(ivData: Uint8Array): cryptoFramework.GcmParamsSpec { let ivBlob: cryptoFramework.DataBlob = { data: ivData, }; let rand: cryptoFramework.Random = cryptoFramework.createRandom(); let aadBlob: cryptoFramework.DataBlob = rand.generateRandomSync(8); let tagBlob: cryptoFramework.DataBlob = rand.generateRandomSync(16); // GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中 let gcmParams: cryptoFramework.GcmParamsSpec = { iv: ivBlob, aad: aadBlob, authTag: tagBlob, algName: 'GcmParamsSpec', }; return gcmParams; } async function generateSecret(priKey: cryptoFramework.PriKey, pubKey: cryptoFramework.PubKey): Promise<cryptoFramework.DataBlob> { // EC密钥协商 let agreement: cryptoFramework.KeyAgreement = cryptoFramework.createKeyAgreement('ECC256'); let keyData: cryptoFramework.DataBlob = await agreement.generateSecret(priKey, pubKey); let infoData: Uint8Array = new Uint8Array(buffer.from('infostring', 'utf-8').buffer); let spec: cryptoFramework.X963KdfSpec = { algName: 'X963KDF', key: keyData.data, info: infoData, keySize: 32, // 前16字节作为AES128的IV,后16字节作为密钥 }; // 使用X963KDF进行密钥派生 let kdf = cryptoFramework.createKdf('X963KDF|SHA256'); let secret = await kdf.generateSecret(spec); return secret; } async function generateSymKey(secret: cryptoFramework.DataBlob): Promise<cryptoFramework.SymKey> { let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128'); let keyData: cryptoFramework.DataBlob = { data: secret.data.slice(16), }; let symKey: cryptoFramework.SymKey = await symKeyGenerator.convertKey(keyData); return symKey; } async function encrypt(symKey: cryptoFramework.SymKey, gcmParams: cryptoFramework.GcmParamsSpec, plainText: cryptoFramework.DataBlob): Promise<cryptoFramework.DataBlob> { // AES-GCM对称加密 let cipher: cryptoFramework.Cipher = cryptoFramework.createCipher('AES128|GCM'); await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, gcmParams); let cipherText: cryptoFramework.DataBlob = await cipher.update(plainText); gcmParams.authTag = await cipher.doFinal(null); return cipherText; } async function decrypt(symKey: cryptoFramework.SymKey, gcmParams: cryptoFramework.GcmParamsSpec, cipherText: cryptoFramework.DataBlob): Promise<cryptoFramework.DataBlob> { // AES-GCM对称解密 let cipher: cryptoFramework.Cipher = cryptoFramework.createCipher('AES128|GCM'); await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, gcmParams); let plainText: cryptoFramework.DataBlob = await cipher.doFinal(cipherText); return plainText; } export async function doEciesTest(): Promise<string> { try { // 生成A端和B端的EC密钥对 let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator('ECC256'); let keyPairA: cryptoFramework.KeyPair = asyKeyGenerator.generateKeyPairSync(); let keyPairB: cryptoFramework.KeyPair = asyKeyGenerator.generateKeyPairSync(); // A端加密:A端的私钥 + B端的公钥 let secretA: cryptoFramework.DataBlob = await generateSecret(keyPairA.priKey, keyPairB.pubKey); let symKeyA: cryptoFramework.SymKey = await generateSymKey(secretA); let ivData: Uint8Array = secretA.data.slice(0, 16); let gcmParams: cryptoFramework.GcmParamsSpec = generateGcmParamsSpec(ivData); let message: string = 'This is a test message!!!'; let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer), }; let cipherData: cryptoFramework.DataBlob = await encrypt(symKeyA, gcmParams, plainText); // B端解密:B端的私钥 + A端的公钥 let secretB: cryptoFramework.DataBlob = await generateSecret(keyPairB.priKey, keyPairA.pubKey); let symKeyB: cryptoFramework.SymKey = await generateSymKey(secretB); let plainData: cryptoFramework.DataBlob = await decrypt(symKeyB, gcmParams, cipherData); console.info('doEciesTest success, message: ' + buffer.from(plainData.data).toString('utf-8')); return 'Success'; } catch (error) { console.error(`doEciesTest failed, error: ${JSON.stringify(error)}`); return 'Failed'; } } } -
同步方法示例:
import { cryptoFramework } from '@kit.CryptoArchitectureKit'; import { buffer } from '@kit.ArkTS'; namespace ECIES { function generateGcmParamsSpec(ivData: Uint8Array): cryptoFramework.GcmParamsSpec { let ivBlob: cryptoFramework.DataBlob = { data: ivData, }; let rand: cryptoFramework.Random = cryptoFramework.createRandom(); let aadBlob: cryptoFramework.DataBlob = rand.generateRandomSync(8); let tagBlob: cryptoFramework.DataBlob = rand.generateRandomSync(16); // GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中 let gcmParams: cryptoFramework.GcmParamsSpec = { iv: ivBlob, aad: aadBlob, authTag: tagBlob, algName: 'GcmParamsSpec', }; return gcmParams; } function generateSecret(priKey: cryptoFramework.PriKey, pubKey: cryptoFramework.PubKey): cryptoFramework.DataBlob { // EC密钥协商 let agreement: cryptoFramework.KeyAgreement = cryptoFramework.createKeyAgreement('ECC256'); let keyData: cryptoFramework.DataBlob = agreement.generateSecretSync(priKey, pubKey); let infoData: Uint8Array = new Uint8Array(buffer.from('infostring', 'utf-8').buffer); let spec: cryptoFramework.X963KdfSpec = { algName: 'X963KDF', key: keyData.data, info: infoData, keySize: 32, // 前16字节作为AES128的IV,后16字节作为密钥 }; // 使用X963KDF进行密钥派生 let kdf = cryptoFramework.createKdf('X963KDF|SHA256'); let secret = kdf.generateSecretSync(spec); return secret; } function generateSymKey(secret: cryptoFramework.DataBlob): cryptoFramework.SymKey { let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128'); let keyData: cryptoFramework.DataBlob = { data: secret.data.slice(16), }; let symKey: cryptoFramework.SymKey = symKeyGenerator.convertKeySync(keyData); return symKey; } function encrypt(symKey: cryptoFramework.SymKey, gcmParams: cryptoFramework.GcmParamsSpec, plainText: cryptoFramework.DataBlob): cryptoFramework.DataBlob { // AES-GCM对称加密 let cipher: cryptoFramework.Cipher = cryptoFramework.createCipher('AES128|GCM'); cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, gcmParams); let cipherText: cryptoFramework.DataBlob = cipher.updateSync(plainText); gcmParams.authTag = cipher.doFinalSync(null); return cipherText; } function decrypt(symKey: cryptoFramework.SymKey, gcmParams: cryptoFramework.GcmParamsSpec, cipherText: cryptoFramework.DataBlob): cryptoFramework.DataBlob { // AES-GCM对称解密 let cipher: cryptoFramework.Cipher = cryptoFramework.createCipher('AES128|GCM'); cipher.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, gcmParams); let plainText: cryptoFramework.DataBlob = cipher.doFinalSync(cipherText); return plainText; } export function doEciesTest(): string { try { // 生成A端和B端的EC密钥对 let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator('ECC256'); let keyPairA: cryptoFramework.KeyPair = asyKeyGenerator.generateKeyPairSync(); let keyPairB: cryptoFramework.KeyPair = asyKeyGenerator.generateKeyPairSync(); // A端加密:A端的私钥 + B端的公钥 let secretA: cryptoFramework.DataBlob = generateSecret(keyPairA.priKey, keyPairB.pubKey); let symKeyA: cryptoFramework.SymKey = generateSymKey(secretA); let ivData: Uint8Array = secretA.data.slice(0, 16); let gcmParams: cryptoFramework.GcmParamsSpec = generateGcmParamsSpec(ivData); let message: string = 'This is a test message!!!'; let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer), }; let cipherData: cryptoFramework.DataBlob = encrypt(symKeyA, gcmParams, plainText); // B端解密:B端的私钥 + A端的公钥 let secretB: cryptoFramework.DataBlob = generateSecret(keyPairB.priKey, keyPairA.pubKey); let symKeyB: cryptoFramework.SymKey = generateSymKey(secretB); let plainData: cryptoFramework.DataBlob = decrypt(symKeyB, gcmParams, cipherData); console.info('doEciesTest success, message: ' + buffer.from(plainData.data).toString('utf-8')); return 'Success'; } catch (error) { console.error(`doEciesTest failed, error: ${JSON.stringify(error)}`); return 'Failed'; } } }