harmony(鸿蒙)加解密算法库框架开发指导

  • 2022-10-28
  • 浏览 (200)

加解密算法库框架开发指导

说明

本开发指导基于API version 9,OH SDK版本3.2.7以上,适用于JS语言开发

使用密钥对象生成与转换操作

场景说明

使用密钥生成操作中,典型的场景有:

  1. 随机生成算法库密钥对象。该对象可用于后续的加解密等操作。
  2. 根据指定数据生成算法库密钥对象(也就是将外部或存储的二进制数据转换为算法库的密钥对象)。该对象可用于后续的加解密等操作。
  3. 获取算法库密钥对象的二进制数据,用于存储或传输。 > 说明:密钥对象Key包括对称密钥SymKey和非对称密钥(公钥PubKey和私钥PriKey),其中公钥和私钥组成密钥对KeyPair。密钥之间的具体关系可参考API参考

接口及参数说明

详细接口说明可参考API参考

以上场景涉及的常用接口如下表所示:

实例名 接口名 描述
cryptoFramework createAsyKeyGenerator(algName : string) : AsyKeyGenerator 根据algName设置的非对称密钥规格,创建非对称密钥生成器对象
cryptoFramework createSymKeyGenerator(algName : string) : SymKeyGenerator 根据algName设置的对称密钥规格,创建对称密钥生成器对象
AsyKeyGenerator generateKeyPair(callback : AsyncCallback<KeyPair>) : void 使用callback方式,随机生成非对称密钥对象KeyPair
AsyKeyGenerator generateKeyPair() : Promise<KeyPair> 使用Promise方式,随机生成非对称密钥对象KeyPair
SymKeyGenerator generateSymKey(callback : AsyncCallback<SymKey>) : void 使用callback方式,随机生成对称密钥对象SymKey
SymKeyGenerator generateSymKey() : Promise<SymKey> 使用Promise方式,随机生成对称密钥对象SymKey
AsyKeyGenerator convertKey(pubKey : DataBlob, priKey : DataBlob, callback : AsyncCallback<KeyPair>) : void 使用callback方式,根据指定的公钥和私钥二进制数据生成KeyPair对象
(允许公钥/私钥为null,即只传入单一公钥或私钥,生成只携带公钥或私钥的KeyPair对象)
AsyKeyGenerator convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise<KeyPair> 使用Promise方式,根据指定的公钥和私钥二进制数据生成KeyPair对象
(允许公钥/私钥为null,即只传入单一公钥或私钥,生成只携带公钥或私钥的KeyPair对象)
SymKeyGenerator convertKey(key : DataBlob, callback : AsyncCallback<SymKey>) : void 使用callback方式,根据指定的二进制数据,生成对称密钥对象SymKey
SymKeyGenerator convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise<KeyPair> 使用Promise方式,根据指定的二进制数据,生成对称密钥对象SymKey
Key getEncoded() : DataBlob; 获取Key密钥对象的二进制数据(Key的子类实例包括对称密钥SymKey、公钥PubKey、私钥PriKey)

开发步骤

示例1:随机生成非对称密钥KeyPair,并获得二进制数据(场景1、3)

  1. 创建非对称密钥生成器;
  2. 通过非对称密钥生成器随机生成非对称密钥;
  3. 获取密钥对象的二进制数据;

以使用Promise方式随机生成RSA密钥(1024位,素数个数为2)为例:

import cryptoFramework from '@ohos.security.cryptoFramework';

function generateAsyKey() {
  // 创建非对称密钥生成器
  let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
  // 通过非对称密钥生成器,随机生成非对称密钥
  let keyGenPromise = rsaGenerator.generateKeyPair();
  keyGenPromise.then( keyPair => {
    globalKeyPair = keyPair;
    let pubKey = globalKeyPair.pubKey;
    let priKey = globalKeyPair.priKey;
    // 获取非对称密钥的二进制数据
    pkBlob = pubKey.getEncoded();
    skBlob = priKey.getEncoded();
    AlertDialog.show({ message : "pk bin data" + pkBlob.data} );
    AlertDialog.show({ message : "sk bin data" + skBlob.data} );
  })
}

示例2:随机生成对称密钥SymKey,并获得二进制数据(场景1、3)

  1. 创建对称密钥生成器;
  2. 通过对称密钥生成器随机生成对称密钥;
  3. 获取算法库密钥对象的二进制数据;

以使用Promise方式随机生成AES密钥(256位)为例:

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('AES256');
  // 通过密钥生成器随机生成对称密钥
  let promiseSymKey = symKeyGenerator.generateSymKey();
  promiseSymKey.then( key => {
    // 获取对称密钥的二进制数据,输出长度为256bit的字节流
    let encodedKey = key.getEncoded();
    console.info('key hex:' + uint8ArrayToShowStr(encodedKey.data));
  })
}

