From 491a711ed37fdd5632b73552a15004623ff3c43b Mon Sep 17 00:00:00 2001 From: wutiantian_gitee <1159609162@qq.com> Date: Tue, 4 Jul 2023 17:46:30 +0800 Subject: [PATCH] modify doc of cryptFramework Signed-off-by: wutiantian_gitee <1159609162@qq.com> --- .../security/cryptoFramework-guidelines.md | 15 +- .../reference/apis/js-apis-cryptoFramework.md | 22 +- .../security/cryptoFramework-guidelines.md | 375 +++++++++++++++++- .../security/cryptoFramework-overview.md | 129 +++++- 4 files changed, 511 insertions(+), 30 deletions(-) diff --git a/en/application-dev/security/cryptoFramework-guidelines.md b/en/application-dev/security/cryptoFramework-guidelines.md index f1a037f2bb..bea49347b3 100644 --- a/en/application-dev/security/cryptoFramework-guidelines.md +++ b/en/application-dev/security/cryptoFramework-guidelines.md @@ -58,12 +58,11 @@ function generateAsyKey() { // Use the key generator to randomly generate an asymmetric key pair. let keyGenPromise = rsaGenerator.generateKeyPair(); keyGenPromise.then( keyPair => { - globalKeyPair = keyPair; - let pubKey = globalKeyPair.pubKey; - let priKey = globalKeyPair.priKey; + let pubKey = keyPair.pubKey; + let priKey = keyPair.priKey; // Obtain the binary data of the asymmetric key pair. - pkBlob = pubKey.getEncoded(); - skBlob = priKey.getEncoded(); + let pkBlob = pubKey.getEncoded(); + let skBlob = priKey.getEncoded(); AlertDialog.show({ message : "pk bin data" + pkBlob.data} ); AlertDialog.show({ message : "sk bin data" + skBlob.data} ); }) @@ -145,7 +144,7 @@ function convertEccAsyKey() { let priKeyArray = new Uint8Array([48,49,2,1,1,4,32,115,56,137,35,207,0,60,191,90,61,136,105,210,16,27,4,171,57,10,61,123,40,189,28,34,207,236,22,45,223,10,189,160,10,6,8,42,134,72,206,61,3,1,7]); let pubKeyBlob = { data: pubKeyArray }; let priKeyBlob = { data: priKeyArray }; - let generator = cryptoFrameWork.createAsyKeyGenerator("ECC256"); + let generator = cryptoFramework.createAsyKeyGenerator("ECC256"); generator.convertKey(pubKeyBlob, priKeyBlob, (error, data) => { if (error) { AlertDialog.show({message : "Convert keypair fail"}); @@ -884,7 +883,7 @@ function stringToUint8Array(str) { } // Encrypt the message in promise mode. -function encryptMessageProMise() { +function encryptMessagePromise() { // Create an AsyKeyGenerator instance. let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2"); // Create a Cipher instance. @@ -927,7 +926,7 @@ function encryptMessageCallback() { } // Encrypt and decrypt the message in promise mode. -function decryptMessageProMise() { +function decryptMessagePromise() { // Create an AsyKeyGenerator instance. let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2"); // Create a Cipher instance for encryption. diff --git a/zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md b/zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md index b44328c930..73bff799e5 100644 --- a/zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md +++ b/zh-cn/application-dev/reference/apis/js-apis-cryptoFramework.md @@ -58,7 +58,7 @@ buffer数组。 | 名称 | 类型 | 可读 | 可写 | 说明 | | ---- | --------------------- | ---- | ---- | ------------------------------------------------------------ | -| iv | [DataBlob](#datablob) | 是 | 是 | 指明加解密参数iv。常见取值如下:
- AES的CBC\|CTR\|OFB\|CFB模式:iv长度为16字节
- 3DES的CBC\|OFB\|CFB模式:iv长度为8字节 | +| iv | [DataBlob](#datablob) | 是 | 是 | 指明加解密参数iv。常见取值如下:
- AES的CBC\|CTR\|OFB\|CFB模式:iv长度为16字节
- 3DES的CBC\|OFB\|CFB模式:iv长度为8字节
- SM4的CBC\|CTR\|OFB\|CFB模式:iv长度为16字节。 | > **说明:** > @@ -1297,7 +1297,7 @@ createCipher(transformation: string): Cipher > **说明:** > > 1. 目前对称加解密中,PKCS5和PKCS7的实现相同,其padding长度和分组长度保持一致(即PKCS5和PKCS7在3DES中均按照8字节填充,在AES中均按照16字节填充),另有NoPadding表示不填充。
开发者需要自行了解密码学不同分组模式的差异,以便选择合适的参数规格。例如选择ECB和CBC模式时,建议启用填充,否则必须确保明文长度是分组大小的整数倍;选择其他模式时,可以不启用填充,此时密文长度和明文长度一致(即可能不是分组大小的整数倍)。 -> 2. 使用RSA进行非对称加解密时,必须创建两个Cipher对象分别进行加密和解密操作,而不能对同一个Cipher对象进行加解密。对称加解密没有此要求(即只要算法规格一样,可以对同一个Cipher对象进行加解密操作)。 +> 2. 使用RSA、SM2进行非对称加解密时,必须创建两个Cipher对象分别进行加密和解密操作,而不能对同一个Cipher对象进行加解密。对称加解密没有此要求(即只要算法规格一样,可以对同一个Cipher对象进行加解密操作)。 **返回值:** @@ -1335,7 +1335,7 @@ try { 一次完整的加/解密流程在对称加密和非对称加密中略有不同: - 对称加解密:init为必选,update为可选(且允许多次update加/解密大数据),doFinal为必选;doFinal结束后可以重新init开始新一轮加/解密流程。 -- RSA非对称加解密:init为必选,不支持update操作,doFinal为必选(允许连续多次doFinal加/解密大数据);RSA不支持重复init,切换加解密模式或填充方式时,需要重新创建Cipher对象。 +- RSA、SM2非对称加解密:init为必选,不支持update操作,doFinal为必选(允许连续多次doFinal加/解密大数据);RSA不支持重复init,切换加解密模式或填充方式时,需要重新创建Cipher对象。 ### 属性 @@ -1447,7 +1447,7 @@ update(data: DataBlob, callback: AsyncCallback\): void > 2. 根据数据量,可以不调用update(即[init](#init-2)完成后直接调用[doFinal](#dofinal-2))或多次调用update。
> 算法库目前没有对update(单次或累计)的数据量设置大小限制,建议对于大数据量的对称加解密,采用多次update的方式传入数据。
> AES使用多次update操作的示例代码详见开发指导“[使用加解密操作](../../security/cryptoFramework-guidelines.md#使用加解密操作)”。 -> 3. RSA非对称加解密不支持update操作。 +> 3. RSA、SM2非对称加解密不支持update操作。 **系统能力:** SystemCapability.Security.CryptoFramework @@ -1508,7 +1508,7 @@ update(data: DataBlob): Promise\ > 2. 根据数据量,可以不调用update(即[init](#init-2)完成后直接调用[doFinal](#dofinal-2))或多次调用update。
> 算法库目前没有对update(单次或累计)的数据量设置大小限制,建议对于大数据量的对称加解密,可以采用多次update的方式传入数据。
> AES使用多次update操作的示例代码详见开发指导“[使用加解密操作](../../security/cryptoFramework-guidelines.md#使用加解密操作)”。 -> 3. RSA非对称加解密不支持update操作。 +> 3. RSA、SM2非对称加解密不支持update操作。 **系统能力:** SystemCapability.Security.CryptoFramework @@ -1570,14 +1570,14 @@ doFinal(data: DataBlob, callback: AsyncCallback\): void - 对于GCM和CCM模式的对称加密:一次加密流程中,如果将每一次update和doFinal的结果拼接起来,会得到“密文+authTag”,即末尾的16字节(GCM模式)或12字节(CCM模式)是authTag,而其余部分均为密文。(也就是说,如果doFinal的data参数传入null,则doFinal的结果就是authTag)
authTag需要填入解密时的[GcmParamsSpec](#gcmparamsspec)或[CcmParamsSpec](#ccmparamsspec);密文则作为解密时的入参data。 - 对于其他模式的对称加解密、GCM和CCM模式的对称解密:一次加/解密流程中,每一次update和doFinal的结果拼接起来,得到完整的明文/密文。 -(2)在RSA非对称加解密中,doFinal加/解密本次传入的数据,通过注册回调函数获取加密或者解密数据。如果数据量较大,可以多次调用doFinal,拼接结果得到完整的明文/密文。 +(2)在RSA、SM2非对称加解密中,doFinal加/解密本次传入的数据,通过注册回调函数获取加密或者解密数据。如果数据量较大,可以多次调用doFinal,拼接结果得到完整的明文/密文。 > **说明:** > > 1. 对称加解密中,调用doFinal标志着一次加解密流程已经完成,即[Cipher](#cipher)实例的状态被清除,因此当后续开启新一轮加解密流程时,需要重新调用[init()](init-2)并传入完整的参数列表进行初始化
(比如即使是对同一个Cipher实例,采用同样的对称密钥,进行加密然后解密,则解密中调用init的时候仍需填写params参数,而不能直接省略为null)。 > 2. 如果遇到解密失败,需检查加解密数据和[init](#init-2)时的参数是否匹配,包括GCM模式下加密得到的authTag是否填入解密时的GcmParamsSpec等。 > 3. doFinal的结果可能为null,因此使用.data字段访问doFinal结果的具体数据前,请记得先判断结果是否为null,避免产生异常。 -> 4. RSA非对称加解密时多次doFinal操作的示例代码详见开发指导“[使用加解密操作](../../security/cryptoFramework-guidelines.md#使用加解密操作)”。 +> 4. RSA、SM2非对称加解密时多次doFinal操作的示例代码详见开发指导“[使用加解密操作](../../security/cryptoFramework-guidelines.md#使用加解密操作)”。 **系统能力:** SystemCapability.Security.CryptoFramework @@ -1626,14 +1626,14 @@ doFinal(data: DataBlob): Promise\ - 对于GCM和CCM模式的对称加密:一次加密流程中,如果将每一次update和doFinal的结果拼接起来,会得到“密文+authTag”,即末尾的16字节(GCM模式)或12字节(CCM模式)是authTag,而其余部分均为密文。(也就是说,如果doFinal的data参数传入null,则doFinal的结果就是authTag)
authTag需要填入解密时的[GcmParamsSpec](#gcmparamsspec)或[CcmParamsSpec](#ccmparamsspec);密文则作为解密时的入参data。 - 对于其他模式的对称加解密、GCM和CCM模式的对称解密:一次加/解密流程中,每一次update和doFinal的结果拼接起来,得到完整的明文/密文。 -(2)在RSA非对称加解密中,doFinal加/解密本次传入的数据,通过Promise获取加密或者解密数据。如果数据量较大,可以多次调用doFinal,拼接结果得到完整的明文/密文。 +(2)在RSA、SM2非对称加解密中,doFinal加/解密本次传入的数据,通过Promise获取加密或者解密数据。如果数据量较大,可以多次调用doFinal,拼接结果得到完整的明文/密文。 > **说明:** > > 1. 对称加解密中,调用doFinal标志着一次加解密流程已经完成,即[Cipher](#cipher)实例的状态被清除,因此当后续开启新一轮加解密流程时,需要重新调用[init()](init-2)并传入完整的参数列表进行初始化
(比如即使是对同一个Cipher实例,采用同样的对称密钥,进行加密然后解密,则解密中调用init的时候仍需填写params参数,而不能直接省略为null)。 > 2. 如果遇到解密失败,需检查加解密数据和[init](#init-2)时的参数是否匹配,包括GCM模式下加密得到的authTag是否填入解密时的GcmParamsSpec等。 > 3. doFinal的结果可能为null,因此使用.data字段访问doFinal结果的具体数据前,请记得先判断结果是否为null,避免产生异常。 -> 4. RSA非对称加解密时多次doFinal操作的示例代码详见开发指导“[使用加解密操作](../../security/cryptoFramework-guidelines.md#使用加解密操作)”。 +> 4. RSA、SM2非对称加解密时多次doFinal操作的示例代码详见开发指导“[使用加解密操作](../../security/cryptoFramework-guidelines.md#使用加解密操作)”。 **系统能力:** SystemCapability.Security.CryptoFramework @@ -1820,7 +1820,7 @@ Sign实例生成。
支持的规格详见框架概述“[签名验签规格] | 参数名 | 类型 | 必填 | 说明 | | ------- | ------ | ---- | ------------------------------------------------------------ | -| algName | string | 是 | 指定签名算法:RSA,ECC或DSA。使用RSA PKCS1模式时需要设置摘要,使用RSA PSS模式时需要设置摘要和掩码摘要。 | +| algName | string | 是 | 指定签名算法:RSA,SM2,ECC或DSA。使用RSA PKCS1模式时需要设置摘要,使用RSA PSS模式时需要设置摘要和掩码摘要。 | **返回值**: @@ -2207,7 +2207,7 @@ Verify实例生成。
支持的规格详见框架概述“[签名验签规 | 参数名 | 类型 | 必填 | 说明 | | ------- | ------ | ---- | ------------------------------------------------------------ | -| algName | string | 是 | 指定签名算法:RSA,ECC或DSA。使用RSA PKCS1模式时需要设置摘要,使用RSA PSS模式时需要设置摘要和掩码摘要。 | +| algName | string | 是 | 指定签名算法:RSA,SM2,ECC或DSA。使用RSA PKCS1模式时需要设置摘要,使用RSA PSS模式时需要设置摘要和掩码摘要。 | **返回值**: diff --git a/zh-cn/application-dev/security/cryptoFramework-guidelines.md b/zh-cn/application-dev/security/cryptoFramework-guidelines.md index 0959464d69..239686e323 100644 --- a/zh-cn/application-dev/security/cryptoFramework-guidelines.md +++ b/zh-cn/application-dev/security/cryptoFramework-guidelines.md @@ -60,12 +60,11 @@ function generateAsyKey() { // 通过非对称密钥生成器,随机生成非对称密钥 let keyGenPromise = rsaGenerator.generateKeyPair(); keyGenPromise.then( keyPair => { - globalKeyPair = keyPair; - let pubKey = globalKeyPair.pubKey; - let priKey = globalKeyPair.priKey; + let pubKey = keyPair.pubKey; + let priKey = keyPair.priKey; // 获取非对称密钥的二进制数据 - pkBlob = pubKey.getEncoded(); - skBlob = priKey.getEncoded(); + let pkBlob = pubKey.getEncoded(); + let skBlob = priKey.getEncoded(); AlertDialog.show({ message : "pk bin data" + pkBlob.data} ); AlertDialog.show({ message : "sk bin data" + skBlob.data} ); }) @@ -147,7 +146,7 @@ function convertEccAsyKey() { let priKeyArray = new Uint8Array([48,49,2,1,1,4,32,115,56,137,35,207,0,60,191,90,61,136,105,210,16,27,4,171,57,10,61,123,40,189,28,34,207,236,22,45,223,10,189,160,10,6,8,42,134,72,206,61,3,1,7]); let pubKeyBlob = { data: pubKeyArray }; let priKeyBlob = { data: priKeyArray }; - let generator = cryptoFrameWork.createAsyKeyGenerator("ECC256"); + let generator = cryptoFramework.createAsyKeyGenerator("ECC256"); generator.convertKey(pubKeyBlob, priKeyBlob, (error, data) => { if (error) { AlertDialog.show({message : "Convert keypair fail"}); @@ -209,6 +208,94 @@ function testConvertAesKey() { } ``` +### 随机生成SM2密钥对,并获得二进制数据 + +示例6:随机生成非对称密钥KeyPair,并获得二进制数据(场景1、3) + +1. 创建非对称密钥生成器。 +2. 通过非对称密钥生成器随机生成非对称密钥。 +3. 获取密钥对象的二进制数据。 + +以使用Promise方式随机生成SM2密钥(256位)为例: + +```js +import cryptoFramework from '@ohos.security.cryptoFramework'; + +function generateAsyKey() { + // 创建非对称密钥生成器 + let rsaGenerator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + // 通过非对称密钥生成器,随机生成非对称密钥 + let keyGenPromise = rsaGenerator.generateKeyPair(); + keyGenPromise.then( keyPair => { + let pubKey = keyPair.pubKey; + let priKey = keyPair.priKey; + // 获取非对称密钥的二进制数据 + let pkBlob = pubKey.getEncoded(); + let skBlob = priKey.getEncoded(); + AlertDialog.show({ message : "pk bin data" + pkBlob.data} ); + AlertDialog.show({ message : "sk bin data" + skBlob.data} ); + }) +} +``` + +### 随机生成SM4密钥,并获得二进制数据 + +示例7:随机生成对称密钥SymKey,并获得二进制数据(场景1、3) + +1. 创建对称密钥生成器。 +2. 通过对称密钥生成器随机生成对称密钥。 +3. 获取算法库密钥对象的二进制数据。 + +以使用Promise方式随机生成SM4密钥(128位)为例: + +```js +import cryptoFramework from '@ohos.security.cryptoFramework'; + +// 字节流以16进制输出 +function uint8ArrayToShowStr(uint8Array) { + return Array.prototype.map + .call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2)) + .join(''); +} + +function testGenerateAesKey() { + // 创建对称密钥生成器 + let symKeyGenerator = cryptoFramework.createSymKeyGenerator("SM4_128"); + // 通过密钥生成器随机生成对称密钥 + let promiseSymKey = symKeyGenerator.generateSymKey(); + promiseSymKey.then( key => { + // 获取对称密钥的二进制数据,输出长度为256bit的字节流 + let encodedKey = key.getEncoded(); + console.info('key hex:' + uint8ArrayToShowStr(encodedKey.data)); + }) +} +``` + +### 根据SM2密钥二进制数据,生成密钥对 + +示例8:根据指定的SM2非对称密钥二进制数据,生成KeyPair对象(场景2、3) + +1. 获取SM2二进制密钥数据,封装成DataBlob对象。 +2. 调用convertKey方法,传入公钥二进制和私钥二进制(二者非必选项,可只传入其中一个),转换为KeyPair对象。 + +```js +import cryptoFramework from '@ohos.security.cryptoFramework'; + +function convertSM2AsyKey() { + let pubKeyArray = new Uint8Array([48,89,48,19,6,7,42,134,72,206,61,2,1,6,8,42,129,28,207,85,1,130,45,3,66,0,4,90,3,58,157,190,248,76,7,132,200,151,208,112,230,96,140,90,238,211,155,128,109,248,40,83,214,78,42,104,106,55,148,249,35,61,32,221,135,143,100,45,97,194,176,52,73,136,174,40,70,70,34,103,103,161,99,27,187,13,187,109,244,13,7]); + let priKeyArray = new Uint8Array([48,49,2,1,1,4,32,54,41,239,240,63,188,134,113,31,102,149,203,245,89,15,15,47,202,170,60,38,154,28,169,189,100,251,76,112,223,156,159,160,10,6,8,42,129,28,207,85,1,130,45]); + let pubKeyBlob = { data: pubKeyArray }; + let priKeyBlob = { data: priKeyArray }; + let generator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + generator.convertKey(pubKeyBlob, priKeyBlob, (error, data) => { + if (error) { + AlertDialog.show({message : "Convert keypair fail"}); + } + AlertDialog.show({message : "Convert KeyPair success"}); + }) +} +``` + ## 非对称密钥对象根据参数生成与获取参数 ### 场景说明 @@ -884,7 +971,7 @@ function stringToUint8Array(str) { } // 以Promise方式加密 -function encryptMessageProMise() { +function encryptMessagePromise() { // 生成非对称密钥生成器 let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2"); // 生成加解密生成器 @@ -927,7 +1014,7 @@ function encryptMessageCallback() { } // 以Promise方式加解密 -function decryptMessageProMise() { +function decryptMessagePromise() { // 生成非对称密钥生成器 let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2"); // 生成加解密生成器,用于加密 @@ -1211,6 +1298,220 @@ function rsaUseSpecDecryptOAEPPromise() { } ``` +### SM2加解密开发步骤 + +示例7:使用SM2非对称密钥的加解密操作 + +1. 生成SM2密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成SM2非对称密钥。 +2. 生成Cipher对象。通过createCipher接口创建Cipher对象,执行初始化操作,设置密钥及加解密模式。 +3. 执行加解密操作。通过调用Cipher对象提供的doFinal接口,执行加密操作生成密文或执行解密操作生成明文。 + +```js +import cryptoFramework from "@ohos.security.cryptoFramework" + +let plan = "This is cipher test."; + +// 可理解的字符串转成字节流 +function stringToUint8Array(str) { + let arr = []; + for (let i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + return new Uint8Array(arr); +} + +// 以Promise方式加密 +function encryptMessagePromise() { + // 生成非对称密钥生成器 + let sm2Generator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + // 生成加解密生成器 + let cipher = cryptoFramework.createCipher("SM2_256|SM3"); + // 通过非对称秘钥生成器生成非对称密钥对 + let keyGenPromise = sm2Generator.generateKeyPair(); + keyGenPromise.then(sm2KeyPair => { + let pubKey = sm2KeyPair.pubKey; + // 初始化加解密操作环境:使用公钥开始加密 + return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null); + }).then(() => { + // doFinal + let input = { data : stringToUint8Array(plan) }; + return cipher.doFinal(input); + }).then(dataBlob => { + // 获取加密后的信息 + console.info("EncryptOutPut is " + dataBlob.data); + }); +} + +// 以Callback方式加密 +function encryptMessageCallback() { + // 生成非对称密钥生成器 + let sm2Generator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + // 生成加解密生成器 + let cipher = cryptoFramework.createCipher("SM2_256|SM3"); + // 通过非对称秘钥生成器生成非对称密钥对 + sm2Generator.generateKeyPair(function (err, keyPair) { + let pubKey = keyPair.pubKey; + // 初始化加解密操作环境:使用公钥开始加密 + cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null, function (err, data) { + let input = {data : stringToUint8Array(plan) }; + // doFinal + cipher.doFinal(input, function (err, data) { + // 获取加密后的信息 + console.info("EncryptOutPut is " + data.data); + }) + }) + }) +} + +// 以Promise方式加解密 +function decryptMessagePromise() { + // 生成非对称密钥生成器 + let rsaGenerator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + // 生成加解密生成器,用于加密 + let cipher = cryptoFramework.createCipher("SM2_256|SM3"); + // 生成加解密生成器,用于解密 + let decoder = cryptoFramework.createCipher("SM2_256|SM3"); + // 通过非对称秘钥生成器生成非对称密钥对 + let keyGenPromise = rsaGenerator.generateKeyPair(); + let keyPair; + let cipherDataBlob; + let input = { data : stringToUint8Array(plan) }; + keyGenPromise.then(rsaKeyPair => { + keyPair = rsaKeyPair; + // 初始化加解密操作环境:使用公钥开始加密 + return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null); + }).then(() => { + // 加密doFinal + return cipher.doFinal(input); + }).then(dataBlob => { + // 获取加密后的信息,并用于解密的入参 + console.info("EncryptOutPut is " + dataBlob.data); + AlertDialog.show({message : "output" + dataBlob.data}); + cipherDataBlob = dataBlob; + // 初始化加解密操作环境:使用私钥开始解密 + return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null); + }).then(() => { + // 解密doFinal + return decoder.doFinal(cipherDataBlob); + }).then(decodeData => { + // 验证解密后,数据与原先数据是否保持一致 + if (decodeData.data.toString() === input.data.toString()) { + AlertDialog.show({message : "decrypt success"}); + return; + } + AlertDialog.show({message : "decrypt fail"}); + }); +} + +// 以Callback方式加解密 +function decryptMessageCallback() { + // 生成非对称密钥生成器 + let rsaGenerator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + // 生成加解密生成器,用于加密 + let cipher = cryptoFramework.createCipher("SM2_256|SM3"); + // 生成加解密生成器,用于解密 + let decoder = cryptoFramework.createCipher("SM2_256|SM3"); + let plainText = "this is cipher text"; + let input = {data : stringToUint8Array(plainText) }; + let cipherData; + let keyPair; + // 通过非对称秘钥生成器生成非对称密钥对 + rsaGenerator.generateKeyPair(function (err, newKeyPair) { + keyPair = newKeyPair; + // 初始化加解密操作环境:使用公钥开始加密 + cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null, function (err, data) { + // 加密doFinal + cipher.doFinal(input, function (err, data) { + // 获取加密后的信息,并用于解密的入参 + AlertDialog.show({ message : "EncryptOutPut is " + data.data} ); + cipherData = data; + // 初始化加解密操作环境:使用私钥开始解密 + decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null, function (err, data) { + // 解密doFinal + decoder.doFinal(cipherData, function (err, data) { + // 验证解密后,数据与原先数据是否保持一致 + if (input.data.toString() === data.data.toString()) { + AlertDialog.show({ message : "decrype success"} ); + return; + } + AlertDialog.show({ message : "decrype fail"} ); + }); + }); + }); + }); + }); +} +``` + +### SM4 ECB以callback方式加解密开发步骤: + +示例8:使用SM4对称密钥的加解密操作 + +1. 创建对称密钥生成器。 +2. 通过已有二进制数据生成密钥。 +3. 创建加解密生成器。 +4. 通过加解密生成器加密或解密数据。 + +```js +import cryptoFramework from '@ohos.security.cryptoFramework'; + +function stringToUint8Array(str) { + let arr = []; + for (let i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + return new Uint8Array(arr); +} + +// 字节流转成可理解的字符串 +function uint8ArrayToString(array) { + let arrayString = ''; + for (let i = 0; i < array.length; i++) { + arrayString += String.fromCharCode(array[i]); + } + return arrayString; +} + +// SM4 ECB模式示例,callback写法 +function testSM4Ecb() { + // 生成非对称密钥生成器 + let rsaGenerator = cryptoFramework.createSymKeyGenerator('SM4_128'); + // 生成加解密生成器,用于加密 + let cipher = cryptoFramework.createCipher("SM4_128|ECB|PKCS7"); + // 生成加解密生成器,用于解密 + let decoder = cryptoFramework.createCipher("SM4_128|ECB|PKCS7"); + let plainText = "this is cipher text"; + let input = {data : stringToUint8Array(plainText) }; + let cipherData; + let key; + // 通过非对称秘钥生成器生成非对称密钥对 + rsaGenerator.generateSymKey(function (err, newKey) { + key = newKey; + // 初始化加解密操作环境:使用公钥开始加密 + cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, null, function (err, data) { + // 加密doFinal + cipher.doFinal(input, function (err, data) { + // 获取加密后的信息,并用于解密的入参 + AlertDialog.show({ message : "EncryptOutPut is " + data.data} ); + cipherData = data; + // 初始化加解密操作环境:使用私钥开始解密 + decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, key, null, function (err, data) { + // 解密doFinal + decoder.doFinal(cipherData, function (err, data) { + // 验证解密后,数据与原先数据是否保持一致 + if (input.data.toString() === data.data.toString()) { + AlertDialog.show({ message : "decrype success"} ); + return; + } + AlertDialog.show({ message : "decrype fail"} ); + }); + }); + }); + }); + }); +} +``` + ## 使用签名验签操作 ### 场景说明 @@ -1219,6 +1520,7 @@ function rsaUseSpecDecryptOAEPPromise() { 1. 使用RSA签名验签操作 2. 使用ECC签名验签操作 3. 使用RSA签名验签,PSS模式时,获取、设置SignSpecItem参数。 +4. 使用SM2签名验签操作 > **说明:** > @@ -1600,6 +1902,63 @@ function verifyMessageCallbackPSS() { } ``` +### SM2签名验签开发步骤 + +示例5:使用SM2操作 + +1. 生成SM2密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成SM2非对称密钥。 +2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥。 +3. 执行签名操作。通过Sign类提供的update接口,添加签名数据,并调用doFinal接口生成数据的签名。 +4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥。 +5. 执行验签操作。通过Verify类提供的update接口,添加签名数据,并调用doFinal接口传入签名进行验签。 + +```js +import cryptoFramework from "@ohos.security.cryptoFramework" + +// 可理解的字符串转成字节流 +function stringToUint8Array(str) { + var arr = []; + for (var i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + var tmpArray = new Uint8Array(arr); + return tmpArray; +} + +let globalKeyPair; +let SignMessageBlob; +let plan1 = "This is Sign test plan1"; +let plan2 = "This is Sign test plan2"; +let input1 = { data: stringToUint8Array(plan1) }; +let input2 = { data: stringToUint8Array(plan2) }; + +function signAndVerify() { + let rsaGenerator = cryptoFramework.createAsyKeyGenerator("SM2_256"); + let signer = cryptoFramework.createSign("SM2_256|SM3"); + rsaGenerator.generateKeyPair(function (err, keyPair) { + globalKeyPair = keyPair; + let priKey = globalKeyPair.priKey; + signer.init(priKey, function (err, data) { + signer.update(input1, function (err, data) { + signer.sign(input2, function (err, data) { + SignMessageBlob = data; + console.info("sign output is " + SignMessageBlob.data); + let verifyer = cryptoFramework.createVerify("SM2_256|SM3"); + verifyer.init(globalKeyPair.pubKey, function (err, data) { + verifyer.update(input1, function (err, data) { + verifyer.verify(input2, SignMessageBlob, function (err, data) { + console.info("verify result is " + data); + AlertDialog.show({message:"decrype success"}) + }); + }); + }) + }); + }); + }); + }); +} +``` + ## 使用密钥协商操作 ### 场景说明 diff --git a/zh-cn/application-dev/security/cryptoFramework-overview.md b/zh-cn/application-dev/security/cryptoFramework-overview.md index d705b3244a..2c8dc02a48 100644 --- a/zh-cn/application-dev/security/cryptoFramework-overview.md +++ b/zh-cn/application-dev/security/cryptoFramework-overview.md @@ -23,6 +23,10 @@ 3DES,也称为 3DESede 或 TripleDES,是三重数据加密算法,相当于是对每个数据块应用三次DES的对称加密算法,它使用3个64位的密钥对数据块进行三次加密。相比DES,3DES因密钥长度变长,安全性有所提高,但其处理速度不高。因此又出现了AES加密算法,AES较于3DES速度更快、安全性更高。 +- **SM4密钥** + + SM4密码算法是一个分组算法,该算法的分组长度为128位,密钥的长度为128位。加密算法与密钥扩展算法都采用32轮非线性迭代结构,数据解密和数据加密的算法结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。 + ### 非对称密钥 非对称密钥使用公钥和私钥两个密钥来进行算法操作,公钥对外公开,私钥对外保密。对于加解密操作,一般使用公钥对明文进行加密形成密文,持有私钥的人即可对密文解密形成明文。对于签名验签操作,使用私钥对明文进行签名,公钥持有者可以通过公钥对签名数据做验签,验证数据是否被篡改。 @@ -77,6 +81,26 @@ pk:公钥,pk = (g ^ sk) mod p。 +- **SM2密钥** + + SM2算法是一种基于椭圆曲线的公钥密码算法,其密钥长度为256位。SM2算法采用的是Fp域上的椭圆曲线。 + + Fp域下的SM2密钥参数,包括: + + p: 大于3的素数,用于确定Fp。 + + a, b: 定义椭圆曲线的方程。 + + g: 椭圆曲线的一个基点(base point),可由gx,gy表示。 + + n: 基点g的阶(order)。 + + h: 余因子(cofactor)。 + + sk: 私钥,是一个随机整数,小于n。 + + pk: 公钥,是椭圆曲线上的一个点, pk = sk * g。 + ### 加解密 - **对称AES加解密** @@ -105,6 +129,19 @@ > ECB、CBC加密模式,明文长度不是64位整数倍,必须使用填充方法补足。
> 由于需要填充至分组大小,所以实际算法库中的PKCS5和PKCS7都是以分组大小作为填充长度的,即3DES加密填充至8字节。 +- **对称SM4加解密** + + 算法库目前提供了SM4加解密常用的6种加密模式:ECB、CBC、CTR、OFB、CFB和CFB128。SM4为分组加密算法,分组长度大小为128位。实际应用中明文最后一组可能不足128位,不足数据可以使用各种padding模式做数据填充。下文中描述了各个padding的区别: + + - NoPadding:不带填充。 + - PKCS5:填充字符由一个字节序列组成,每个字节填充该填充字节序列的长度,规定是8字节填充。 + - PKCS7:填充字符和PKCS5填充方法一致,但是可以在1-255字节之间任意填充。 + + > **说明:** + > + > ECB、CBC加密模式,明文长度不是128位整数倍,必须使用填充方法补足。
+ > 由于需要填充至分组大小,所以实际算法库中的PKCS5和PKCS7都是以分组大小作为填充长度的,即SM4加密填充至16字节。 + - **非对称RSA加解密** RSA为块加密算法,加密长度需要在固定长度进行,实际应用中会使用各种padding模式做数据填充。算法库目前提供了RSA加解密常用的三种模式:NoPadding、PKCS1和PKCS1_OAEP。下文中描述了各个padding的区别: @@ -121,6 +158,11 @@ > > RSA钥模 = (RSA的bits + 7) / 8 + - **非对称SM2加解密** + + SM2为块加密算法,加密长度需要在固定长度进行。OpenSSL中SM2算法加解密时使用零填充模式,如果数据长度不足32字节,则需要进行填充,填充的方式是在数据后面添加若干个0x00字节,直到数据长度达到32字节为止。 + SM2加密过程中,首先需要生成一个随机数k,并使用公钥对kG进行加密,得到C1。然后,将明文数据进行SM3摘要计算,得到摘要值,并将摘要值与C1进行拼接,得到C3。接着,使用k和摘要值作为参数,对明文数据进行加密,得到C2。最后,将C1、C3、C2按顺序拼接起来,得到最终的加密结果。通过加入摘要值,增强了加密结果的安全性,同时也方便了解密过程中的验证。 + ### 签名验签 - **RSA签名验签** @@ -155,15 +197,16 @@ ### 摘要 -消息摘要MD算法是一种能将任意长度的输入消息,通过哈希算法生成长度固定的摘要的算法。消息摘要算法通过其不可逆的特性能被用于敏感信息的加密。消息摘要算法也被称为哈希算法或单向散列算法。 +消息摘要算法是一种能将任意长度的输入消息,通过哈希算法生成长度固定的摘要的算法。消息摘要算法通过其不可逆的特性能被用于敏感信息的加密。消息摘要算法也被称为哈希算法或单向散列算法。 在摘要算法相同时,生成的摘要值主要有下列特点: - 当输入消息相同时,生成摘要序列相同。 - 当输入消息的长度不一致时,生成摘要序列长度固定(摘要长度由算法决定)。 - 当输入消息不一致时,生成摘要序列几乎不会相同(依然存在相同概率,由摘要长度决定相同概率)。 -消息摘要算法主要分为三类:MD,SHA与MAC(详见HMAC章节)。 -MD算法包括MD2,MD4和MD5。 +消息摘要算法主要分为两类:SHA和SM3。 +SM3包括MD和MAC(详见HMAC章节)。 +SM3中MD算法包括MD2,MD4和MD5。 SHA算法主要包括SHA1,SHA224,SHA256,SHA384,SHA512。 ### 消息验证码 @@ -350,6 +393,39 @@ HMAC(Hash-based Message Authentication Code)是一种基于密钥的消息 > 1. DSA不支持通过指定私钥参数(p, q, g, sk)来生成私钥。 > 2. 当使用公共参数(p, q, g)来生成DSA密钥对时,DSA密钥长度至少需要1024位。 + +### SM2密钥生成规格 + +> **说明:** +> +> 从API version 10开始, 支持使用密钥参数来生成SM2密钥. + +- 支持以字符串参数来生成SM2密钥,其生成参数如下表所示: + + |非对称密钥算法|密钥长度(bit)|字符串参数| + |---|---|---| + |SM2|256|SM2_256| + + > **说明:** + > + > “字符串参数”是“非对称密钥算法”和“密钥长度”使用连接符号“_”拼接而成,用于在创建非对称密钥生成器时,指定密钥规格。 + +### SM4密钥生成规格 + +> **说明:** +> +> 从API version 10开始, 支持使用密钥参数来生成SM4密钥. + +- 支持以字符串参数来生成SM4密钥,其生成参数如下表所示: + + |对称密钥算法|密钥长度(bit)|字符串参数| + |---|---|---| + |SM4|128|SM4_128| + + > **说明:** + > + > “字符串参数”是“对称密钥算法”和“密钥长度”使用连接符号“_”拼接而成,用于在创建对称密钥生成器时,指定密钥规格。 + ## 加解密规格 ### 对称加解密 @@ -372,11 +448,18 @@ HMAC(Hash-based Message Authentication Code)是一种基于密钥的消息 |AES|CFB|AES[128\|192\|256]\|CFB\|[NoPadding\|PKCS5\|PKCS7]| |AES|GCM|AES[128\|192\|256]\|GCM\|[NoPadding\|PKCS5\|PKCS7]| |AES|CCM|AES[128\|192\|256]\|CCM\|[NoPadding\|PKCS5\|PKCS7]| + |SM4|ECB|SM4_128\|ECB\|[NoPadding\|PKCS5\|PKCS7]| + |SM4|CBC|SM4_128\|CBC\|[NoPadding\|PKCS5\|PKCS7]| + |SM4|CTR|SM4_128\|CTR\|[NoPadding\|PKCS5\|PKCS7]| + |SM4|OFB|SM4_128\|OFB\|[NoPadding\|PKCS5\|PKCS7]| + |SM4|CFB|SM4_128\|CFB\|[NoPadding\|PKCS5\|PKCS7]| + |SM4|CFB128|SM4_128\|CFB128\|[NoPadding\|PKCS5\|PKCS7]| > **说明:** > > 1. []中只能任选一项。 > 2. “字符串参数”是“对称加解密算法(含密钥长度)”、“分组模式”、“填充模式”拼接而成,用于在创建对称加解密实例时,指定对称加解密算法规格。 + > 3. “字符串参数”中“SM4”和密钥长度间需要添加下划线 ### 非对称RSA加解密 @@ -488,6 +571,24 @@ RSA加解密时,涉及三种填充模式:NoPadding, PKCS1和PKCS1_OAEP。 > > 上表说明了算法库对于OAEP参数的获取和设置支持情况,打√的表示需要对该参数具有获取或设置的能力。 + +### 非对称SM2加解密 + +> **说明:** +> +> 从API version 10开始, 支持非对称SM2加解密不带密钥长度的规格。 + +SM2加解密时,仅支持C1C3C2密文排列组合模式。SM2非对称加密的结果由C1,C2,C3三部分组成。其中C1是根据生成的随机数计算出的椭圆曲线点,C2是密文数据,C3是通过指定摘要算法计算的值。国密新标准以C1,C3,C2顺序存放,不支持无摘要加密。 +- 支持的加密算法: + + | 非对称密钥类型 | 摘要 | 字符串参数 | + |---|---|---| + |SM2_256|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512\|SM3]|SM2_256\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512\|SM3]| + + > **说明:** + > + > “字符串参数”是“非对称密钥类型”、“填充模式”拼接而成,用于在创建非对称加解密实例时,指定非对称加解密算法规格。 + ## 签名验签规格 ### RSA签名验签 @@ -628,6 +729,26 @@ RSA签名验签时,涉及两种填充模式:PKCS1和PSS。 > 例如:"DSA1024|SHA256" > 3. 在上表最后一行,为了兼容由密钥参数生成的密钥,DSA签名验签参数输入密钥类型时支持不带长度,签名验签运算取决于实际输入的密钥长度。 + +### SM2签名验签 + +> **说明:** +> +> 从API version 10开始, 支持SM2签名验签规格。 + +- 支持的SM2参数: + + |非对称密钥类型|摘要|字符串参数| + |---|---|---| + |SM2_256|SM3|SM2_256\|SM3| + |SM2|SM3|SM2\|SM3| + + > **说明:** + > + > 1. []内的参数只能任选一项,非[]内的为固定值。 + > 2. 使用时请从表格中选择非对称密钥类型、摘要二个数据,用|拼接成“字符串参数”,用于在创建非对称签名验签实例时,指定非对称签名验签算法规格。
+ > SM2签名时只支持SM3摘要。 + ## 密钥协商规格 ### ECDH @@ -664,6 +785,7 @@ RSA签名验签时,涉及两种填充模式:PKCS1和PSS。 |HASH|SHA384| |HASH|SHA512| |HASH|MD5| + |HASH|SM3| > **说明:** > @@ -680,6 +802,7 @@ RSA签名验签时,涉及两种填充模式:PKCS1和PSS。 |HASH|SHA256| |HASH|SHA384| |HASH|SHA512| + |HASH|SM3| > **说明:** > -- GitLab