未验证 提交 3ed02bcc 编写于 作者: O openharmony_ci 提交者: Gitee

!19472 【加解密算法库】新增DSA、ECC、RSA、Rand算法接口和规格

Merge pull request !19472 from xwb/master
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -4,21 +4,21 @@
>
> 本开发指导基于API version 9,OH SDK版本3.2.7以上,适用于JS语言开发
## 使用密钥对象生成与转换操作
## 密钥对象生成与转换操作
**场景说明**
### 场景说明
使用密钥生成操作中,典型的场景有:
1. 随机生成算法库密钥对象。该对象可用于后续的加解密等操作。
2. 根据指定数据生成算法库密钥对象(也就是将外部或存储的二进制数据转换为算法库的密钥对象)。该对象可用于后续的加解密等操作。
3. 获取算法库密钥对象的二进制数据,用于存储或传输。
2. 根据密钥参数生成指定的算法库密钥对象。该对象可用于后续的加解密等操作。
3. 根据指定数据生成算法库密钥对象(也就是将外部或存储的二进制数据转换为算法库的密钥对象)。该对象可用于后续的加解密等操作。
4. 获取算法库密钥对象的二进制数据,用于存储或传输。
5. 对于非对称密钥,获取密钥对象的参数属性,用于存储或运输。
> **说明**:密钥对象Key包括对称密钥SymKey和非对称密钥(公钥PubKey和私钥PriKey),其中公钥和私钥组成密钥对KeyPair。密钥之间的具体关系可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)。
> **说明:**
>
> 密钥对象Key包括对称密钥SymKey和非对称密钥(公钥PubKey和私钥PriKey),其中公钥和私钥组成密钥对KeyPair。密钥之间的具体关系可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)。
**接口及参数说明**
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
......@@ -27,6 +27,7 @@
|实例名|接口名|描述|
|---|---|---|
|cryptoFramework|createAsyKeyGenerator(algName : string) : AsyKeyGenerator|根据algName设置的非对称密钥规格,创建非对称密钥生成器对象|
|cryptoFramework|createAsyKeyGeneratorBySpec(asyKeySpec: AsyKeySpec): AsyKeyGeneratorBySpec;|根据密钥参数设置的非对称密钥规格,创建非对称密钥生成器对象|
|cryptoFramework|createSymKeyGenerator(algName : string) : SymKeyGenerator|根据algName设置的对称密钥规格,创建对称密钥生成器对象|
|AsyKeyGenerator|generateKeyPair(callback : AsyncCallback\<KeyPair>) : void|使用callback方式,随机生成非对称密钥对象KeyPair|
|AsyKeyGenerator|generateKeyPair() : Promise\<KeyPair>|使用Promise方式,随机生成非对称密钥对象KeyPair|
......@@ -38,8 +39,7 @@
| SymKeyGenerator |convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise\<KeyPair>| 使用Promise方式,根据指定的二进制数据,生成对称密钥对象SymKey |
| Key | getEncoded() : DataBlob; | 获取Key密钥对象的二进制数据(Key的子类实例包括对称密钥SymKey、公钥PubKey、私钥PriKey) |
**开发步骤**
### 随机生成RSA密钥对,并获得二进制数据
示例1:随机生成非对称密钥KeyPair,并获得二进制数据(场景1、3)
1. 创建非对称密钥生成器;
......@@ -48,7 +48,7 @@
以使用Promise方式随机生成RSA密钥(1024位,素数个数为2)为例:
```js
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
function generateAsyKey() {
......@@ -69,6 +69,7 @@ function generateAsyKey() {
}
```
### 随机生成AES密钥,并获得二进制数据
示例2:随机生成对称密钥SymKey,并获得二进制数据(场景1、3)
1. 创建对称密钥生成器;
......@@ -77,7 +78,7 @@ function generateAsyKey() {
以使用Promise方式随机生成AES密钥(256位)为例:
```js
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
// 字节流以16进制输出
......@@ -100,12 +101,14 @@ function testGenerateAesKey() {
}
```
### 根据RSA密钥二进制数据,生成密钥对
示例3:根据指定的RSA非对称密钥二进制数据,生成KeyPair对象(场景2)
1. 获取RSA公钥或私钥二进制数据,公钥需满足ASN.1语法、X.509规范、DER编码格式,私钥需满足ASN.1语法、PKCS#8规范、DER编码格式。
2. 创建AsyKeyGenerator对象,调用convertKey方法,传入公钥二进制和私钥二进制(二者非必选项,可只传入其中一个),转换为KeyPair对象。
```js
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
function convertAsyKey() {
......@@ -121,24 +124,24 @@ function convertAsyKey() {
}
```
> **说明:**
>
> 当前convertKey操作,公钥只支持转换满足X.509规范的DER格式,私钥只支持PKCS#8规范的DER格式。
**说明**
当前convertKey操作,公钥只支持转换满足X.509规范的DER格式,私钥只支持PKCS#8规范的DER格式;
### 根据ECC密钥二进制数据,生成密钥对
示例4:根据指定的ECC非对称密钥二进制数据,生成KeyPair对象(场景2、3)
1. 获取ECC二进制密钥数据,封装成DataBlob对象。
2. 调用convertKey方法,传入公钥二进制和私钥二进制(二者非必选项,可只传入其中一个),转换为KeyPair对象。
```js
import cryptoFramework from "@ohos.security.cryptoFramework"
```javascript
function convertEccAsyKey() {
let pubKeyArray = new Uint8Array([48,89,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,3,66,0,4,83,96,142,9,86,214,126,106,247,233,92,125,4,128,138,105,246,162,215,71,81,58,202,121,26,105,211,55,130,45,236,143,55,16,248,75,167,160,167,106,2,152,243,44,68,66,0,167,99,92,235,215,159,239,28,106,124,171,34,145,124,174,57,92]);
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"});
......@@ -148,6 +151,7 @@ function convertEccAsyKey() {
}
```
### 根据3DES密钥二进制数据,生成密钥
示例5:根据指定的对称密钥二进制数据,生成SymKey对象(场景2、3)
1. 创建对称密钥生成器;
......@@ -156,7 +160,7 @@ function convertEccAsyKey() {
以使用callback方式生成3DES密钥(3DES密钥只能为192位)为例:
```js
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
// 字节流以16进制输出
......@@ -197,21 +201,222 @@ function testConvertAesKey() {
}
}
```
## 非对称密钥对象根据参数生成与获取参数
### 场景说明
使用密钥生成操作中,典型的场景有:
1. 根据非对称密钥参数生成指定的算法库密钥对象。该对象可用于后续的加解密等操作。
2. 对于非对称密钥,获取密钥对象的参数属性,用于存储或运输。
> **说明**:<br>
> 1. 从API version 10开始, 支持使用密钥参数来生成非对称密钥。
> 2. 非对称密钥(公钥PubKey和私钥PriKey),其中公钥和私钥组成密钥对KeyPair。非对称密钥参数具体可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)。
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md#asykeygeneratorbyspec10)
以上场景涉及的常用接口如下表所示:
|实例名|接口名|描述|
|---|---|---|
|AsyKeyGeneratorBySpec|generateKeyPair(callback: AsyncCallback<KeyPair>): void;|使用callback方式,根据密钥参数生成非对称密钥对象KeyPair
|AsyKeyGeneratorBySpec|generateKeyPair(): Promise<KeyPair>;|使用Promise方式,根据密钥参数生成非对称密钥对象KeyPair
|AsyKeyGeneratorBySpec|generatePriKey(callback: AsyncCallback<KeyPair>): void;|使用callback方式,根据密钥参数生成非对称私钥对象PriKey
|AsyKeyGeneratorBySpec|generatePriKey(): Promise<KeyPair>;|使用Promise方式,根据密钥参数生成非对称私钥对象PriKey
|AsyKeyGeneratorBySpec|generatePubKey(callback: AsyncCallback<KeyPair>): void;|使用callback方式,根据密钥参数生成非对称公钥对象PubKey
|AsyKeyGeneratorBySpec|generatePubKey(): Promise<KeyPair>;|使用Promise方式,根据密钥参数生成非对称公钥对象PubKey
| PriKey | getAsyKeySpec(itemType: AsyKeySpecItem): bigint \| string \| number; | 获取非对称密钥私钥对象的密钥参数属性 |
| PubKey | getAsyKeySpec(itemType: AsyKeySpecItem): bigint \| string \| number; | 获取非对称密钥公钥对象的密钥参数属性 |
### 根据参数生成ECC密钥对,并获得密钥参数开发步骤
示例1:根据参数生成ECC密钥对,并获得密钥参数(场景1、2)
1. 创建根据密钥参数的非对称密钥生成器;
2. 通过根据密钥参数的非对称密钥生成器由指定密钥参数生成非对称密钥对;
3. 获取密钥对象的密钥参数属性;
以使用Promise方式根据密钥参数生成ECC密钥为例:
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
// 打印bigint信息
function showBigIntInfo(bnName, bnValue) {
console.warn(bnName + ":");
console.warn(". 十进制: " + bnValue.toString());
console.warn(". 16进制: " + bnValue.toString(16));
console.warn(". 长度(bits): " + bnValue.toString(2).length);
}
// 根据密钥参数属性,构造ECC公私钥共有参数的sepc结构体
function genEccCommonSpec() {
let fieldFp = {
fieldType : "Fp",
p : BigInt("0xffffffffffffffffffffffffffffffff000000000000000000000001")
}
let G = {
x : BigInt("0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"),
y : BigInt("0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34")
}
let eccCommonSpec = {
algName : "ECC",
specType : cryptoFramework.AsyKeySpecType.COMMON_PARAMS_SPEC,
field : fieldFp,
a : BigInt("0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe"),
b : BigInt("0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"),
g : G,
n : BigInt("0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d"),
h : 1
}
return eccCommonSpec;
}
// 打印ECC密钥参数属性
function showEccSpecDetailInfo(key, keyType) {
console.info("show detail of " + keyType + ":");
try {
let p = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_FP_P_BN);
showBigIntInfo("--- p", p); //length is 224, hex : ffffffffffffffffffffffffffffffff000000000000000000000001
let a = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_A_BN);
showBigIntInfo("--- a", a); // length is 224, hex : fffffffffffffffffffffffffffffffefffffffffffffffffffffffe
let b = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_B_BN);
showBigIntInfo("--- b", b); // length is 224, hex : b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4
let gX = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_G_X_BN);
showBigIntInfo("--- gX", gX); // length is 224, hex : b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21
let gY = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_G_Y_BN);
showBigIntInfo("--- gY", gY); // length is 224, hex : bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34
let n = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_N_BN);
showBigIntInfo("--- n", n); // length is 224, hex : ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d
let h = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_H_NUM);
console.warn("--- h: " + h); //key h: 1
let fieldType = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_FIELD_TYPE_STR);
console.warn("--- field type: " + fieldType); // key field type: Fp
let fieldSize = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_FIELD_SIZE_NUM);
console.warn("--- field size: " + fieldSize); // key field size: 224
let curveName = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_CURVE_NAME_STR);
console.warn("--- curve name: " + curveName); // key curve name: NID_secp224r1
if (keyType == "priKey") {
let sk = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_SK_BN);
showBigIntInfo("--- sk", sk);
} else if (keyType == "pubKey") {
let pkX = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_PK_X_BN);
showBigIntInfo("--- pkX", pkX);
let pkY = key.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.ECC_PK_Y_BN);
showBigIntInfo("--- pkY", pkY);
}
} catch (error) {
console.error("getAsyKeySpec error");
console.error("error code: " + error.code + ", message is: " + error.message);
}
}
// 测试根据ECC公私钥公共密钥参数生成ECC密钥对,并获得其密钥参数属性
function testEccUseCommKeySpecGet()
{
try {
let commKeySpec = genEccCommonSpec(); // 使用参数属性,构造ECC公私钥公共密钥参数对象
let generatorBySpec = cryptoFramework.createAsyKeyGeneratorBySpec(commKeySpec); // 使用密钥参数对象创建生成器
let keyPairPromise = generatorBySpec.generateKeyPair(); // 使用生成器创建ECC密钥对
keyPairPromise.then( keyPair => {
showEccSpecDetailInfo(keyPair.priKey, "priKey"); // 对私钥获取相关密钥参数属性
showEccSpecDetailInfo(keyPair.pubKey, "pubKey"); // 对公钥获取相关密钥参数属性
}).catch(error => {
console.error("generateComm error");
console.error("error code: " + error.code + ", message is: " + error.message);
})
} catch(error) {
console.error("testEccUseCommSpec error");
console.error("error code: " + error.code + ", message is: " + error.message);
}
}
```
### 根据参数生成RSA公钥,并获得密钥参数属性
示例2:根据参数生成RSA公钥,并获得密钥参数(场景1、2)
1. 创建根据密钥参数的非对称密钥生成器;
2. 通过根据密钥参数的非对称密钥生成器由指定密钥参数生成非对称密钥的公钥;
3. 获取密钥对象的密钥参数属性;
以使用Callback方式根据密钥参数生成RSA公钥为例:
``` javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
// RSA公钥密钥参数生成函数
function genRsaPubKeySpec(nIn : bigint, eIn : bigint) {
let rsaCommSpec = { n : nIn, algName : "RSA", specType : cryptoFramework.AsyKeySpecType.COMMON_PARAMS_SPEC };
let rsaPubKeySpec = { params: rsaCommSpec, pk : eIn, algName : "RSA", specType : cryptoFramework.AsyKeySpecType.PUBLIC_KEY_SPEC };
return rsaPubKeySpec;
}
// 根据密钥参数属性,构造RSA公钥密钥参数对象
function genRsa2048PubKeySpec() {
let nIn = BigInt("0x9260d0750ae117eee55c3f3deaba74917521a262ee76007cdf8a56755ad73a1598a1408410a01434c3f5bc54a88b57fa19fc4328daea0750a4c44e88cff3b2382621b80f670464433e4336e6d003e8cd65bff211da144b88291c2259a00a72b711c116ef7686e8fee34e4d933c868187bdc26f7be071493c86f7a5941c3510806ad67b0f94d88f5cf5c02a092821d8626e8932b65c5bd8c92049c210932b7afa7ac59c0e886ae5c1edb00d8ce2c57633db26bd6639bff73cee82be9275c402b4cf2a4388da8cf8c64eefe1c5a0f5ab8057c39fa5c0589c3e253f0960332300f94bea44877b588e1edbde97cf2360727a09b775262d7ee552b3319b9266f05a25");
let eIn = BigInt("0x010001");
return genRsaPubKeySpec(nIn, eIn);
}
// 将RSA公钥密钥参数属性与预期值比较
function compareRsaPubKeyBySpec(rsaKeySpec, n, e) {
if (rsaKeySpec.params.n != n) {
return false;
}
if (rsaKeySpec.pk != e) {
return false;
}
return true;
}
// 测试根据RSA公钥密钥参数生成RSA公钥,并获得其密钥参数属性,与预期值做比较
function rsaUsePubKeySpecGetCallback() {
let rsaPubKeySpec = genRsa2048PubKeySpec();
let rsaGeneratorSpec = cryptoFramework.createAsyKeyGeneratorBySpec(rsaPubKeySpec);
rsaGeneratorSpec.generatePubKey((error, key) => {
let pubKey = key;
let nBN = pubKey.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.RSA_N_BN);
let eBN = pubKey.getAsyKeySpec(cryptoFramework.AsyKeySpecItem.RSA_PK_BN);
if (compareRsaPubKeyBySpec(rsaPubKeySpec, nBN, eBN) != true) {
AlertDialog.show({ message : "error pub key big number"} );
} else {
console.info("n, e in the pubKey are same as the spec.");
}
if (error) {
console.error("generate pubKey error" + "error code: " + error.code + "error message" + error.message);
}
});
}
```
## 使用加解密操作
**场景说明**
### 场景说明
在数据存储或传输场景中,可以使用加解密操作用于保证数据的机密性,防止敏感数据泄露。使用加解密操作中,典型的场景有:
1. 使用对称密钥的加解密操作
2. 使用非对称密钥的加解密操作
3. 使用RSA, PKCS1_OAEP填充模式时,获取、设置CipherSpecItem参数
**接口及参数说明**
> **说明**:<br>
> 1. 从API version 10开始, 支持RSA使用PKCS1_OAEP填充模式时,获取、设置[CipherSpecItem](../reference/apis/js-apis-cryptoFramework.md#cipherspecitem10)参数。
> 2. 从API version 10开始,支持加解密时字符串参数不带密钥长度。
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
### 接口及参数说明
由于密码算法的复杂性,在选取不同规格和参数时,开发差异较大,无法通过代码示例一一列举,请仔细阅读API参考资料中的相关接口,确保使用正确。
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)<br/>由于密码算法的复杂性,在选取不同规格和参数时,开发差异较大,无法通过代码示例一一列举,请仔细阅读API参考资料中的相关接口,确保使用正确。
以上场景设计的常用接口如下表所示:
......@@ -224,19 +429,19 @@ function testConvertAesKey() {
|Cipher|update(data : DataBlob) : Promise\<DataBlob>|使用Promise方式添加加解密数据|
|Cipher|doFinal(data : DataBlob, callback : AsyncCallback\<DataBlob>) : void|使用callback方式结束对所有数据的加解密|
|Cipher|doFinal(data : DataBlob) : Promise\<DataBlob>|使用Promise方式结束对所有数据的加解密|
|Cipher|getCipherSpec(itemType: CipherSpecItem): string \| Uint8Array|获取加解密的参数,当前仅支持RSA算法|
|Cipher|setCipherSpec(itemType: CipherSpecItem, itemValue: Uint8Array): void|设置加解密的参数,当前仅支持RSA算法|
**开发步骤**
### AES GCM以Promise方式加解密开发步骤:
示例1:使用对称密钥的加解密操作
示例1:使用AES对称密钥的加解密操作
1. 创建对称密钥生成器。
2. 通过密钥生成器生成对称密钥。
2. 通过密钥生成器随机生成对称密钥。
3. 创建加解密生成器。
4. 通过加解密生成器加密或解密数据。
以AES GCM以Promise方式加解密为例:
```js
``` javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
var globalCipher;
......@@ -286,16 +491,6 @@ function uint8ArrayToString(array) {
return arrayString;
}
function genKeyMaterialBlob() {
let arr = [
0xba, 0x3d, 0xc2, 0x71, 0x21, 0x1e, 0x30, 0x56,
0xad, 0x47, 0xfc, 0x5a, 0x46, 0x39, 0xee, 0x7c,
0xba, 0x3b, 0xc2, 0x71, 0xab, 0xa0, 0x30, 0x72]; // keyLen = 192 (24 bytes)
let keyMaterial = new Uint8Array(arr);
return {data : keyMaterial};
}
// AES GCM模式示例,自动生成密钥(promise写法)
function testAesGcm() {
return new Promise((resolve, reject) => {
......@@ -370,7 +565,14 @@ function testAesGcm() {
}
```
以3DES ECB以callback方式加解密(采用已有数据生成密钥)为例:
### 3DES ECB以callback方式加解密开发步骤:
示例2:使用3DES对称密钥的加解密操作
1. 创建对称密钥生成器。
2. 通过已有二进制数据生成密钥
3. 创建加解密生成器。
4. 通过加解密生成器加密或解密数据。
```js
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -496,9 +698,18 @@ function test3DesEcb() {
}
```
### AES GCM以promise方式,分段update()加解密开发步骤:
示例3:使用AES对称密钥的分段update()加解密操作
1. 创建对称密钥生成器。
2. 通过已有二进制数据生成密钥
3. 创建加解密生成器。
4. 通过加解密生成器加密或解密数据。
以AES GCM以promise方式,分段update()实现加解密为例:
```js
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
var globalCipher;
......@@ -637,77 +848,102 @@ function testAesMultiUpdate() {
})
}
```
示例2:使用非对称密钥的加解密操作
### RSA加解密开发步骤
示例4:使用RSA非对称密钥的加解密操作
1. 生成RSA密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成RSA非对称密钥。
2. 生成Cipher对象。通过createCipher接口创建Cipher对象,执行初始化操作,设置密钥及加解密模式。
3. 执行加解密操作。通过调用Cipher对象提供的doFinal接口,执行加密操作生成密文或执行解密操作生成明文。
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
let plan = "This is cipher test.";
// 可理解的字符串转成字节流
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
let arr = [];
for (let i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
return new Uint8Array(arr);
}
// 以Promise方式加密
function encryptMessageProMise() {
// 生成非对称密钥生成器
let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
// 生成加解密生成器
let cipher = cryptoFramework.createCipher("RSA1024|PKCS1");
// 通过非对称秘钥生成器生成非对称密钥对
let keyGenPromise = rsaGenerator.generateKeyPair();
keyGenPromise.then(rsaKeyPair => {
let pubKey = rsaKeyPair.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 rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
// 生成加解密生成器
let cipher = cryptoFramework.createCipher("RSA1024|PKCS1");
// 通过非对称秘钥生成器生成非对称密钥对
rsaGenerator.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("RSA1024|PRIMES_2");
// 生成加解密生成器,用于加密
let cipher = cryptoFramework.createCipher("RSA1024|PKCS1");
// 生成加解密生成器,用于解密
let decoder = cryptoFramework.createCipher("RSA1024|PKCS1");
// 通过非对称秘钥生成器生成非对称密钥对
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;
......@@ -716,22 +952,33 @@ function decryptMessageProMise() {
});
}
// 以Callback方式加解密
function decryptMessageCallback() {
// 生成非对称密钥生成器
let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
// 生成加解密生成器,用于加密
let cipher = cryptoFramework.createCipher("RSA1024|PKCS1");
// 生成加解密生成器,用于解密
let decoder = cryptoFramework.createCipher("RSA1024|PKCS1");
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;
......@@ -744,19 +991,22 @@ function decryptMessageCallback() {
});
}
```
### RSA分段加解密开发步骤
示例5:使用RSA非对称密钥的分段加解密操作
以RSA非对称加解密(多次调用doFinal实现分段)为例:
```js
1. 生成RSA密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成RSA非对称密钥。
2. 生成Cipher对象。通过createCipher接口创建Cipher对象,执行初始化操作,设置密钥及加解密模式。
3. 执行加解密操作。通过调用Cipher对象提供的doFinal接口,执行加密操作生成密文或执行解密操作生成明文,多次调用doFinal实现分段。
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
let arr = [];
for (let i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
return new Uint8Array(arr);
}
// 字节流转成可理解的字符串
......@@ -831,22 +1081,132 @@ function encryptLongMessagePromise() {
}
```
> **说明:**
>
> 1. 使用RSA加解密时,Cipher对象不可重复调用init方法初始化,在创建了一个加密Cipher对象后,如果要进行解密,则需要重新创建另一个Cipher对象执行解密操作。
> 2. RSA加密有长度限制,允许加密明文的最大长度见[加解密算法库框架概述](cryptoFramework-overview.md)中的基本概念章节。
> 3. RSA解密每次允许解密的密文长度为,RSA密钥的位数/8。
**说明**
1. 使用RSA加解密时,Cipher对象不可重复调用init方法初始化,在创建了一个加密Cipher对象后,如果要进行解密,则需要重新创建另一个Cipher对象执行解密操作。
2. RSA加密有长度限制,允许加密明文的最大长度见[加解密算法库框架概述](cryptoFramework-overview.md)中的基本概念加解密章节。
3. RSA解密每次允许解密的密文长度为,RSA密钥的位数/8。
### RSA加解密PKCS1_OAEP模式开发步骤
示例6:使用RSA非对称密钥使用PKCS1_OAEP模式的以Promise形式的加解密操作
1. 根据密钥参数生成RSA密钥。通过createAsyKeyGeneratorBySpec接口创建AsyKeyGeneratorBySpec对象,并生成RSA非对称密钥对。(也可以使用createAsyKeyGenerator接口随机生成或转换得到RSA密钥对象)
2. 生成Cipher对象。通过createCipher接口创建Cipher对象,执行初始化操作,设置密钥及加解密模式,在Update前通过setCipherSpec设置PKCS1_OAEP填充字节流P。
3. 执行加解密操作。通过调用Cipher对象提供的doFinal接口,执行加密操作生成密文或执行解密操作生成明文,需要加解密Cipher对象的字节流P一致。
``` javascript
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);
}
// 根据密钥参数属性构造RSA非对称密钥对密钥参数
function genRsaKeyPairSpec(nIn : bigint, eIn : bigint, dIn : bigint) {
let rsaCommSpec = { n : nIn, algName : "RSA", specType : cryptoFramework.AsyKeySpecType.COMMON_PARAMS_SPEC };
let rsaKeyPairSpec = { params: rsaCommSpec, sk : dIn, pk : eIn, algName : "RSA", specType : cryptoFramework.AsyKeySpecType.KEY_PAIR_SPEC };
return rsaKeyPairSpec;
}
// 生成RSA2048密钥对参数
function genRsa2048KeyPairSpec() {
let nIn = BigInt("0x9260d0750ae117eee55c3f3deaba74917521a262ee76007cdf8a56755ad73a1598a1408410a01434c3f5bc54a88b57fa19fc4328daea0750a4c44e88cff3b2382621b80f670464433e4336e6d003e8cd65bff211da144b88291c2259a00a72b711c116ef7686e8fee34e4d933c868187bdc26f7be071493c86f7a5941c3510806ad67b0f94d88f5cf5c02a092821d8626e8932b65c5bd8c92049c210932b7afa7ac59c0e886ae5c1edb00d8ce2c57633db26bd6639bff73cee82be9275c402b4cf2a4388da8cf8c64eefe1c5a0f5ab8057c39fa5c0589c3e253f0960332300f94bea44877b588e1edbde97cf2360727a09b775262d7ee552b3319b9266f05a25");
let eIn = BigInt("0x010001");
let dIn = BigInt("0x6a7df2ca63ead4dda191d614b6b385e0d9056a3d6d5cfe07db1daabee022db08212d97613d3328e0267c9dd23d787abde2afcb306aeb7dfce69246cc73f5c87fdf06030179a2114b767db1f083ff841c025d7dc00cd82435b9a90f695369e94df23d2ce458bc3b3283ad8bba2b8fa1ba62e2dce9accff3799aae7c840016f3ba8e0048c0b6cc4339af7161003a5beb864a0164b2c1c9237b64bc87556994351b27506c33d4bcdfce0f9c491a7d6b0628c7c852be4f0a9c3132b2ed3a2c8881e9aab07e20e17deb074691be677776a78b5c502e05d9bdde72126b3738695e2dd1a0a98a14247c65d8a7ee79432a092cb0721a12df798e44f7cfce0c498147a9b1");
return genRsaKeyPairSpec(nIn, eIn, dIn);
}
function rsaUseSpecDecryptOAEPPromise() {
let plan = "This is cipher test.";
// 获得RSA密钥对密钥参数对象
let rsaKeyPairSpec = genRsa2048KeyPairSpec();
// 根据RSA密钥对参数生成RSA密钥对
let rsaGeneratorSpec = cryptoFramework.createAsyKeyGeneratorBySpec(rsaKeyPairSpec);
let keyGenPromise = rsaGeneratorSpec.generateKeyPair();
let cipher = cryptoFramework.createCipher("RSA|PKCS1_OAEP|SHA256|MGF1_SHA1");
let decoder = cryptoFramework.createCipher("RSA|PKCS1_OAEP|SHA256|MGF1_SHA1");
let keyPair;
let cipherDataBlob;
// RSA加解密PKCS1-OAEP模式填充字节流P
let pSource = new Uint8Array([1,2,3,4]);
let input = { data : stringToUint8Array(plan) };
// 生成密钥
keyGenPromise.then(rsaKeyPair => {
keyPair = rsaKeyPair;
// 进行加密操作初始化
return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null);
}).then(() => {
// get和set操作可以放在Cipher对象init之后,此处对cipher进行set和get操作
cipher.setCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF1_PSRC_UINT8ARR, pSource);
let retP = cipher.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF1_PSRC_UINT8ARR);
// 比较get出来的P字节流与set进去的P字节流是否一致
if (retP.toString() != pSource.toString()) {
AlertDialog.show({message : "error init pSource" + retP});
} else {
console.info("pSource changed ==" + retP);
}
// 进行OAEP其他参数的get操作
let md = cipher.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MD_NAME_STR);
console.info("md == " + md);
let mgf = cipher.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF_NAME_STR);
console.info("mgf == " + mgf);
let mgf1Md = cipher.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF1_MD_STR);
console.info("mgf1Md == " + mgf1Md);
return cipher.doFinal(input);
}).then(dataBlob => {
console.info("EncryptOutPut is " + dataBlob.data);
cipherDataBlob = dataBlob;
// get和set操作可以放在Cipher对象init之前,且与init之后等价,此处对decoder进行set和get操作
decoder.setCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF1_PSRC_UINT8ARR, pSource);
let retP = decoder.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF1_PSRC_UINT8ARR);
// 比较get出来的P字节流与set进去的P字节流是否一致
if (retP.toString() != pSource.toString()) {
AlertDialog.show({message : "error init pSource" + retP});
} else {
console.info("pSource changed ==" + retP);
}
// 进行OAEP其他参数的get操作
let md = decoder.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MD_NAME_STR);
console.info("md == " + md);
let mgf = decoder.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF_NAME_STR);
console.info("mgf == " + mgf);
let mgf1Md = decoder.getCipherSpec(cryptoFramework.CipherSpecItem.OAEP_MGF1_MD_STR);
console.info("mgf1Md == " + mgf1Md);
// 初始化解密操作
return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null);
}).then(() => {
return decoder.doFinal(cipherDataBlob);
}).then(decodeData => {
// 解密成功
if (decodeData.data.toString() === input.data.toString()) {
console.info("oaep decrypt success");
AlertDialog.show({message : " oaep decrypt success"});
} else {
AlertDialog.show({message : "oeap decrypt fail"});
}
});
}
```
## 使用签名验签操作
**场景说明**
### 场景说明
当需要判断接收的数据是否被篡改且是否为指定对象发送的数据时,可以使用签名验签操作。使用签名验签操作中,典型的场景有:
1. 使用RSA签名验签操作
2. 使用ECC签名验签操作
3. 使用RSA签名验签,PSS模式时,获取、设置SignSpecItem参数。
> **说明**:<br>
> 1. 从API version 10开始,支持RSA使用PSS填充模式时,获取、设置[SignSpecItem](../reference/apis/js-apis-cryptoFramework.md#signspecitem10)参数。
> 2. 从API version 10开始,支持签名验签时字符串参数不带密钥长度。
**接口及参数说明**
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)<br/>由于密码算法的复杂性,在选取不同规格和参数时,开发差异较大,无法通过代码示例一一列举,请仔细阅读API参考资料中的相关接口,确保使用正确。
......@@ -859,34 +1219,36 @@ function encryptLongMessagePromise() {
|Sign|update(data : DataBlob) : Promise\<void>|用Promise方式添加签名数据|
|Sign|sign(data : DataBlob, callback : AsyncCallback\<DataBlob>) : void|使用callback方式签名所有数据|
|Sign|sign(data : DataBlob) : Promise\<DataBlob>|使用Promise方式签名所有数据|
|Sign|getSignSpec(itemType: SignSpecItem): string \| number|获得签名的参数,当前仅支持RSA算法|
|Sign|setSignSpec(itemType: SignSpecItem, itemValue: number): void|设置签名的参数,当前仅支持RSA算法|
|cryptoFramework|function createVerify(algName : string) : Verify|根据String设置的参数创建Verify对象|
|Verify|init(priKey : PriKey, callback : AsyncCallback\<void>) : void|使用callback方式设置密钥并初始化Verify对象|
|Verify|init(priKey : PriKey) : Promise\<void>|使用Promise方式设置密钥并初始化Verify对象|
|Verify|init(pubKey : PubKey, callback : AsyncCallback\<void>) : void|使用callback方式设置密钥并初始化Verify对象|
|Verify|init(pubKey : PubKey) : Promise\<void>|使用Promise方式设置密钥并初始化Verify对象|
|Verify|update(data : DataBlob, callback : AsyncCallback\<void>) : void|使用callback方式添加验签数据|
|Verify|update(data : DataBlob) : Promise\<void>|用Promise方式添加验签数据|
|Verify|verify(data : DataBlob, signatureData : DataBlob, callback : AsyncCallback\<boolean>) : void|使用callback方式验签所有数据|
|Verify|verify(data : DataBlob, signatureData : DataBlob) : Promise\<boolean>|使用Promise方式验签所有数据|
|Verify|getVerifySpec(itemType: SignSpecItem): string \| number|获得验签的参数,当前仅支持RSA算法|
|Verify|setVerifySpec(itemType: SignSpecItem, itemValue: number): void|设置验签的参数,当前仅支持RSA算法|
**开发步骤**
### RSA签名验签开发步骤
示例1:使用RSA签名验签操作
1. 生成RSA密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成RSA非对称密钥。
2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥。
3. 执行签名操作。通过Sign类提供的update接口,添加签名数据,并调用sign接口生成数据的签名。
4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥。
5. 执行验签操作。通过Verify类提供的update接口,添加签名数据,并调用verify接口传入签名进行验签。
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
let arr = [];
for (let i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
return new Uint8Array(arr);
}
let globalKeyPair;
......@@ -898,7 +1260,7 @@ let input2 = { data : stringToUint8Array(plan2) };
function signMessagePromise() {
let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
let signer = cryptoFramework.createSign("RSA1024|PKCS1|SHA256");
let signer = cryptoFramework.createSign("RSA1024|PKCS1|SHA256"); // API version 10开始,支持"RSA|PKCS1|SHA256"
let keyGenPromise = rsaGenerator.generateKeyPair();
keyGenPromise.then( keyPair => {
globalKeyPair = keyPair;
......@@ -928,7 +1290,7 @@ function verifyMessagePromise() {
function signMessageCallback() {
let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
let signer = cryptoFramework.createSign("RSA1024|PKCS1|SHA256");
let signer = cryptoFramework.createSign("RSA1024|PKCS1|SHA256"); // API version 10开始,支持"RSA|PKCS1|SHA256"
rsaGenerator.generateKeyPair(function (err, keyPair) {
globalKeyPair = keyPair;
let priKey = globalKeyPair.priKey;
......@@ -955,24 +1317,25 @@ function verifyMessageCallback() {
}
```
示例2:使用ECDSA操作
### ECDSA签名验签开发步骤
示例2:使用ECDSA操作
1. 生成ECC密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成ECC非对称密钥。
2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥。
3. 执行签名操作。通过Sign类提供的update接口,添加签名数据,并调用doFinal接口生成数据的签名。
4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥。
5. 执行验签操作。通过Verify类提供的update接口,添加签名数据,并调用doFinal接口传入签名进行验签。
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
let arr = [];
for (let i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
return new Uint8Array(arr);
}
let globalKeyPair;
......@@ -1041,18 +1404,25 @@ function verifyMessageCallback() {
}
```
以执行签名、验签操作时多次调用update实现分段为例:
### RSA分段签名验签开发步骤
```js
示例3:使用RSA签名验签操作
1. 生成RSA密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成RSA非对称密钥。
2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥。
3. 执行签名操作。通过Sign类提供的update接口,多次添加签名数据,并调用sign接口生成数据的签名,完成分段签名。
4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥。
5. 执行验签操作。多次通过Verify类提供的update接口,添加签名数据,并调用verify接口传入签名进行验签,完成分段验签。
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
let arr = [];
for (let i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
return new Uint8Array(arr);
}
function signLongMessagePromise() {
......@@ -1109,9 +1479,168 @@ function signLongMessagePromise() {
}
```
### RSA签名验签PSS模式开发步骤
示例4:使用RSA签名验签PSS模式,以Callback形式完成签名验签流程。
1. 根据密钥参数生成RSA密钥。通过createAsyKeyGeneratorBySpec接口创建AsyKeyGeneratorBySpec对象,并生成RSA非对称密钥对。
2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥,可以获得、设置PSS模式相关参数。
3. 执行签名操作。通过Sign类提供的update接口,添加签名数据,并调用sign接口生成数据的签名。
4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥,可以获得、设置PSS模式相关参数,验签成功需要保证盐值长度一致。
5. 执行验签操作。通过Verify类提供的update接口,添加签名数据,并调用verify接口传入签名进行验签。
```javascript
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);
}
// 根据密钥参数属性构造RSA非对称密钥对密钥参数
function genRsaKeyPairSpec(nIn : bigint, eIn : bigint, dIn : bigint) {
let rsaCommSpec = { n : nIn, algName : "RSA", specType : cryptoFramework.AsyKeySpecType.COMMON_PARAMS_SPEC };
let rsaKeyPairSpec = { params: rsaCommSpec, sk : dIn, pk : eIn, algName : "RSA", specType : cryptoFramework.AsyKeySpecType.KEY_PAIR_SPEC };
return rsaKeyPairSpec;
}
// 生成RSA2048密钥对参数
function genRsa2048KeyPairSpec() {
let nIn = BigInt("0x9260d0750ae117eee55c3f3deaba74917521a262ee76007cdf8a56755ad73a1598a1408410a01434c3f5bc54a88b57fa19fc4328daea0750a4c44e88cff3b2382621b80f670464433e4336e6d003e8cd65bff211da144b88291c2259a00a72b711c116ef7686e8fee34e4d933c868187bdc26f7be071493c86f7a5941c3510806ad67b0f94d88f5cf5c02a092821d8626e8932b65c5bd8c92049c210932b7afa7ac59c0e886ae5c1edb00d8ce2c57633db26bd6639bff73cee82be9275c402b4cf2a4388da8cf8c64eefe1c5a0f5ab8057c39fa5c0589c3e253f0960332300f94bea44877b588e1edbde97cf2360727a09b775262d7ee552b3319b9266f05a25");
let eIn = BigInt("0x010001");
let dIn = BigInt("0x6a7df2ca63ead4dda191d614b6b385e0d9056a3d6d5cfe07db1daabee022db08212d97613d3328e0267c9dd23d787abde2afcb306aeb7dfce69246cc73f5c87fdf06030179a2114b767db1f083ff841c025d7dc00cd82435b9a90f695369e94df23d2ce458bc3b3283ad8bba2b8fa1ba62e2dce9accff3799aae7c840016f3ba8e0048c0b6cc4339af7161003a5beb864a0164b2c1c9237b64bc87556994351b27506c33d4bcdfce0f9c491a7d6b0628c7c852be4f0a9c3132b2ed3a2c8881e9aab07e20e17deb074691be677776a78b5c502e05d9bdde72126b3738695e2dd1a0a98a14247c65d8a7ee79432a092cb0721a12df798e44f7cfce0c498147a9b1");
return genRsaKeyPairSpec(nIn, eIn, dIn);
}
function verifyMessageCallbackPSS() {
let plan1 = "This is Sign test plan1";
let plan2 = "This is Sign test plan1";
let input1 = { data : stringToUint8Array(plan1) };
let input2 = { data : stringToUint8Array(plan2) };
let globalKeyPair;
let signMessageBlob;
// 获得RSA密钥对密钥参数对象
let rsaKeyPairSpec = genRsa2048KeyPairSpec();
// 构造RSA密钥对生成器
let rsaGeneratorSpec = cryptoFramework.createAsyKeyGeneratorBySpec(rsaKeyPairSpec);
// sign和verfiy均支持RSA密钥带长度/不带长度的写法
let signer = cryptoFramework.createSign("RSA|PSS|SHA256|MGF1_SHA256");
let verifyer = cryptoFramework.createVerify("RSA2048|PSS|SHA256|MGF1_SHA256");
rsaGeneratorSpec.generateKeyPair(function (err, keyPair) {
globalKeyPair = keyPair;
signer.init(globalKeyPair.priKey, function (err, data) {
// 在签名初始化后,对PSS参数进行set和get操作
let setN = 32;
signer.setSignSpec(cryptoFramework.SignSpecItem.PSS_SALT_LEN_NUM, setN);
let saltLen = signer.getSignSpec(cryptoFramework.SignSpecItem.PSS_SALT_LEN_NUM);
console.info("SaltLen == " + saltLen);
let tf = signer.getSignSpec(cryptoFramework.SignSpecItem.PSS_TRAILER_FIELD_NUM);
console.info("trailer field == " + tf);
let md = signer.getSignSpec(cryptoFramework.SignSpecItem.PSS_MD_NAME_STR);
console.info("md == " + md);
let mgf = signer.getSignSpec(cryptoFramework.SignSpecItem.PSS_MGF_NAME_STR);
console.info("mgf == " + mgf);
let mgf1Md = signer.getSignSpec(cryptoFramework.SignSpecItem.PSS_MGF1_MD_STR);
console.info("mgf1Md == " + mgf1Md);
signer.update(input1, function (err, data) {
signer.sign(input2, function (err, data) {
// 在验签初始化前,对PSS参数进行set和get操作,功能与初始化后一致
signMessageBlob = data;
AlertDialog.show({message : "res" + signMessageBlob.data});
let setN = 32;
verifyer.setVerifySpec(cryptoFramework.SignSpecItem.PSS_SALT_LEN_NUM, setN);
let saltLen = verifyer.getVerifySpec(cryptoFramework.SignSpecItem.PSS_SALT_LEN_NUM);
console.info("SaltLen == " + saltLen);
let tf = verifyer.getVerifySpec(cryptoFramework.SignSpecItem.PSS_TRAILER_FIELD_NUM);
console.info("trailer field == " + tf);
let md = verifyer.getVerifySpec(cryptoFramework.SignSpecItem.PSS_MD_NAME_STR);
console.info("md == " + md);
let mgf = verifyer.getVerifySpec(cryptoFramework.SignSpecItem.PSS_MGF_NAME_STR);
console.info("mgf == " + mgf);
let mgf1Md = verifyer.getVerifySpec(cryptoFramework.SignSpecItem.PSS_MGF1_MD_STR);
console.info("mgf1Md == " + mgf1Md);
verifyer.init(globalKeyPair.pubKey, function (err, data) {
verifyer.update(input1, function(err, data) {
verifyer.verify(input2, signMessageBlob, function(err, data) {
AlertDialog.show({message : "res " + data});
})
});
});
});
});
});
});
}
```
## 使用密钥协商操作
### 场景说明
使用密钥协商操作中,典型的场景有:
通信双方可以在一个公开的信道上通过相互传送一些消息,共同建立一个安全的共享秘密密钥。
> **说明**:<br>
> 从API version 10开始,支持密钥协商时字符串参数不带密钥长度。
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
|实例名|接口名|描述|
|---|---|---|
|cryptoFramework|createKeyAgreement(algName : string) : KeyAgreement|根据String设置的参数创建KeyAgreement对象|
|KeyAgreement|generateSecret(priKey : PriKey, pubKey : PubKey, callback : AsyncCallback\<DataBlob>) : void|使用callback方式进行密钥协商|
|KeyAgreement|generateSecret(priKey : PriKey, pubKey : PubKey) : Promise\<DataBlob>|使用Promise方式进行密钥协商|
### 开发步骤
1. 生成ECC密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成ECC非对称密钥。
2. 基于ECC密钥的私钥及公钥执行ECDH操作。
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
let globalKeyPair;
function ecdhPromise() {
let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
let eccKeyAgreement = cryptoFramework.createKeyAgreement("ECC256"); // API version 10开始,支持输入"ECC"来进行密钥协商
let keyGenPromise = eccGenerator.generateKeyPair();
keyGenPromise.then( keyPair => {
globalKeyPair = keyPair;
return eccKeyAgreement.generateSecret(keyPair.priKey, keyPair.pubKey);
}).then((secret) => {
console.info("ecdh output is " + secret.data);
}).catch((error) => {
console.error("ecdh error.");
});
}
function ecdhCallback() {
let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
let eccKeyAgreement = cryptoFramework.createKeyAgreement("ECC256");
eccGenerator.generateKeyPair(function (err, keyPair) {
globalKeyPair = keyPair;
eccKeyAgreement.generateSecret(keyPair.priKey, keyPair.pubKey, function (err, secret) {
if (err) {
console.error("ecdh error.");
return;
}
console.info("ecdh output is " + secret.data);
});
});
}
```
## 使用摘要操作
**场景说明**
### 场景说明
用户指定摘要算法(如SHA256)生成Md实例,并输入单段或多段需要摘要的信息,进行摘要计算更新,并返回消息摘要计算结果,在指定算法后可获取当前算法名与摘要计算长度(字节)
......@@ -1119,7 +1648,7 @@ function signLongMessagePromise() {
用户指定摘要算法(如SHA256)生成Md实例,并输入单段或多段需要摘要的信息,进行摘要计算更新,并返回消息摘要计算结果,在指定算法后可获取当前算法名与摘要计算长度(字节)
**接口及参数说明**
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
......@@ -1133,14 +1662,14 @@ function signLongMessagePromise() {
| Md | getMdLength() : number; | 获取摘要的长度(由指定的摘要算法决定) |
| Md | readonly algName : string; | 获取当前设置的摘要算法名 |
**开发步骤**
### 摘要算法开发步骤
1. 设置算法,通过接口`createMd`生成摘要操作实例
2. 接受用户数据,通过接口`update`,更新摘要,此步骤可重复
2. 接受用户数据,通过接口`update`,更新摘要,此步骤可重复,算法库不限制单次update的长度
3. 通过接口`digest`,返回摘要计算结果
4. 获取当前摘要算法名与摘要计算长度
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
......@@ -1212,9 +1741,14 @@ function doMdByCallback() {
}
```
以MD更新时多次调用update实现分段为例:
### 分段摘要算法开发步骤
```js
1. 设置算法,通过接口`createMd`生成摘要操作实例
2. 接受用户数据,多次通过接口`update`,更新摘要,实现分段
3. 通过接口`digest`,返回摘要计算结果
4. 获取当前摘要算法名与摘要计算长度
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
......@@ -1273,77 +1807,9 @@ async function doLoopMdPromise() {
}
```
## 使用密钥协商操作
**场景说明**
使用密钥协商操作中,典型的场景有:
通信双方可以在一个公开的信道上通过相互传送一些消息,共同建立一个安全的共享秘密密钥。
**接口及参数说明**
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
|实例名|接口名|描述|
|---|---|---|
|cryptoFramework|createKeyAgreement(algName : string) : KeyAgreement|根据String设置的参数创建KeyAgreement对象|
|KeyAgreement|generateSecret(priKey : PriKey, pubKey : PubKey, callback : AsyncCallback\<DataBlob>) : void|使用callback方式进行密钥协商|
|KeyAgreement|generateSecret(priKey : PriKey, pubKey : PubKey) : Promise\<DataBlob>|使用Promise方式进行密钥协商|
**开发步骤**
1. 通过createKeyAgreement接口创建KeyAgreement对象,用于后续的密钥协商操作。
2. 调用KeyAgreement对象提供的generateSecret方法,传入对端的ECC公钥对象,以及本地生成的ECC私钥对象。
```js
import cryptoFramework from "@ohos.security.cryptoFramework"
let globalSelfPriKey;
let globalPeerPubKey;
function ecdhPromise() {
let peerPubKeyArray = new Uint8Array([48,89,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,3,66,0,4,83,96,142,9,86,214,126,106,247,233,92,125,4,128,138,105,246,162,215,71,81,58,202,121,26,105,211,55,130,45,236,143,55,16,248,75,167,160,167,106,2,152,243,44,68,66,0,167,99,92,235,215,159,239,28,106,124,171,34,145,124,174,57,92]);
let peerPubKeyBlob = { data: peerPubKeyArray };
let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
let eccKeyAgreement = cryptoFramework.createKeyAgreement("ECC256");
eccGenerator.convertKey(peerPubKeyBlob, null).then((peerKeyPair) => {
globalPeerPubKey = peerKeyPair.pubKey;
return eccGenerator.generateKeyPair();
}).then((keyPair) => {
globalSelfPriKey = keyPair.priKey;
return eccKeyAgreement.generateSecret(globalSelfPriKey, globalPeerPubKey);
}).then((secret) => {
console.info("ecdh promise output is " + secret.data);
}).catch((error) => {
console.error("ecdh error.");
});
}
function ecdhCallback() {
let peerPubKeyArray = new Uint8Array([48,89,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,3,66,0,4,83,96,142,9,86,214,126,106,247,233,92,125,4,128,138,105,246,162,215,71,81,58,202,121,26,105,211,55,130,45,236,143,55,16,248,75,167,160,167,106,2,152,243,44,68,66,0,167,99,92,235,215,159,239,28,106,124,171,34,145,124,174,57,92]);
let peerPubKeyBlob = { data: peerPubKeyArray };
let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
let eccKeyAgreement = cryptoFramework.createKeyAgreement("ECC256");
eccGenerator.convertKey(peerPubKeyBlob, null, function (err, peerKeyPair) {
globalPeerPubKey = peerKeyPair.pubKey;
eccGenerator.generateKeyPair(function (err, keyPair) {
globalSelfPriKey = keyPair.priKey;
eccKeyAgreement.generateSecret(globalSelfPriKey, globalPeerPubKey, function (err, secret) {
if (err) {
console.error("ecdh error.");
return;
}
console.info("ecdh callback output is " + secret.data);
});
});
})
}
```
## 使用消息认证码操作
**场景说明**
### 场景说明
消息认证码操作主要应用于身份认证的场景:
......@@ -1351,7 +1817,7 @@ Mac(message authentication code)可以对消息进行完整性校验,通过使
用户指定摘要算法(如SHA256)生成消息认证码Mac实例,输入对称密钥初始化Mac,并传入单段或多段需要摘要的信息,进行消息认证码计算,并获取消息认证码计算结果,在指定算法后可获取当前算法名与消息认证码计算长度(字节)。
**接口及参数说明**
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
......@@ -1367,7 +1833,7 @@ Mac(message authentication code)可以对消息进行完整性校验,通过使
| Mac | getMacLength() : number; | 获取MAC的长度(由指定的摘要算法决定) |
| Mac | readonly algName : string; | 获取当前设置的摘要算法名 |
**开发步骤**
### HMAC开发步骤
1. 设置算法,通过接口`createMac`生成消息认证码操作实例
2. 接受输入对称密钥,通过接口`init`,初始化Mac
......@@ -1375,7 +1841,7 @@ Mac(message authentication code)可以对消息进行完整性校验,通过使
4. 通过接口`doFinal`,返回Mac计算结果
5. 获取当前摘要算法名与Mac计算长度
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// 可理解的字符串转成字节流
......@@ -1435,6 +1901,7 @@ function doHmacByCallback() {
try {
mac = cryptoFramework.createMac(macAlgName);
} catch (error) {
AlertDialog.show({message: "[Callback]: error code: " + error.code + ", message is: " + error.message});
console.error("[Callback]: error code: " + error.code + ", message is: " + error.message);
}
console.info("[Promise]: Mac algName is: " + mac.algName);
......@@ -1462,9 +1929,9 @@ function doHmacByCallback() {
console.error("[Callback]: err: " + err3.code);
} else {
macOutput = output;
console.info("[Callback]: HMAC result: " + macOutput.data);
console.error("[Callback]: HMAC result: " + macOutput.data);
let macLen = mac.getMacLength();
console.info("[Callback]: MAC len: " + macLen);
console.error("[Callback]: MAC len: " + macLen);
}
});
});
......@@ -1473,9 +1940,15 @@ function doHmacByCallback() {
}
```
### 分段HMAC开发步骤
以HMAC更新MAC时多次调用update实现分段为例:
1. 设置算法,通过接口`createMac`生成消息认证码操作实例
2. 接受输入对称密钥,通过接口`init`,初始化Mac
3. 接受数据,多次通过接口`update`,以实现分段:
4. 通过接口`doFinal`,返回Mac计算结果
5. 获取当前摘要算法名与Mac计算长度
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
function stringToUint8Array(str) {
......@@ -1545,36 +2018,37 @@ function doLoopHmacPromise() {
}
```
## 使用随机数操作
**场景说明**
### 场景说明
使用随机数操作的主要场景为:
- 用户生成随机数Random实例,输入随机数生成的长度(字节),生成指定长度随机数。
- 用户生成随机数Random实例,输入随机数生成的长度(字节),生成指定长度(范围为1~INT_MAX)的安全随机数。
- 用户使用生成的随机数作为参数,进行种子设置。
**接口及参数说明**
### 接口及参数说明
详细接口说明可参考[API参考](../reference/apis/js-apis-cryptoFramework.md)
| 实例名 | 接口名 | 描述 |
| --------------- | ------------------------------------------------------------ | ---------------------------------------------- |
| --------------- | ------------------------------------------------------------ | ------------------------------------------ |
| cryptoFramework | function createRandom() : Random; | 生成随机数Random实例 |
| Random | generateRandom(len : number, callback: AsyncCallback\<DataBlob>) : void; | 接受输入长度,通过Callback,异步生成随机数 |
| Random | generateRandom(len : number) : Promise\<DataBlob>; | 接受输入长度,通过Promise,异步生成随机数 |
| Random | generateRandomSync(len: number): DataBlob; | 接受输入长度,同步生成随机数 |
| Random | setSeed(seed : DataBlob) : void; | 接受输入Blob,设置种子 |
**开发步骤**
### 开发步骤
1. 通过接口`createRandom`生成随机数操作实例
2. 接受输入长度,通过接口`generateRandom`,生成指定长度的随机数
3. 接受DataBlob数据,通过接口`setSeed`,为随机数生成池设置种子
```js
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
// process by promise
// 通过Promise方式生成随机数
function doRandByPromise(len) {
var rand;
try {
......@@ -1595,7 +2069,7 @@ function doRandByPromise(len) {
});
}
// process by callback
// 通过Callback方式生成随机数
function doRandByCallback(len) {
var rand;
try {
......@@ -1616,4 +2090,25 @@ function doRandByCallback(len) {
}
});
}
// 通过同步接口生成随机数
function doRandBySync(len) {
var rand;
try {
rand = cryptoFramework.createRandom();
} catch (error) {
console.error("[Sync]: error code: " + error.code + ", message is: " + error.message);
}
try {
let randData = rand.generateRandomSync(len);
if (randData != null) {
console.info("[Sync]: rand result: " + randData.data);
} else {
console.error("[Sync]: get rand result fail!");
}
} catch (error) {
console.error("[Sync]: error: " + error.message);
}
}
```
# 加解密算法库框架概述
加解密算法库框架是一个屏蔽了第三方密码学算法库实现差异的算法框架,提供加解密、签名验签、消息验证码、哈希、安全随机数等相关功能。开发者可以通过调用加解密算法库框架,忽略底层不同三方算法库的差异,实现迅捷开发。
> **说明:**
>
> 加解密算法库框架仅提供密钥的密码学操作,而不提供密钥管理功能。因此,使用算法库时,需要应用自己来保管密钥(适用于临时会话密钥等仅在内存中使用的场景,或者应用自己实现密钥安全存储的场景)。如果业务需要由系统提供密钥管理功能(密钥存储等),请使用[HUKS部件](huks-overview.md)。
> **说明:** 加解密算法库框架仅提供密钥的密码学操作,而不提供密钥管理功能。因此,使用算法库时,需要应用自己来保管密钥(适用于临时会话密钥等仅在内存中使用的场景,或者应用自己实现密钥安全存储的场景)。如果业务需要由系统提供密钥管理功能(密钥存储等),请使用[HUKS部件](huks-overview.md)。
## 框架实现原理
加解密算法库框架提供的组件分为三层:接口层,Framework层和插件层。接口层负责对外提供统一的JS接口,插件层实现针对具体三方算法库的功能,Framework层通过灵活加载插件层的插件适配并屏蔽三方算法库差异。
## 基本概念
**对称密钥**
### 对称密钥
对称密钥使用同一个密钥对数据进行加密解密操作。即对称加密算法中,数据发送方使用加密密钥对明文进行特殊加密算法处理后,使其变成复杂的加密密文发送出去。接收方收到密文后,若想解读原文,则需要使用同一个加密密钥以及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。
- **AES加密**
- **AES密钥**
AES的全称是Advanced Encryption Standard,是最常见的对称加密。AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。
- **3DES加密**
- **3DES密钥**
3DES,也称为 3DESede 或 TripleDES,是三重数据加密算法,相当于是对每个数据块应用三次DES的对称加密算法,它使用3个64位的密钥对数据块进行三次加密。相比DES,3DES因密钥长度变长,安全性有所提高,但其处理速度不高。因此又出现了AES加密算法,AES较于3DES速度更快、安全性更高。
**非对称密钥**
### 非对称密钥
非对称密钥使用公钥和私钥两个密钥来进行算法操作,公钥对外公开,私钥对外保密。对于加解密操作,一般使用公钥对明文进行加密形成密文,持有私钥的人即可对密文解密形成明文。对于签名验签操作,使用私钥对明文进行签名,公钥持有者可以通过公钥对签名数据做验签,验证数据是否被篡改。
- **RSA密钥**
RSA密钥以极大整数做因数分解的数学难题作为密钥安全性的基石。生成密钥时,首先需要随机出两个大素数p和q,计算n = p * q并将n做为模,再选择一个大于1且小于(p - 1) * (q - 1)的整数e,确保e与(p - 1)*(q - 1)互素,最后计算d,使得e * d - 1为(p - 1)和(q - 1)的倍数,则可得到公钥(n, e)和私钥(n, d)。
RSA算法是由Ron Rivest、Adi Shamir和Leonard Adleman一起提出的,是一种非对称加密算法,广泛应用于现代的信息加密传输等领域。它的数学基础是大质数相乘,对其积做因式分解的计算困难性。
RSA密钥参数,涉及三个整数,包括:
n:模数(Modulus),是私钥和公钥的公共参数。
算法库框架除提供了默认的双素数RSA密钥生成外,还提供了多素数密钥生成方式,可以在密钥生成时通过指定primes参数(PRIMES_2, PRIMES_3, PRIMES_4, PRIMES_5)指定素数个数。多素数密钥的优点是可以减少解密、签名的计算量(中国剩余定理),但相对的劣势是密钥强度会越低,算法库依据OpenSSL的素数使用规则制定了相应规格,具体将在**约束与限制**章节中说明。
sk:私钥指数(privateExponent),公式中常写作d。
pk:公钥指数(publicExponent),公式中常写作e。
- **ECC密钥**
ECC是一种基于椭圆曲线数学的公开密钥加密算法,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性,算法库框架提供了多种椭圆曲线的ECC密钥生成能力。
ECC的全称是Elliptic Curve Cryptography,是一种基于椭圆曲线数学的公开密钥加密算法,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性,算法库框架提供了多种椭圆曲线的ECC密钥生成能力。
椭圆曲线算法可以看作是定义在特殊集合下数的运算,当前算法库支持的是Fp域的椭圆曲线,p为素数,Fp域也称素数域。
Fp域下的ECC密钥参数,包括:
p: 素数,用于确定Fp。
a, b: 确定椭圆曲线的方程。
g: 椭圆曲线的一个基点(base point),可由gx,gy表示。
n: 基点g的阶(order)。
h: 余因子(cofactor)。
sk: 私钥,是一个随机整数,小于n。
pk: 公钥,是椭圆曲线上的一个点, pk = sk * g。
- **DSA密钥**
DSA的全称是Digital Signature Algorithm,是一种基于模算数和整数有限域离散对数难题的一种公开密钥算法,不能用于加解密,一般用于数字签名和验签,算法库框架提供了多种不同长度的DSA密钥生成能力。
**加解密**
DSA密钥参数,包括:
p:一个素模数,比特长度为64的整数倍。
q:p-1的素因子,长度与p的长度有关。
g:g = (h ^ ((p - 1) / q)) mod p,h为满足1 < h < p -1的任意整数。
sk:私钥,为随机生成的整数,满足0 < sk < q。
pk:公钥,pk = (g ^ sk) mod p。
### 加解密
- **对称AES加解密**
算法库目前提供了AES加解密常用的7种加密模式:ECB、CBC、OFB、CFB、CTR、GCM和CCM。AES为分组加密算法,分组长度大小为128位。实际应用中明文最后一组可能不足128位,不足数据可以使用各种padding模式做数据填充。下文中描述了各个padding的区别:
- NoPadding:不带填充。
- PKCS5:填充字符由一个字节序列组成,每个字节填充该填充字节序列的长度,规定是8字节填充。
- PKCS7:填充字符和PKCS5填充方法一致,但是可以在1-255字节之间任意填充。
- NoPadding:不带填充;
- PKCS5:填充字符由一个字节序列组成,每个字节填充该填充字节序列的长度,规定是8字节填充;
- PKCS7:填充字符和PKCS5填充方法一致,但是可以在1-255字节之间任意填充;
> **说明:**
>
> ECB、CBC加密模式,明文长度不是128位整数倍,必须使用填充方法补足。<br/>
> 由于需要填充至分组大小,所以实际算法库中的PKCS5和PKCS7都是以分组大小作为填充长度的,即AES加密填充至16字节。
> **说明:** ECB、CBC加密模式,明文长度不是128位整数倍,必须使用填充方法补足。<br/>由于需要填充至分组大小,所以实际算法库中的PKCS5和PKCS7都是以分组大小作为填充长度的,即AES加密填充至16字节。
- **对称3DES加解密**
该算法的加解密过程分别是对明文/密文数据进行三次DES加密或解密,得到相应的密文或明文。
算法库目前提供了3DES加解密常用的4种加密模式:ECB、CBC、OFB和CFB。DES为分组加密算法,分组长度大小为64位。实际应用中明文最后一组可能不足64位,不足数据可以使用各种padding模式做数据填充。下文中描述了各个padding的区别:
- NoPadding:不带填充。
- PKCS5:填充字符由一个字节序列组成,每个字节填充该填充字节序列的长度,规定是8字节填充。
- PKCS7:填充字符和PKCS5填充方法一致,但是可以在1-255字节之间任意填充。
- NoPadding:不带填充;
- PKCS5:填充字符由一个字节序列组成,每个字节填充该填充字节序列的长度,规定是8字节填充;
- PKCS7:填充字符和PKCS5填充方法一致,但是可以在1-255字节之间任意填充;
> **说明:** ECB、CBC加密模式,明文长度不是64位整数倍,必须使用填充方法补足。<br/>由于需要填充至分组大小,所以实际算法库中的PKCS5和PKCS7都是以分组大小作为填充长度的,即3DES加密填充至8字节。
> **说明:**
>
> ECB、CBC加密模式,明文长度不是64位整数倍,必须使用填充方法补足。<br/>
> 由于需要填充至分组大小,所以实际算法库中的PKCS5和PKCS7都是以分组大小作为填充长度的,即3DES加密填充至8字节。
- **非对称RSA加解密**
当持有RSA公钥(n, e)和私钥(n, d)后,RSA加密过程为:密文 = 明文 ^ e mod n, 解密过程为:明文 = 密文 ^ d mod n。算法库目前提供了RSA加解密常用的三种模式:PKCS1、PKCS1_OAEP和NoPadding。RSA为块加密算法,加密长度需要在固定长度进行,实际应用中会使用各种padding模式做数据填充。下文中描述了各个padding的区别:
- NoPadding:不带填充,输入的数据必须与RSA钥模一样长,输出数据长度与RSA钥模一样长。
- PKCS1:pkcs1padding V1.5是RSA加解密默认的填充方式,输入的数据必须<=RSA钥模-11,输出数据长度与RSA钥模一样长。
- PKCS1_OAEP:RSA_PKCS1_OAEP_PADDING填充模式是PKCS#1推出的新填充方式,此模式需要设置两个摘要(md和mgf1_md),输入的数据必须小于RSA钥模 - md摘要长度 - mgf1_md摘要长度 - 2,输出数据长度与RSA钥模一样长。
RSA为块加密算法,加密长度需要在固定长度进行,实际应用中会使用各种padding模式做数据填充。算法库目前提供了RSA加解密常用的三种模式:NoPadding、PKCS1和PKCS1_OAEP。下文中描述了各个padding的区别:
- NoPadding:不带填充,输入的数据必须与RSA钥模一样长,输出数据长度与RSA钥模一样长;
- PKCS1:即RFC3447规范中的RSAES-PKCS1-V1_5模式(对应于OpenSSL中的RSA_PKCS1_PADDING)在进行RSA运算时需要将源数据D转化为Encryption block(EB),加密时,输入的数据最大长度 <= RSA钥模 - 11,输出数据长度与RSA钥模一样长;
- PKCS1_OAEP:即RFC3447规范中的RSAES-OAEP模式(对应于OpenSSL中的RSA_PKCS1_OAEP_PADDING),是PKCS#1推出的新填充方式,此模式需要设置两个摘要(md和mgf1_md),加密时,输入的数据必须小于RSA钥模 - md摘要长度 - mgf1_md摘要长度 - 2(摘要长度以字节为单位),输出数据长度与RSA钥模一样长;此模式还可额外设置pSource字节流,来定义OAEP填充的编码输入P,并且可以获取PKCS1_OAEP的相关参数。<br/>
> **说明:**
>
> RSA钥模 = (RSA的bits + 7) / 8
PKCS1_OAEP的相关参数包括:
md: 摘要算法。
mgf: 掩码生成算法,目前仅支持MGF1。
**签名验签**
mgf1_md: mgf1摘要算法。
pSource: 字节流,用于编码输入。
> **说明:** RSA钥模 = (RSA的bits + 7) / 8
### 签名验签
- **RSA签名验签**
当持有RSA公钥(n, e)和私钥(n, d)后,RSA签名生成过程为:签名 = 消息 ^ d mod n, 验签过程为:消息 = 签名 ^ d mod n。消息发送方发送数据时,同时发送消息和私钥签名后的签名信息,消息接收方接受到数据后,将签名信息用公钥解密并验证消息是否一致。因发送的消息长度大多大于RSA钥模,因此算法库框架提供了两种padding模式,通过摘要提取消息的散列值再做签名。算法库框架中提供了签名验签相关的两种模式:PKCS1和PSS。下问对两种模式做详细描述:
- PKCS1: pkcs1padding V1.5是RSA加解密默认的填充方式,使用该模式时需要设置摘要(md)。
- PSS: PSS模式是RSA 算法的基础上叠加上一种填充算法,使用该签名算法时需要使用摘要(md)和掩码函数(mgf1_md)。
算法库框架目前提供了两种RSA签名验签的padding模式:PKCS1和PSS。下面对两种模式做详细描述:
- PKCS1: 即RFC3447规范中的RSASSA-PKCS1-V1_5模式(对应于OpenSSL中的RSA_PKCS1_PADDING),在签名验签时,使用该模式时需要设置摘要(md),摘要算法输出的长度(字节)需要小于RSA的钥模;
- PSS: 即RFC3447规范中的RSASSA-PSS模式(对应于OpenSSL中的RSA_PKCS1_PSS_PADDING),此模式需要设置两个摘要(md和mgf1_md),且md和mgf1_md长度之和(字节)需要小于RSA的钥模;此模式还可额外设置以字节为单位的盐长度(saltLen),并且可以获取PSS的相关参数;
PSS的相关参数包括:
md: 摘要算法。
mgf: 掩码生成算法,目前仅支持MGF1。
mgf1_md: MGF1算法中使用的摘要算法。
saltLen: 盐长度,以字节为单位。
trailer_field:用于编码操作的整数,其值只支持为1。
> **说明:** RSA钥模 = (RSA的bits + 7) / 8
- **ECDSA**
椭圆曲线数字签名算法(ECDSA)是基于椭圆曲线密码(ECC)模拟数字签名算法(DSA)。相比普通的离散对数问题(DLP)和大数分解问题(IFP),椭圆曲线密码的单位比特强度要高于其他公钥体制。算法库框架提供了多种椭圆曲线及摘要算法组合的椭圆曲线数字签名算法(ECDSA)能力。
椭圆曲线数字签名算法(ECDSA)是基于椭圆曲线密码(ECC)数字签名算法(DSA)。相比普通的离散对数问题(DLP)和大数分解问题(IFP),椭圆曲线密码的单位比特强度要高于其他公钥体制。算法库框架提供了多种椭圆曲线及摘要算法组合的椭圆曲线数字签名算法(ECDSA)能力。
**密钥协商**
- **DSA**
数字签名算法(DSA)的安全性基于整数有限域离散对数问题的困难性,这类签名标准具有较大的兼容性和适用性。
### 密钥协商
- **ECDH**
ECDH的全称是椭圆曲线迪菲-赫尔曼秘钥交换,是用来在一个非安全通道中建立起安全的共有加密资料,交换双方可以在不共享任何秘密的情况下协商出一个密钥。算法库框架基于开源算法库提供了多种椭圆曲线的ECDH能力。
**摘要**
### 摘要
消息摘要MD算法是一种能将任意长度的输入消息,通过哈希算法生成长度固定的摘要的算法。消息摘要算法通过其不可逆的特性能被用于敏感信息的加密。消息摘要算法也被称为哈希算法或单向散列算法。
在摘要算法相同时,生成的摘要值主要有下列特点:
- 当输入消息相同时,生成摘要序列相同
- 当输入消息的长度不一致时,生成摘要序列长度固定(摘要长度由算法决定)
- 当输入消息不一致时,生成摘要序列几乎不会相同(依然存在相同概率,由摘要长度决定相同概率)
- 当输入消息相同时,生成摘要序列相同
- 当输入消息的长度不一致时,生成摘要序列长度固定(摘要长度由算法决定)
- 当输入消息不一致时,生成摘要序列几乎不会相同(依然存在相同概率,由摘要长度决定相同概率)
消息摘要算法主要分为三类:MD,SHA与MAC(详见HMAC章节)
MD算法包括MD2,MD4和MD5。
SHA算法主要包括SHA1,SHA224,SHA256,SHA384,SHA512。
**消息验证码**
### 消息验证码
HMAC(Hash-based Message Authentication Code)是一种基于密钥的消息认证码算法。HMAC通过指定摘要算法,以通信双方共享密钥与消息作为输入,生成消息认证码用于检验传递报文的完整性,HMAC生成的消息认证码为固定长度。HMAC在消息摘要算法的基础上增加了密钥的输入,确保了信息的正确性。
**随机数**
### 随机数
随机数在加解密过程中主要用于临时会话密钥的生成与非对称加密算法中密钥的生成。随机数由硬件生成的硬件随机数生成器或由软件生成的伪随机数生成器进行生成。在加解密的场景中,安全随机数生成器需要具备随机性,不可预测性,与不可重现性。密码学安全伪随机数生成器CSPRNG(Cryptography Secure Random Number Generators)生成的随机数满足密码学安全伪随机性
- **内部状态**代表随机数生成器内存中的数值,当内部状态相同时,随机数生成器会生成固定的随机数序列
- **种子**(seed)是一个用来对伪随机数的内部状态进行初始化的数据,随机数生成器通过种子来生成一系列的随机序列。
## 约束与限制
- 算法库框架不支持多线程并发操作。
- 算法库当前只支持OpenSSL。
- 使用密钥参数生成密钥时,用到的bigint类型需要以大端的形式输入,且必须为正数。
- 加解密算法库提供常用算法,其中有部分算法和规格并不适用于安全场景,如MD5等,用户需要根据使用需求选择适合的算法。
## 密钥生成规格
### 密钥生成规格
密钥生成有两种指定规格的方式:字符串参数 / 密钥参数。
- 字符串参数:以字符串的形式描述用户想要生成的密钥规格。
- 密钥参数:使用密钥的详细密码学信息,构造密钥对象。
**对称密钥生成规格**
### AES密钥生成规格
- 支持的对称密钥生成参数
- 支持以字符串参数来生成AES密钥,其生成参数如下表所示
|对称密钥算法|密钥长度(bit)|字符串参数|
|---|---|---|
|3DES|192|3DES192|
|AES|128|AES128|
|AES|192|AES192|
|AES|256|AES256|
> **说明:**
>
> “字符串参数”是“对称密钥算法”和“密钥长度”拼接而成,用于在创建对称密钥生成器时,指定密钥规格。
> **说明**:“字符串参数”是“对称密钥算法”和“密钥长度”拼接而成,用于在创建对称密钥生成器时,指定密钥规格。
**非对称密钥生成规格**
### 3DES密钥生成规格
- **RSA密钥生成**
- 支持以字符串参数来生成3DES密钥,其生成参数如下表所示:
支持的非对称密钥生成参数:
|对称密钥算法|密钥长度(bit)|字符串参数|
|---|---|---|
|3DES|192|3DES192|
> **说明**:“字符串参数”是“对称密钥算法”和“密钥长度”拼接而成,用于在创建对称密钥生成器时,指定密钥规格。
### RSA密钥生成规格
> **说明**:<br>
> 从API version 10开始, 支持使用密钥参数来生成RSA密钥。
|非对称密钥类型|素数个数|字符串参数|
- 支持以字符串参数来生成RSA密钥,其生成参数如下表所示:
|RSA密钥类型|素数个数|字符串参数|
|---|---|---|
|RSA512|2|RSA512\|PRIMES_2|
|RSA768|2|RSA768\|PRIMES_2|
......@@ -163,28 +233,102 @@ HMAC(Hash-based Message Authentication Code)是一种基于密钥的消息
|RSA8192|4|RSA8192\|PRIMES_4|
|RSA8192|5|RSA8192\|PRIMES_5|
> **说明:**
>
> 生成RSA非对称密钥时,默认素数为2,PRIMES_2参数可省略。
> **说明**:“字符串参数”是“RSA密钥类型”和“素数个数”拼接而成,用于在创建非对称密钥生成器时,指定密钥规格。生成RSA非对称密钥时,默认素数为2,PRIMES_2参数可省略。
- **ECC密钥生成**
- 支持以密钥参数来生成RSA密钥,其密钥参数种类和各个密钥参数的密码学规格要求如下表所示:
| |公共参数|公钥参数|私钥参数|公私钥对参数|
|---|---------|---|---|---|
|n |× |√ |× |√ |
|pk| |√ | |√ |
|sk| | |× |√ |
支持的非对称密钥生成参数:
> **说明**:密钥参数用于在创建非对称密钥生成器时,指定密钥规格。</br>
> 上表说明了算法库对于指定公/私钥参数生成RSA密钥的支持情况。</br>
打√的表示需要指定这一列中的具体属性,来构成密钥参数。</br>
打×的表示这一列中的具体属性对应于某种密钥参数,但是算法库当前不支持通过该密钥参数生成密钥。
|非对称密钥算法|密钥长度|
|---|---|
|ECC|ECC224|
|ECC|ECC256|
|ECC|ECC384|
|ECC|ECC521|
> **注意**:
> 1. RSA不支持通过指定公共参数(n)来随机生成密钥。</br>
> 2. RSA不支持通过指定私钥参数(n, sk)来生成私钥。
### 加解密规格
### ECC密钥生成规格
**对称加解密**
> **说明**:<br>
> 从API version 10开始, 支持使用密钥参数来生成ECC密钥。
- 支持以字符串参数来生成ECC密钥,其生成参数如下表所示:
- 支持的对称加密算法:
|非对称密钥算法|密钥长度(bit)|曲线名|字符串参数|
|---|---|---|---|
|ECC|224|NID_secp224r1|ECC224|
|ECC|256|NID_X9_62_prime256v1|ECC256|
|ECC|384|NID_secp384r1|ECC384|
|ECC|521|NID_secp521r1|ECC521|
> **说明**:“字符串参数”是“非对称密钥算法”和“密钥长度”拼接而成,用于在创建非对称密钥生成器时,指定密钥规格。</br>
> 当前支持的ECC均为Fp域曲线。
- 支持以密钥参数来生成ECC密钥,其密钥参数种类和各个密钥参数的密码学规格要求如下表所示:
| |公共参数|公钥参数|私钥参数|公私钥对参数|
|---|---|---|---|---|
|fieldType| √| √| √| √|
|p | √| √| √| √|
|a | √| √| √| √|
|b | √| √| √| √|
|g | √| √| √| √|
|n | √| √| √| √|
|h | √| √| √| √|
|pk | | √| | √|
|sk | | | √| √|
> **说明**:密钥参数用于在创建非对称密钥生成器时,指定密钥规格。</br>
> 上表说明了算法库对于指定公/私钥参数生成ECC密钥的支持情况。</br>
> 打√的表示需要指定这一列中的具体属性,来构成密钥参数。
> **注意**:
> 1. 当前ECC只支持Fp域,因此fieldType固定为"Fp"。fieldType和p构成了属性field,当前field只支持[ECFieldFp](../reference/apis/js-apis-cryptoFramework.md#ecfieldfp10)。</br>
> 2. g和pk为ECC曲线上的点,属于[Point](../reference/apis/js-apis-cryptoFramework.md#point10)类型,需要指定具体X,Y坐标。
### DSA密钥生成规格
> **说明**:<br>
> 从API version 10开始, 支持DSA算法,包括密钥生成和签名验签。
- 支持以字符串参数来生成DSA密钥,其生成参数如下表所示:
|非对称密钥算法|密钥长度(bit)|字符串参数|
|---|---|---|
|DSA|1024|DSA1024|
|DSA|2048|DSA2048|
|DSA|3072|DSA3072|
> **说明**:“字符串参数”是“非对称密钥算法”和“密钥长度”拼接而成,用于在创建非对称密钥生成器时,指定密钥规格。</br>
|对称加解密算法|分组模式| 字符串参数 |
- 支持以密钥参数来生成RSA密钥,其密钥参数种类和各个密钥参数的密码学规格要求如下表所示:
| |公共参数|公钥参数|私钥参数|公私钥对参数|
|---|---------|---|---|---|
|p |√ |√ |× |√ |
|q |√ |√ |× |√ |
|g |√ |√ |× |√ |
|pk | |√ | |√ |
|sk | | |× |√ |
> **说明**:密钥参数用于在创建非对称密钥生成器时,指定密钥规格。</br>
> 上表说明了算法库对于指定公/私钥参数生成DSA密钥的支持情况。</br>
打√的表示需要指定这一列中的具体属性,来构成密钥参数。</br>
打×的表示这一列中的具体属性对应于某种密钥参数,但是算法库当前不支持通过该密钥参数生成密钥。
> **注意**:
> 1. DSA不支持通过指定私钥参数(p, q, g, sk)来生成私钥。</br>
> 2. 当使用公共参数(p, q, g)来生成DSA密钥对时,DSA密钥长度至少需要1024位。
## 加解密规格
### 对称加解密
> **说明**:<br>
> 从API version 10开始, 支持对称加解密不带密钥长度的规格。
- 支持的对称加密算法:
|对称加解密算法|分组模式|字符串参数 |
|---|---|---|
|3DES|ECB|3DES192\|ECB\|[NoPadding\|PKCS5\|PKCS7]|
|3DES|CBC|3DES192\|CBC\|[NoPadding\|PKCS5\|PKCS7]|
......@@ -203,10 +347,11 @@ HMAC(Hash-based Message Authentication Code)是一种基于密钥的消息
> 1. []中只能任选一项。
> 2. “字符串参数”是“对称加解密算法(含密钥长度)”、“分组模式”、“填充模式”拼接而成,用于在创建对称加解密实例时,指定对称加解密算法规格。
**非对称RSA加解密**
### 非对称RSA加解密
> **说明**:<br>
> 从API version 10开始, 支持非对称RSA加解密不带密钥长度的规格。
RSA加解密时,涉及三种填充模式:NoPadding, PKCS1和PKCS1_OAEP。
- 使用NoPadding模式时可以指定的参数:
|非对称密钥类型| 填充模式 | 字符串参数 |
......@@ -218,6 +363,12 @@ RSA加解密时,涉及三种填充模式:NoPadding, PKCS1和PKCS1_OAEP。
|RSA3072|NoPadding|RSA3072\|NoPadding|
|RSA4096|NoPadding|RSA4096\|NoPadding|
|RSA8192|NoPadding|RSA8192\|NoPadding|
|RSA|NoPadding|RSA\|NoPadding|
> **说明:**
>
> 1. “字符串参数”是“非对称密钥类型”、“填充模式”拼接而成,用于在创建非对称加解密实例时,指定非对称加解密算法规格。
> 2. 在上表最后一行,为了兼容由密钥参数生成的密钥,RSA加解密参数输入密钥类型时支持不带长度,加解密运算取决于实际输入的密钥长度。
- 使用PKCS1模式时可以指定的参数:
......@@ -230,14 +381,14 @@ RSA加解密时,涉及三种填充模式:NoPadding, PKCS1和PKCS1_OAEP。
|RSA3072|PKCS1|RSA3072\|PKCS1|
|RSA4096|PKCS1|RSA4096\|PKCS1|
|RSA8192|PKCS1|RSA8192\|PKCS1|
- 使用PKCS1_OAEP模式时可以指定的参数:
|RSA|PKCS1|RSA\|PKCS1|
> **说明:**
>
> 1. []内的参数只能任选一项,非[]内的为固定值;
> 2. 使用时请从表格中选择非对称密钥类型、填充模式、摘要、掩码摘要四个数据,用|拼接成字符串。<br>
> 例如:"RSA2048|PKCS1_OAEP|SHA256|MGF1_SHA256"
> 1. “字符串参数”是“非对称密钥类型”、“填充模式”拼接而成,用于在创建非对称加解密实例时,指定非对称加解密算法规格。
> 2. 在上表最后一行,为了兼容由密钥参数生成的密钥,RSA加解密参数输入密钥类型时支持不带长度,加解密运算取决于实际输入的密钥长度。
- 使用PKCS1_OAEP模式时可以指定的参数:
| 非对称密钥类型 | 填充模式 | 摘要 | 掩码摘要 |
|---|---|---|---|
......@@ -278,34 +429,56 @@ RSA加解密时,涉及三种填充模式:NoPadding, PKCS1和PKCS1_OAEP。
|RSA8192|PKCS1_OAEP|MD5|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PKCS1_OAEP|SHA1|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PKCS1_OAEP|SHA224|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PKCS1_OAEP|SHA256|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512 ]|
|RSA8192|PKCS1_OAEP|SHA256|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PKCS1_OAEP|SHA384|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PKCS1_OAEP|SHA512|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA|PKCS1_OAEP|符合长度要求的摘要算法|MGF1_符合长度要求的摘要算法|
### 签名验签规格
> **说明:**
>
> 1. []内的参数只能任选一项,非[]内的为固定值;
> 2. 使用时请从表格中选择非对称密钥类型、填充模式、摘要、掩码摘要四个数据,用|拼接成“字符串参数”,用于在创建非对称加解密实例时,指定非对称加解密算法规格。
> 例如:"RSA2048|PKCS1_OAEP|SHA256|MGF1_SHA256"
> 3. 在上表最后一行,为了兼容由密钥参数生成的密钥,RSA加解密参数输入密钥类型时支持不带长度,加解密运算取决于实际输入的密钥长度。
> 4. 输入的数据必须小于RSA钥模 - md摘要长度 - mgf1_md摘要长度 - 2,如RSA密钥为512位时,不支持SHA512,RSA钥模和摘要长度定义,详见[加解密](#加解密)中RSA的相关描述。
- 使用PKCS1_OAEP模式时,可以通过获取加解密OAEP填充模式的各个[参数](../reference/apis/js-apis-cryptoFramework.md#cipherspecitem10),并设置OAEP填充的编码输入P。
| OAEP参数 |枚举值| 获取 | 设置 |
|---|---|---|---|
|md|OAEP_MD_NAME_STR |√||
|mgf|OAEP_MGF_NAME_STR|√||
|mgf1_md|OAEP_MGF1_MD_STR |√||
|pSource|OAEP_MGF1_PSRC_UINT8ARR|√|√|
**RSA签名验签**
> **说明**:</br>
> 上表说明了算法库对于OAEP参数的获取和设置支持情况,打√的表示需要对该参数具有获取或设置的能力。
RSA签名验签时,涉及两种填充模式:PKCS1和PSS。
## 签名验签规格
### RSA签名验签
> **说明**:<br>
> 从API version 10开始, 支持RSA签名验签不带密钥长度的规格。
RSA签名验签时,涉及两种填充模式:PKCS1和PSS。
- 使用PKCS1模式时可以指定的参数:
| 非对称密钥类型 | 填充模式 | 摘要 | 字符串参数 |
|---|---|---|---|
|RSA512|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384]|RSA512\|PKCS1\| [MD5\|SHA1\|SHA224\|SHA256\|SHA384]|
|RSA512|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384]|RSA512\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384]|
|RSA768|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|RSA768\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|RSA1024|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|RSA1024\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|RSA2048|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|RSA2048\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|RSA3072|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|RSA3072\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|RSA4096|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|RSA4096\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|RSA8192|PKCS1|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|RSA8192\|PKCS1\|[MD5\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|RSA|PKCS1|符合长度要求的摘要算法|RSA\|PKCS1\|符合长度要求的摘要算法|
- 使用PSS模式时可以指定的参数:
> **说明:**
>
> 1. []内的参数只能任选一项,非[]内的为固定值;
> 2. 使用时请从表格中选择非对称密钥类型、填充模式、摘要、掩码摘要四个数据,用|拼接成字符串。<br>
> 例如:"RSA2048|PSS|SHA256|MGF1_SHA256"
> 2. 在上表最后一行,为了兼容由密钥参数生成的密钥,RSA签名验签参数输入密钥类型时支持不带长度,签名验签运算取决于实际输入的密钥长度。
> 3. RSA签名验签时,摘要算法输出的长度,需要小于RSA的钥模, 如RSA密钥为512位时,不支持SHA512,详见[签名验签](#签名验签)中RSA的相关描述。
- 使用PSS模式时可以指定的参数:
| 非对称密钥类型 | 填充模式 | 摘要 | 掩码摘要 |
|---|---|---|---|
......@@ -348,42 +521,89 @@ RSA签名验签时,涉及两种填充模式:PKCS1和PSS。
|RSA8192|PSS|SHA224|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PSS|SHA256|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PSS|SHA384|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PSS|SHA512| [MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA8192|PSS|SHA512|[MGF1_MD5\|MGF1_SHA1\|MGF1_SHA224\|MGF1_SHA256\|MGF1_SHA384\|MGF1_SHA512]|
|RSA|PSS|符合长度要求的摘要算法|MGF1_符合长度要求的摘要算法|
**ECDSA签名验签**
> **说明:**
>
> 1. []内的参数只能任选一项,非[]内的为固定值;
> 2. 使用时请从表格中选择非对称密钥类型、填充模式、摘要、掩码摘要四个数据,用|拼接成“字符串参数”,用于在创建非对称签名验签实例时,指定非对称签名验签算法规格。
> 例如:"RSA2048|PSS|SHA256|MGF1_SHA256"
> 3. 在上表最后一行,为了兼容由密钥参数生成的密钥,RSA签名验签参数输入密钥类型时支持不带长度,签名验签运算取决于实际输入的密钥长度。
> 4. RSA签名验签时,对于PSS模式,md和mgf1_md长度之和(字节)需要小于RSA的钥模。如RSA密钥为512位时,无法支持md和mgf1_md同时为SHA256。RSA钥模和摘要长度定义,详见[签名验签](#签名验签)中RSA的相关描述。
- 使用PSS模式时,可以通过获取签名验签PSS填充模式的各个[参数](../reference/apis/js-apis-cryptoFramework.md#signspecitem10),并设置PSS的以字节为单位的盐长度(saltLen)。
| PSS参数 |枚举值| 获取 | 设置 |
|---|---|---|---|
|md|PSS_MD_NAME_STR |√||
|mgf|PSS_MGF_NAME_STR|√||
|mgf1_md|PSS_MGF1_MD_STR |√||
|saltLen|PSS_SALT_LEN_NUM|√|√|
|trailer_field|PSS_TRAILER_FIELD_NUM|√||
> **说明**:</br>
> 上表说明了算法库对于PSS参数的获取和设置支持情况,打√的表示需要对该参数具有获取或设置的能力。
### ECDSA签名验签
> **说明**:<br>
> 从API version 10开始, 支持ECDSA签名验签不带密钥长度的规格。
- 支持的ECDSA参数:
|非对称密钥算法|支持种类|
|---|---|
|ECC|ECC224|
|ECC|ECC256|
|ECC|ECC384|
|ECC|ECC521|
|非对称密钥类型|摘要|字符串参数|
|---|---|---|
|ECC224|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|ECC224\|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|ECC256|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|ECC256\|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|ECC384|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|ECC384\|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|ECC521|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|ECC521\|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|ECC|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|ECC\|[SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|摘要算法|支持种类|
|---|---|
|HASH|SHA1|
|HASH|SHA224|
|HASH|SHA256|
|HASH|SHA384|
|HASH|SHA512|
> **说明:**
> 1. []内的参数只能任选一项,非[]内的为固定值;
> 2. 使用时请从表格中选择非对称密钥类型、摘要二个数据,用|拼接成“字符串参数”,用于在创建非对称签名验签实例时,指定非对称签名验签算法规格。
> 例如:"ECC224|SHA256"
> 3. 在上表最后一行,为了兼容由密钥参数生成的密钥,ECDSA签名验签参数输入密钥类型时支持不带长度,签名验签运算取决于实际输入的密钥长度。
### DSA签名验签
> **说明**:<br>
> 从API version 10开始, 支持DSA签名验签规格。
- 支持的DSA参数:
|非对称密钥类型|摘要|字符串参数|
|---|---|---|
|DSA1024|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|DSA1024\|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|DSA2048|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|DSA2048\|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|DSA3072|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|DSA3072\|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
|DSA|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|DSA\|[NoHash\|SHA1\|SHA224\|SHA256\|SHA384\|SHA512]|
> **说明:**
> 1. []内的参数只能任选一项,非[]内的为固定值;
> 2. 使用时请从表格中选择非对称密钥类型、摘要二个数据,用|拼接成“字符串参数”,用于在创建非对称签名验签实例时,指定非对称签名验签算法规格。
> 例如:"DSA1024|SHA256"
> 3. 在上表最后一行,为了兼容由密钥参数生成的密钥,DSA签名验签参数输入密钥类型时支持不带长度,签名验签运算取决于实际输入的密钥长度。
### 密钥协商规格
## 密钥协商规格
**ECDH**
### ECDH
> **说明**:<br>
> 从API version 10开始, 支持ECDH不带密钥长度的规格。
- 支持的ECDH参数:
|非对称密钥算法|支持种类|
|非对称密钥算法|字符串参数|
|---|---|
|ECC|ECC224|
|ECC|ECC256|
|ECC|ECC384|
|ECC|ECC521|
|ECC|ECC|
> **说明:**
> 1. “字符串参数”,用于在创建密钥协商时,指定密钥协商算法规格。
> 2. 在上表最后一行,为了兼容由密钥参数生成的密钥,ECDH密钥协商参数输入密钥类型时支持不带长度,密钥协商运算取决于实际输入的密钥长度。
### MD消息摘要算法规格
## MD消息摘要算法规格
- 加解密算法库框架当前支持的MD算法参数:
|摘要算法|支持种类|
......@@ -395,8 +615,10 @@ RSA签名验签时,涉及两种填充模式:PKCS1和PSS。
|HASH|SHA512|
|HASH|MD5|
### HMAC消息认证码算法规格
> **说明:**
> “支持种类”,用于在创建MD消息摘要时,指定MD消息摘要算法规格。
## HMAC消息认证码算法规格
- 加解密算法库框架当前支持的HMAC算法参数:
|摘要算法|支持种类|
......@@ -406,3 +628,13 @@ RSA签名验签时,涉及两种填充模式:PKCS1和PSS。
|HASH|SHA256|
|HASH|SHA384|
|HASH|SHA512|
> **说明:**
> “支持种类”,用于在创建HMAC消息认证码时,指定HMAC消息认证码算法规格。
## 随机数
- 加解密算法库框架支持随机数生成算法,目前只支持“CTR_DRBG"算法规格
> **说明:**
> 1. 随机数生成算法目前支持生成长度为[1, INT_MAX]的安全随机数,长度单位为byte。
> 2. 随机数生成算法使用openssl的RAND_priv_bytes接口生成安全随机数。
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册