示例3:根据指定的RSA非对称密钥二进制数据,生成KeyPair对象(场景2)

  1. 获取RSA公钥或私钥二进制数据,公钥需满足ASN.1语法、X.509规范、DER编码格式,私钥需满足ASN.1语法、PKCS#8规范、DER编码格式。
  2. 创建AsyKeyGenerator对象,调用convertKey方法,传入公钥二进制和私钥二进制(二者非必选项,可只传入其中一个),转换为KeyPair对象。
import cryptoFramework from '@ohos.security.cryptoFramework';

function convertAsyKey() {
  let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024");
  let pkval = new Uint8Array([48,129,159,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,129,141,0,48,129,137,2,129,129,0,174,203,113,83,113,3,143,213,194,79,91,9,51,142,87,45,97,65,136,24,166,35,5,179,42,47,212,79,111,74,134,120,73,67,21,19,235,80,46,152,209,133,232,87,192,140,18,206,27,106,106,169,106,46,135,111,118,32,129,27,89,255,183,116,247,38,12,7,238,77,151,167,6,102,153,126,66,28,253,253,216,64,20,138,117,72,15,216,178,37,208,179,63,204,39,94,244,170,48,190,21,11,73,169,156,104,193,3,17,100,28,60,50,92,235,218,57,73,119,19,101,164,192,161,197,106,105,73,2,3,1,0,1]);
  let pkBlob = {data : pkval};
  rsaGenerator.convertKey(pkBlob, null, function(err, keyPair) {
    if (keyPair == null) {
      AlertDialog.show({message : "Convert keypair fail"});
    }
    AlertDialog.show({message : "Convert KeyPair success"});
  })
}

说明

当前convertKey操作,公钥只支持转换满足X.509规范的DER格式,私钥只支持PKCS#8规范的DER格式;

示例4:根据指定的ECC非对称密钥二进制数据,生成KeyPair对象(场景2、3)

  1. 获取ECC二进制密钥数据,封装成DataBlob对象。
  2. 调用convertKey方法,传入公钥二进制和私钥二进制(二者非必选项,可只传入其中一个),转换为KeyPair对象。
function convertEccAsyKey() {
    let pubKeyArray = new Uint8Array([4,196,55,233,100,227,224,38,38,5,128,81,53,112,129,7,59,189,116,105,182,87,190,85,31,248,172,116,213,7,206,85,190,65,169,193,138,173,232,187,74,54,78,251,29,131,192,223,251,227,170,138,80,7,98,193,216,168,235,114,255,188,70,134,104]);
    let priKeyArray = new Uint8Array([255,70,89,220,189,19,41,157,175,173,83,60,74,216,195,96,24,181,231,23,112,247,150,126,15,155,24,79,33,97,31,225]);
    let pubKeyBlob = { data: pubKeyArray };
    let priKeyBlob = { data: priKeyArray };
    let generator = cryptoFrameWork.createAsyKeyGenerator("ECC256");
    generator.convertKey(pubKeyBlob, priKeyBlob, (error, data) => {
        if (error) {
            AlertDialog.show({message : "Convert keypair fail"});
        }
        AlertDialog.show({message : "Convert KeyPair success"});
    })
}

示例5:根据指定的对称密钥二进制数据,生成SymKey对象(场景2、3)

  1. 创建对称密钥生成器;
  2. 通过对称密钥生成器,根据指定的对称密钥二进制数据,生成SymKey对象;
  3. 获取算法库密钥对象的二进制数据;

以使用callback方式生成3DES密钥(3DES密钥只能为192位)为例:

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 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};
}

function testConvertAesKey() {
  // 生成对称密钥生成器
  let symKeyGenerator = cryptoFramework.createSymKeyGenerator('3DES192');
  // 根据用户指定的数据,生成对称密钥
  let keyMaterialBlob = genKeyMaterialBlob();
  try {
    symKeyGenerator.convertKey(keyMaterialBlob, (error, key) => {
      if (error) {    // 业务逻辑执行错误通过callback的第一个参数返回错误信息
        console.error(`convertKey error, ${error.code}, ${error.message}`);
        return;
      }
      console.info(`key algName: ${key.algName}`);
      console.info(`key format: ${key.format}`);
      let encodedKey = key.getEncoded();    // 获取对称密钥的二进制数据,输出长度为192bit的字节流
      console.info('key getEncoded hex: ' + uint8ArrayToShowStr(encodedKey.data));
    })
  } catch (error) {    // 参数检查的错误以同步的方式立即抛出异常
    console.error(`convertKey failed, ${error.code}, ${error.message}`);
    return;
  }
}

使用加解密操作

场景说明

在数据存储或传输场景中,可以使用加解密操作用于保证数据的机密性,防止敏感数据泄露。使用加解密操作中,典型的场景有: 1. 使用对称密钥的加解密操作 2. 使用非对称密钥的加解密操作

接口及参数说明

详细接口说明可参考API参考

以上场景设计的常用接口如下表所示:

实例名 接口名 描述
cryptoFramework createCipher(transformation : string) : Cipher 根据transformation设置的算法参数创建Cipher对象
Cipher init(opMode : CryptoMode, key : Key, params : ParamsSpec, callback : AsyncCallback<void>) : void 使用callback方式设置密钥并初始化Cipher对象
Cipher init(opMode : CryptoMode, key : Key, params : ParamsSpec) : Promise<void> 使用Promise方式设置密钥并初始化Cipher对象
Cipher update(data : DataBlob, callback : AsyncCallback<DataBlob>) : void 使用callback方式添加加解密数据
Cipher update(data : DataBlob) : Promise<DataBlob> 使用Promise方式添加加解密数据
Cipher doFinal(data : DataBlob, callback : AsyncCallback<DataBlob>) : void 使用callback方式结束对所有数据的加解密
Cipher doFinal(data : DataBlob) : Promise<DataBlob> 使用Promise方式结束对所有数据的加解密

开发步骤

示例1:使用对称密钥的加解密操作

  1. 创建对称密钥生成器。
  2. 通过密钥生成器生成对称密钥。
  3. 创建加解密生成器。
  4. 通过加解密生成器加密或解密数据。

以AES GCM以Promise方式加解密为例:

import cryptoFramework from '@ohos.security.cryptoFramework';

var globalCipher;
var globalGcmParams;
var globalKey;
var globalCipherText;

function genGcmParamsSpec() {
  let arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0]; // 12 bytes
  let dataIv = new Uint8Array(arr);
  let ivBlob = {data : dataIv};

  arr = [0, 0, 0, 0 , 0, 0, 0, 0]; // 8 bytes
  let dataAad = new Uint8Array(arr);
  let aadBlob = {data : dataAad};

  arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0]; // 16 bytes
  let dataTag = new Uint8Array(arr);
  let tagBlob = {data : dataTag};
  let gcmParamsSpec = {iv : ivBlob, aad : aadBlob, authTag : tagBlob, algoName : "GcmParamsSpec"};
  return gcmParamsSpec;
}

// 可理解的字符串转成字节流
function stringToUint8Array(str) {
  let arr = [];
  for (let i = 0, j = str.length; i < j; ++i) {
    arr.push(str.charCodeAt(i));
  }
  return new Uint8Array(arr);
}

// 字节流以16进制输出
function uint8ArrayToShowStr(uint8Array) {
  return Array.prototype.map
    .call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2))
    .join('');
}

// 字节流转成可理解的字符串
function uint8ArrayToString(array) {
  let arrayString = '';
  for (let i = 0; i < array.length; i++) {
    arrayString += String.fromCharCode(array[i]);
  }
  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) => {
    setTimeout(() => {
      resolve('testAesGcm');
    }, 10)
  }).then(() => {
    // 生成对称密钥生成器
    let symAlgoName = 'AES128';
    let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgoName);
    if (symKeyGenerator == null) {
      console.error('createSymKeyGenerator failed');
      return;
    }
    console.info(`symKeyGenerator algName: ${symKeyGenerator.algName}`);
    // 通过密钥生成器随机生成128位长度的对称密钥
    let promiseSymKey = symKeyGenerator.generateSymKey();
    // 构造参数
    globalGcmParams = genGcmParamsSpec();

    // 生成加解密生成器
    let cipherAlgoName = 'AES128|GCM|PKCS7';
    try {
      globalCipher = cryptoFramework.createCipher(cipherAlgoName);
      console.info(`cipher algName: ${globalCipher.algName}`);
    } catch (error) {
      console.error(`createCipher failed, ${error.code}, ${error.message}`);
      return;
    }
    return promiseSymKey;
  }).then(key => {
      let encodedKey = key.getEncoded();
      console.info('key hex:' + uint8ArrayToShowStr(encodedKey.data));
      globalKey = key;
      return key;
  }).then(key => {
      // 初始化加解密操作环境:开始加密
      let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
      let promiseInit = globalCipher.init(mode, key, globalGcmParams);    // init
      return promiseInit;
  }).then(() => {
      let plainText = {data : stringToUint8Array('this is test!')};
      let promiseUpdate = globalCipher.update(plainText);   // update
      return promiseUpdate;
  }).then(updateOutput => {
      globalCipherText = updateOutput;
      let promiseFinal = globalCipher.doFinal(null);    // doFinal
      return promiseFinal;
  }).then(authTag => {
      // 获取加密后的认证信息
      globalGcmParams.authTag = authTag;
      return;
  }).then(() => {
      // 初始化加解密操作环境:开始解密
      let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
      let promiseInit = globalCipher.init(mode, globalKey, globalGcmParams);    // init
      return promiseInit;
  }).then(() => {
      let promiseUpdate = globalCipher.update(globalCipherText);    // update
      return promiseUpdate;
  }).then(updateOutput => {
      console.info('decrypt plainText: ' + uint8ArrayToString(updateOutput.data));
      let promiseFinal = globalCipher.doFinal(null);    // doFinal
      return promiseFinal;
  }).then(finalOutput => {
      if (finalOutput == null) {
          console.info('GCM finalOutput is null');
      }
  }).catch(error => {
      console.error(`catch error, ${error.code}, ${error.message}`);
  })
}

以3DES ECB以callback方式加解密(采用已有数据生成密钥)为例:

import cryptoFramework from '@ohos.security.cryptoFramework';

var globalCipher;
var globalGcmParams;
var globalKey;
var globalCipherText;

// 可理解的字符串转成字节流
function stringToUint8Array(str) {
  let arr = [];
  for (let i = 0, j = str.length; i < j; ++i) {
    arr.push(str.charCodeAt(i));
  }
  return new Uint8Array(arr);
}

// 字节流以16进制输出
function uint8ArrayToShowStr(uint8Array) {
  return Array.prototype.map
    .call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2))
    .join('');
}

// 字节流转成可理解的字符串
function uint8ArrayToString(array) {
  let arrayString = '';
  for (let i = 0; i < array.length; i++) {
    arrayString += String.fromCharCode(array[i]);
  }
  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};
}

// 3DES ECB模式示例,采用已有数据生成密钥(callback写法)
function test3DesEcb() {
  // 生成对称密钥生成器
  let symAlgoName = '3DES192';
  let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgoName);
  if (symKeyGenerator == null) {
    console.error('createSymKeyGenerator failed');
    return;
  }
  console.info(`symKeyGenerator algName: ${symKeyGenerator.algName}`);

  // 生成加解密生成器
  let cipherAlgoName = '3DES192|ECB|PKCS7';
  try {
    globalCipher = cryptoFramework.createCipher(cipherAlgoName);
    console.info(`cipher algName: ${globalCipher.algName}`);
  } catch (error) {
    console.error(`createCipher failed, ${error.code}, ${error.message}`);
    return;
  }

  // 根据指定的数据,生成对称密钥
  let keyMaterialBlob = genKeyMaterialBlob();
  try {
    symKeyGenerator.convertKey(keyMaterialBlob, (error, key) => {
      if (error) {
        console.error(`convertKey error, ${error.code}, ${error.message}`);
        return;
      }
      console.info(`key algName: ${key.algName}`);
      console.info(`key format: ${key.format}`);
      let encodedKey = key.getEncoded();
      console.info('key getEncoded hex: ' + uint8ArrayToShowStr(encodedKey.data));
      globalKey = key;

      // 初始化加解密操作环境:开始加密
      let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
      // init
      globalCipher.init(mode, key, null, (err, ) => {
        let plainText = {data : stringToUint8Array('this is test!')};
        // update
        globalCipher.update(plainText, (err, updateOutput) => {
          globalCipherText = updateOutput;
          //doFinal
          globalCipher.doFinal(null, (err, finalOutput) => {
            if (error) {
              console.error(`doFinal error, ${error.code}, ${error.message}`);
              return;
            }
            if (finalOutput != null) {
              globalCipherText = Array.from(globalCipherText.data);
              finalOutput = Array.from(finalOutput.data);
              globalCipherText = globalCipherText.concat(finalOutput);
              globalCipherText = new Uint8Array(globalCipherText);
              globalCipherText = {data : globalCipherText};
            }
            // 初始化加解密操作环境:开始解密
            let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
            // init
            globalCipher.init(mode, globalKey, null, (err, ) => {
              // update
              globalCipher.update(globalCipherText, (err, updateOutput) => {
                console.info('decrypt plainText: ' + uint8ArrayToString(updateOutput.data));
                // doFinal
                globalCipher.doFinal(null, (error, finalOutput) => {
                  if (finalOutput != null) {
                    console.info("decrypt plainText:" + uint8ArrayToString(finalOutput.data));
                  }
                })
              })
            })
          })
        })
      })
    })
  } catch (error) {
    console.error(`convertKey failed, ${error.code}, ${error.message}`);
    return;
  }
}

示例2:使用非对称密钥的加解密操作

  1. 生成RSA密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成RSA非对称密钥。
  2. 生成Cipher对象。通过createCipher接口创建Cipher对象,执行初始化操作,设置密钥及加解密模式。
  3. 执行加解密操作。通过调用Cipher对象提供的doFinal接口,执行加密操作生成密文或执行解密操作生成明文。
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) {
    arr.push(str.charCodeAt(i));
  }
  var tmpArray = new Uint8Array(arr);
  return tmpArray;
}

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(() => {
    let input = { data : stringToUint8Array(plan) };
    return cipher.doFinal(input);
  }).then(dataBlob => {
    console.info("EncryptOutPut is " + dataBlob.data);
  });
}

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) };
      cipher.doFinal(input, function (err, data) {
        console.info("EncryptOutPut is " + data.data);
      })
    })
  })
}

说明

  1. 使用RSA加解密时,Cipher对象不可重复调用init方法初始化,在创建了一个加密Cipher对象后,如果要进行解密,则需要重新创建另一个Cipher对象执行解密操作。
  2. RSA加密有长度限制,允许加密明文的最大长度见加解密算法库框架概述中的基本概念章节。
  3. RSA解密每次允许解密的密文长度为,RSA密钥的位数/8。

使用签名验签操作

场景说明

当需要判断接收的数据是否被篡改且是否为指定对象发送的数据时,可以使用签名验签操作。使用签名验签操作中,典型的场景有: 1. 使用RSA签名验签操作 2. 使用ECC签名验签操作

接口及参数说明

详细接口说明可参考API参考

实例名 接口名 描述
cryptoFramework createSign(algName : string) : Sign 根据String设置的参数创建Sign对象
Sign init(priKey : PriKey, callback : AsyncCallback<void>) : void 使用callback方式设置密钥并初始化Sign对象
Sign init(priKey : PriKey) : Promise<void> 使用Promise方式设置密钥并初始化Sign对象
Sign update(data : DataBlob, callback : AsyncCallback<void>) : void 使用callback方式添加签名数据
Sign update(data : DataBlob) : Promise<void> 用Promise方式添加签名数据
Sign sign(data : DataBlob, callback : AsyncCallback<DataBlob>) : void 使用callback方式签名所有数据
Sign sign(data : DataBlob) : Promise<DataBlob> 使用Promise方式签名所有数据
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 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方式验签所有数据

开发步骤

示例1:使用RSA签名验签操作 1. 生成RSA密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成RSA非对称密钥。 2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥。 3. 执行签名操作。通过Sign类提供的update接口,添加签名数据,并调用sign接口生成数据的签名。 4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥。 5. 执行验签操作。通过Verify类提供的update接口,添加签名数据,并调用verify接口传入签名进行验签。

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 plan1";
let input1 = { data : stringToUint8Array(plan1) };
let input2 = { data : stringToUint8Array(plan2) };

function signMessagePromise() {
  let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
  let signer = cryptoFramework.createSign("RSA1024|PKCS1|SHA256");
  let keyGenPromise = rsaGenerator.generateKeyPair();
  keyGenPromise.then( keyPair => {
    globalKeyPair = keyPair;
    let priKey = globalKeyPair.priKey;
    return signer.init(priKey);
  }).then(() => {
    return signer.update(input1);
  }).then(() => {
    return signer.sign(input2);
  }).then(dataBlob => {
    SignMessageBlob = dataBlob;
    console.info("sign output is " + SignMessageBlob.data);
  });
}

function verifyMessagePromise() {
  let verifyer = cryptoFramework.createVerify("RSA1024|PKCS1|SHA256");
  let verifyInitPromise = verifyer.init(globalKeyPair.pubKey);
  verifyInitPromise.then(() => {
    return verifyer.update(input1);
  }).then(() => {
    return verifyer.verify(input2, SignMessageBlob);
  }).then(res => {
    console.log("Verify result is " + res);
  });
}

function signMessageCallback() {
  let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
  let signer = cryptoFramework.createSign("RSA1024|PKCS1|SHA256");
  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);
        });
      });
    });
  });
}

function verifyMessageCallback() {
  let verifyer = cryptoFramework.createVerify("RSA1024|PKCS1|SHA256");
  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);
      });
    });
  })
}

示例2:使用ECDSA操作 1. 生成ECC密钥。通过createAsyKeyGenerator接口创建AsyKeyGenerator对象,并生成ECC非对称密钥。 2. 生成Sign对象。通过createSign接口创建Sign对象,执行初始化操作并设置签名私钥。 3. 执行签名操作。通过Sign类提供的update接口,添加签名数据,并调用doFinal接口生成数据的签名。 4. 生成Verify对象。通过createVerify接口创建Verify对象,执行初始化操作并设置验签公钥。 5. 执行验签操作。通过Verify类提供的update接口,添加签名数据,并调用doFinal接口传入签名进行验签。

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 plan1";
let input1 = { data : stringToUint8Array(plan1) };
let input2 = { data : stringToUint8Array(plan2) };

function signMessagePromise() {
  let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
  let signer = cryptoFramework.createSign("ECC256|SHA256");
  let keyGenPromise = eccGenerator.generateKeyPair();
  keyGenPromise.then( keyPair => {
    globalKeyPair = keyPair;
    let priKey = globalKeyPair.priKey;
    return signer.init(priKey);
  }).then(() => {
    return signer.update(input1);
  }).then(() => {
    return signer.sign(input2);
  }).then(dataBlob => {
    SignMessageBlob = dataBlob;
    console.info("sign output is " + SignMessageBlob.data);
  });
}

function verifyMessagePromise() {
  let verifyer = cryptoFramework.createVerify("ECC256|SHA256");
  let verifyInitPromise = verifyer.init(globalKeyPair.pubKey);
  verifyInitPromise.then(() => {
    return verifyer.update(input1);
  }).then(() => {
    return verifyer.verify(input2, SignMessageBlob);
  }).then(res => {
    console.log("Verify result is " + res);
  });
}

function signMessageCallback() {
  let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
  let signer = cryptoFramework.createSign("ECC256|SHA256");
  eccGenerator.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);
        });
      });
    });
  });
}

function verifyMessageCallback() {
  let verifyer = cryptoFramework.createVerify("ECC256|SHA256");
  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);
      });
    });
  })
}

使用摘要操作

场景说明

用户指定摘要算法(如SHA256)生成Md实例,并输入单段或多段需要摘要的信息,进行摘要计算更新,并返回消息摘要计算结果,在指定算法后可获取当前算法名与摘要计算长度(字节)

使用摘要操作的主要场景为:

用户指定摘要算法(如SHA256)生成Md实例,并输入单段或多段需要摘要的信息,进行摘要计算更新,并返回消息摘要计算结果,在指定算法后可获取当前算法名与摘要计算长度(字节)

接口及参数说明

详细接口说明可参考API参考

实例名 接口名 描述
cryptoFramework function createMd(algName : string) : Md; 指定摘要算法,生成摘要操作实例Md
Md update(input : DataBlob, callback : AsyncCallback<void>) : void; 接受用户输入数据,通过Callback的方式,异步更新摘要
Md update(input : DataBlob) : Promise<void>; 接受用户输入数据,通过Promise的方式,异步更新摘要
Md digest(callback : AsyncCallback<DataBlob>) : void; 通过Callback的方式,返回结果
Md digest() : Promise<DataBlob>; 通过Promise的方式,返回结果
Md getMdLength() : number; 获取摘要的长度(由指定的摘要算法决定)
Md readonly algName : string; 获取当前设置的摘要算法名

开发步骤

  1. 设置算法,通过接口createMd生成摘要操作实例
  2. 接受用户数据,通过接口update,更新摘要,此步骤可重复
  3. 通过接口digest,返回摘要计算结果
  4. 获取当前摘要算法名与摘要计算长度
import cryptoFramework from "@ohos.security.cryptoFramework"

// turn string into uint8Arr
function stringToUint8Array(str) {
  var arr = [];
  for (var i = 0, j = str.length; i < j; ++i) {
      arr.push(str.charCodeAt(i));
  }
  var tmpUint8Array = new Uint8Array(arr);
  return tmpUint8Array;
}

// generate dataBlob with given length
function GenDataBlob(dataBlobLen) {
  var dataBlob;
  if (dataBlobLen == 12) {
      dataBlob = {data: stringToUint8Array("my test data")};
  } else {
      console.error("GenDataBlob: dataBlobLen is invalid");
      dataBlob = {data: stringToUint8Array("my test data")};
  }
  return dataBlob;
}

// md with promise async
function doMdByPromise(algName) {
  var md;
  try {
    md = cryptoFramework.createMd(algName);
  } catch (error) {
    console.error("[Promise]: error code: " + error.code + ", message is: " + error.message);
  }
  console.error("[Promise]: Md algName is: " + md.algName);
  var promiseMdUpdate = md.update(GenDataBlob(12));
  promiseMdUpdate.then(() => {
    var PromiseMdDigest = md.digest();
    return PromiseMdDigest;
  }).then(mdOutput => {
    console.error("[Promise]: MD result: " + mdOutput.data);
    var mdLen = md.getMdLength();
    console.error("[Promise]: MD len: " + mdLen);
  }).catch(error => {
    console.error("[Promise]: error: " + error.message);
  });
}

// md with callback async
function doMdByCallback(algName) {
  var md;
  try {
    md = cryptoFramework.createMd(algName);
  } catch (error) {
    console.error("[Callback]: error code: " + error.code + ", message is: " + error.message);
  }
  console.error("[Callback]: Md algName is: " + md.algName);
  md.update(GenDataBlob(12), (err,) => {
    if (err) {
      console.error("[Callback]: err: " + err.code);
    }
    md.digest((err1, mdOutput) => {
      if (err1) {
        console.error("[Callback]: err: " + err1.code);
      } else {
        console.error("[Callback]: MD result: " + mdOutput.data);
        var mdLen = md.getMdLength();
        console.error("[Callback]: MD len: " + mdLen);
      }
    });
  });
}

使用密钥协商操作

场景说明

使用密钥协商操作中,典型的场景有:

通信双方可以在一个公开的信道上通过相互传送一些消息,共同建立一个安全的共享秘密密钥。

接口及参数说明

详细接口说明可参考API参考

实例名 接口名 描述
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操作。
import cryptoFramework from "@ohos.security.cryptoFramework"

let globalKeyPair;

function ecdhPromise() {
  let eccGenerator = cryptoFramework.createAsyKeyGenerator("ECC256");
  let eccKeyAgreement = cryptoFramework.createKeyAgreement("ECC256");
  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);
    });
  });
}

使用消息认证码操作

场景说明

消息认证码操作主要应用于身份认证的场景:

Mac(message authentication code)可以对消息进行完整性校验,通过使用双方共享的密钥,识别出信息伪装篡改等行为

用户指定摘要算法(如SHA256)生成消息认证码Mac实例,输入对称密钥初始化Mac,并传入单段或多段需要摘要的信息,进行消息认证码计算,并获取消息认证码计算结果,在指定算法后可获取当前算法名与消息认证码计算长度(字节)。

接口及参数说明

详细接口说明可参考API参考

实例名 接口名 描述
cryptoFramework function createMac(algName : string) : Mac; 指定摘要算法,生成消息认证码实例Mac
Mac init(key : SymKey, callback : AsyncCallback<void>) : void; 接收输入对称密钥,通过Callback的方式,异步初始化MAC
Mac init(key : SymKey) : Promise<void>; 接收输入对称密钥,通过Promise的方式,异步初始化MAC
Mac update(input : DataBlob, callback : AsyncCallback<void>) : void; 接受输入数据,通过Callback的方式,异步更新MAC
Mac update(input : DataBlob) : Promise<void>; 接受输入数据,通过Promise的方式,异步更新MAC
Mac doFinal(callback : AsyncCallback<DataBlob>) : void; 通过Callback的方式,返回MAC计算结果
Mac doFinal() : Promise<DataBlob>; 通过Promise的方式,返回MAC计算结果
Mac getMacLength() : number; 获取MAC的长度(由指定的摘要算法决定)
Mac readonly algName : string; 获取当前设置的摘要算法名

开发步骤

  1. 设置算法,通过接口createMac生成消息认证码操作实例
  2. 接受输入对称密钥,通过接口init,初始化Mac
  3. 接受数据,通过接口update,更新Mac,此步骤可重复
  4. 通过接口doFinal,返回Mac计算结果
  5. 获取当前摘要算法名与Mac计算长度
import cryptoFramework from "@ohos.security.cryptoFramework"

// turn string into uint8Arr
function stringToUint8Array(str) {
  var arr = [];
  for (var i = 0, j = str.length; i < j; ++i) {
      arr.push(str.charCodeAt(i));
  }
  var tmpUint8Array = new Uint8Array(arr);
  return tmpUint8Array;
}

// generate blob with this func
function GenDataBlob(dataBlobLen) {
  var dataBlob;
  if (dataBlobLen == 12) {
      dataBlob = {data: stringToUint8Array("my test data")};
  } else {
      console.error("GenDataBlob: dataBlobLen is invalid");
      dataBlob = {data: stringToUint8Array("my test data")};
  }
  return dataBlob;
}

// process by promise
function doHmacByPromise(algName) {
  var mac;
  try {
    mac = cryptoFramework.createMac(algName);
  } catch (error) {
    console.error("[Promise]: error code: " + error.code + ", message is: " + error.message);
  }
  console.error("[Promise]: Mac algName is: " + mac.algName);
  var KeyBlob = {
    data : stringToUint8Array("12345678abcdefgh")
  }
  var symKeyGenerator = cryptoFramework.createSymKeyGenerator("AES128");
  var promiseConvertKey = symKeyGenerator.convertKey(KeyBlob);
  promiseConvertKey.then(symKey => {
    var promiseMacInit = mac.init(symKey);
    return promiseMacInit;
  }).then(() => {
    var promiseMacUpdate = mac.update(GenDataBlob(12));
    return promiseMacUpdate;
  }).then(() => {
    var PromiseMacDoFinal = mac.doFinal();
    return PromiseMacDoFinal;
  }).then(macOutput => {
    console.error("[Promise]: HMAC result: " + macOutput.data);
    var macLen = mac.getMacLength();
    console.error("[Promise]: MAC len: " + macLen);
  }).catch(error => {
    console.error("[Promise]: error: " + error.message);
  });
}

// process by callback
function doHmacByCallback(algName) {
  var mac;
  try {
    mac = cryptoFramework.createMac(algName);
  } 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);
  }
  var KeyBlob = {
    data : stringToUint8Array("12345678abcdefgh")
  }
  var symKeyGenerator = cryptoFramework.createSymKeyGenerator("AES128");
  symKeyGenerator.convertKey(KeyBlob, (err, symKey) => {
    if (err) {
      console.error("[Callback]: err: " + err.code);
    }
    mac.init(symKey, (err1, ) => {
      if (err1) {
        console.error("[Callback]: err: " + err1.code);
      }
      mac.update(GenDataBlob(12), (err2, ) => {
        if (err2) {
          console.error("[Callback]: err: " + err2.code);
        }
        mac.doFinal((err3, macOutput) => {
          if (err3) {
            console.error("[Callback]: err: " + err3.code);
          } else {
            console.error("[Callback]: HMAC result: " + macOutput.data);
            var macLen = mac.getMacLength();
            console.error("[Callback]: MAC len: " + macLen);
          }
        });
      });
    });
  });
}

使用随机数操作

场景说明

使用随机数操作的主要场景为:

  • 用户生成随机数Random实例,输入随机数生成的长度(字节),生成指定长度的随机数。
  • 用户使用生成的随机数作为参数,进行种子设置。

接口及参数说明

详细接口说明可参考API参考

实例名 接口名 描述
cryptoFramework function createRandom() : Random; 生成随机数Random实例
Random generateRandom(len : number, callback: AsyncCallback<DataBlob>) : void; 接受输入长度,通过Callback,异步生成随机数
Random generateRandom(len : number) : Promise<DataBlob>; 接受输入长度,通过Promise,异步生成随机数
Random setSeed(seed : DataBlob) : void; 接受输入Blob,设置种子

开发步骤

  1. 通过接口createRandom生成随机数操作实例
  2. 接受输入长度,通过接口generateRandom,生成指定长度的随机数
  3. 接受DataBlob数据,通过接口setSeed,为随机数生成池设置种子
import cryptoFramework from "@ohos.security.cryptoFramework"

// process by promise
function doRandByPromise(len) {
  var rand;
  try {
    rand = cryptoFramework.createRandom();
  } catch (error) {
    console.error("[Promise]: error code: " + error.code + ", message is: " + error.message);
  }
  var promiseGenerateRand = rand.generateRandom(len);
  promiseGenerateRand.then(randData => {
    console.error("[Promise]: rand result: " + randData.data);
      try {
          rand.setSeed(randData);
      } catch (error) {
          console.log("setSeed failed, errCode: " + error.code + ", errMsg: " + error.message);
      }
  }).catch(error => {
    console.error("[Promise]: error: " + error.message);
  });
}

// process by callback
function doRandByCallback(len) {
  var rand;
  try {
    rand = cryptoFramework.createRandom();
  } catch (error) {
    console.error("[Callback]: error code: " + error.code + ", message is: " + error.message);
  }
  rand.generateRandom(len, (err, randData) => {
    if (err) {
      console.error("[Callback]: err: " + err.code);
    } else {
      console.error("[Callback]: generate random result: " + randData.data);
      try {
          rand.setSeed(randData);
      } catch (error) {
          console.log("setSeed failed, errCode: " + error.code + ", errMsg: " + error.message);
      }
    }
  });
}

你可能感兴趣的鸿蒙文章

harmony(鸿蒙)安全

harmony(鸿蒙)访问控制授权申请

harmony(鸿蒙)访问控制(权限)开发概述

harmony(鸿蒙)HarmonyAppProvision配置文件说明

harmony(鸿蒙)证书开发指导

harmony(鸿蒙)证书概述

harmony(鸿蒙)加解密算法库框架概述

harmony(鸿蒙)Hap包签名工具指导

harmony(鸿蒙)Hap包签名工具概述

harmony(鸿蒙)通用密钥库密码算法规格

0  赞