头图

前言

加密算法是开发中常见的业务,为了安全起见,客户端与服务端传输数据,往往是通过加密之后进行通信,这样做的目的,可以保证数据的机密性,防止敏感数据泄露,而鸿蒙系统中,关于加密算法就比较容易实现,毕竟ArkTs是基于TypeScript实现的,所以有些算法之间基本是通用的。

加密方式有很多,比如对称加密,非对称加密,还有常见的消息摘要算法MD5,SHA等等,本文主要概述常见的几种算法,并简单封装后使用。

消息摘要算法

消息摘要算法,也就是哈希算法或单向散列算法,通过任意长度的消息,运算生成固定长度摘要的算法,鸿蒙中主要是通过cryptoFramework.createMd方法来实现各个算法。

目前支持的算法与规格如下:

摘要算法支持种类API版本
HASHSHA19+
HASHSHA2249+
HASHSHA2569+
HASHSHA3849+
HASHSHA5129+
HASHMD59+
HASHSM310+

举一个很简单的SHA256算法,其他规格,只需要更改种类即可。

    let md = cryptoFramework.createMd("SHA256")
    await md.update({ data: new Uint8Array(buffer.from("加密的数据", 'utf-8').buffer) })
    let mdResult = await md.digest()
    console.info('===加密后结果:' + mdResult.data)
    let sha256Result = this.uint8ArrayToString(mdResult.data)
    console.info('===转字符串后结果:' + sha256Result)
    let mdLen = md.getMdLength()
    console.info("===加密后长度: " + mdLen)

再比如,MD5:

    let md = cryptoFramework.createMd("MD5")
    await md.update({ data: new Uint8Array(buffer.from("加密的数据", 'utf-8').buffer) })
    let mdResult = await md.digest()
    console.info('===加密后结果:' + mdResult.data)
    let sha256Result = this.uint8ArrayToString(mdResult.data)
    console.info('===转字符串后结果:' + sha256Result)
    let mdLen = md.getMdLength()
    console.info("===加密后长度: " + mdLen)

从以上的代码中可以看出,基本上系统提供的Api已经足够的简洁。

Base64

其实要论严格来说,base64并不是加密算法,只是对应的编码格式,用于在文本协议中表示二进制数据,通过使用Base64编码,可以将二进制数据转换为可打印的ACSII字符,即Base64编码是从二进制到字符的过程,从而保证数据在传输过程中不受损失。

在鸿蒙当中也提供了Base64的编码与解密,使用起来也是非常的简单。


  // Base64 编码
  public base64Encode(str: string): string {
    let blob: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(str, 'utf-8').buffer) }
    let base64Helper = new util.Base64Helper()
    return base64Helper.encodeToStringSync(blob.data)
  }

  // Base64 解密
  public base64Decode(input: string): string {
    let base64Helper = new util.Base64Helper()
    let uint8Array = base64Helper.decodeSync(input)
    return buffer.from(uint8Array).toString("utf-8")
  }

AES对称加密

对称加密有一个显著的特点,那就是加密方和解密方使用的是同一个密钥,这种方式加解密的速度比较快,适合数据比较长时使用,但是密钥传输的过程不安全,且容易被破解,密钥管理也比较麻烦,常见的对称加密有,AES,DES,一般最常用的就是AES。

对称加密AES提供了7种加密模式,分别是ECB、CBC、OFB、CFB、CTR、GCM和CCM,不同的加密模式适用的加解密参数不同。

分组模式密钥长度(bit)填充模式API版本
ECB[128/192/256][NoPadding/PKCS5/PKCS7]9+
CBC[128/192/256][NoPadding/PKCS5/PKCS7]9+
CTR[128/192/256][NoPadding/PKCS5/PKCS7]9+
OFB[128/192/256][NoPadding/PKCS5/PKCS7]9+
CFB[128/192/256][NoPadding/PKCS5/PKCS7]9+
GCM[128/192/256][NoPadding/PKCS5/PKCS7]9+
CCM[128/192/256][NoPadding/PKCS5/PKCS7]9+

简单举例几个模式实际代码执行,无论哪种方式,都是需要秘钥和加解密内容,一般我们进行AES开发,首先要确定秘钥,然后确定加密内容和解密内容。

ECB模式,加解密

 // 加密消息
  async encryptMessagePromise(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
    let cipher = cryptoFramework.createCipher('AES128|ECB|PKCS7');
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null);
    let cipherData = await cipher.doFinal(plainText);
    return cipherData;
  }

  // 解密消息
  async decryptMessagePromise(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
    let decoder = cryptoFramework.createCipher('AES128|ECB|PKCS7');
    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null);
    let decryptData = await decoder.doFinal(cipherText);
    re

GCM模式,加解密

genGcmParamsSpec() {
    let ivBlob = this.generateRandom(12);
    let arr = [1, 2, 3, 4, 5, 6, 7, 8]; // 8 bytes
    let dataAad = new Uint8Array(arr);
    let aadBlob: cryptoFramework.DataBlob = { 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: cryptoFramework.DataBlob = {
      data: dataTag
    };
    // GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中
    let gcmParamsSpec: cryptoFramework.GcmParamsSpec = {
      iv: ivBlob,
      aad: aadBlob,
      authTag: tagBlob,
      algName: "GcmParamsSpec"
    };
    return gcmParamsSpec;
  }

  gcmParams = this.genGcmParamsSpec();

  // 加密消息
  async encryptMessagePromise(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
    let cipher = cryptoFramework.createCipher('AES128|GCM|PKCS7');
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, this.gcmParams);
    let encryptUpdate = await cipher.update(plainText);
    // gcm模式加密doFinal时传入空,获得tag数据,并更新至gcmParams对象中。
    this.gcmParams.authTag = await cipher.doFinal(null);
    return encryptUpdate;
  }

  // 解密消息
  async decryptMessagePromise(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
    let decoder = cryptoFramework.createCipher('AES128|GCM|PKCS7');
    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, this.gcmParams);
    let decryptUpdate = await decoder.update(cipherText);
    // gcm模式解密doFinal时传入空,验证init时传入的tag数据,如果验证失败会抛出异常。
    let decryptData = await decoder.doFinal(null);
    if (decryptData == null) {
      console.info('GCM decrypt success, decryptData is null');
    }
    return decryptUpdate;
  }

CCM模式,加解密

genCcmParamsSpec() {
    let rand: cryptoFramework.Random = cryptoFramework.createRandom();
    let ivBlob: cryptoFramework.DataBlob = rand.generateRandomSync(7);
    let aadBlob: cryptoFramework.DataBlob = rand.generateRandomSync(8);
    let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 bytes
    let dataTag = new Uint8Array(arr);
    let tagBlob: cryptoFramework.DataBlob = {
      data: dataTag
    };
    // CCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中
    let ccmParamsSpec: cryptoFramework.CcmParamsSpec = {
      iv: ivBlob,
      aad: aadBlob,
      authTag: tagBlob,
      algName: "CcmParamsSpec"
    };
    return ccmParamsSpec;
  }

  ccmParams = this.genCcmParamsSpec();

  // 加密消息
  async encryptMessagePromise(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
    let cipher = cryptoFramework.createCipher('AES128|CCM');
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, this.ccmParams);
    let encryptUpdate = await cipher.update(plainText);
    // ccm模式加密doFinal时传入空,获得tag数据,并更新至ccmParams对象中。
    this.ccmParams.authTag = await cipher.doFinal(null);
    return encryptUpdate;
  }

  // 解密消息
  async decryptMessagePromise(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
    let decoder = cryptoFramework.createCipher('AES128|CCM');
    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, this.ccmParams);
    let decryptUpdate = await decoder.doFinal(cipherText);
    return decryptUpdate;
  }

秘钥,在实际的开发中,我们可以根据提供的字符串或者其他特定字符生成我们的秘钥,一般为Base64编码之后的字符串形式秘钥,在加解密的时候,再进行解码即可。

RSA非对称加密

非对称加密和对称加密不同之处就在于,它有两个秘钥,一个公钥,一个私钥,公钥用于加密,私钥用于解密,相对于对称加密而言,安全系数上上了一层台阶,但是也有中间人攻击的风险,常见的非对称加密有,RSA,DSA,ECC等,一般最常用的就是RSA。

RSA也提供了多种加密方式,比如PKCS1模式,PKCS1\_OAEP模式,以及NoPadding。

PKCS1模式

// 加密消息
  async encryptMessagePromise(publicKey: cryptoFramework.PubKey, plainText: cryptoFramework.DataBlob) {
    let cipher = cryptoFramework.createCipher('RSA1024|PKCS1');
    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, publicKey, null);
    let encryptData = await cipher.doFinal(plainText);
    return encryptData;
  }

  // 解密消息
  async decryptMessagePromise(privateKey: cryptoFramework.PriKey, cipherText: cryptoFramework.DataBlob) {
    let decoder = cryptoFramework.createCipher('RSA1024|PKCS1');
    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, privateKey, null);
    let decryptData = await decoder.doFinal(cipherText);
    return decryptData;
  }

其它模式,不再举例了,大家可以去官网查看。

封装使用

大家可以使用以上的方式进行数据的加解密,当然了,也可以自行封装,或者使用他人封装好的,针对以上,我也简单封装了一下,有需要的朋友可以拿来使用。

简单功能列表

image.png

快速使用

方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。

建议:在使用的模块路径下进行执行命令。

ohpm install @abner/security

方式二:在工程的oh-package.json5中设置三方包依赖,配置示例如下:

"dependencies": { "@abner/security": "^1.0.0"}

代码使用

1、MD5

同步

let encryptContent = md5EncryptSync("加密的数据")
console.log("===加密后:" + encryptContent)

异步

md5Encrypt("加密的数据").then((content) => {
  console.log("===加密后:" + content)
})

2、BASE64

编码同步

let encryptContent = base64EncodeSync("我是测试数据")
this.mBase64EncodeString = encryptContent
console.log("===编码后:" + encryptContent)

编码异步

base64Encode("我是测试数据").then((encryptContent) => {
  this.mBase64EncodeString = encryptContent
  console.log("===编码后:" + encryptContent)
})

解码同步

base64Decode(this.mBase64EncodeString).then((decode) => {
  console.log("===解码后:" + decode)
})

3、SHA

sha默认是SHA256,可以根据需要进行修改,在第二个参数传入即可。

同步

let encryptContent = shaEncryptSync("1")
console.log("===加密后:" + encryptContent)

异步

shaEncrypt("1").then((content) => {
  console.log("===加密后:" + content)
})

修改algName

let encryptContent = shaEncryptSync("1","SHA256")
console.log("===加密后:" + encryptContent)

4、SM3

同步

let encryptContent = sM3EncryptSync("加密的数据")
console.log("===加密后:" + encryptContent)

异步

sM3Encrypt("加密的数据").then((content) => {
  console.log("===加密后:" + content)
})

5、AES

随机生成SymKey密钥【异步】

aesGenerateSymKey().then((symKey) => {
  this.mSymKey = symKey
  console.log("===密钥:" + symKey)
})

随机生成SymKey密钥【同步】

let symKey = aesGenerateSymKeySync()
this.mSymKey = symKey
console.log("===密钥:" + symKey)

字符串生成密钥【异步】

aesGenerateSymKey("1234").then((symKey) => {
  this.mSymKey = symKey
  console.log("===密钥:" + symKey)
})

字符串生成密钥【同步】

let symKeyString = aesGenerateSymKeySync("1234")
this.mSymKey = symKeyString
console.log("===密钥:" + symKeyString)

加密数据【异步】【ECB模式】

aesEncryptString("123", this.mSymKey).then((result) => {
  this.encryptString = result
  console.log("===加密后数据:" + result)
})

解密数据【异步】【ECB模式】

aesDecryptString(this.encryptString, this.mSymKey).then((result) => {
  console.log("===解密后数据:" + result)
})

加密数据【同步】【ECB模式】

let result = aesEncryptStringSync("123", this.mSymKey)
this.encryptString = result
console.log("===加密后数据:" + result)

解密数据【同步】【ECB模式】

let decryptString = aesDecryptStringSync(this.encryptString!, this.mSymKey!)
console.log("===加密后数据:" + decryptString)

6、RSA

随机生成KeyPair密钥对 【异步】

rsaGenerateAsyKey().then((keyPair) => {
  let pubKey = keyPair.pubKey //公钥
  let priKey = keyPair.priKey //私钥
  this.priKey = priKey
  this.pubKey = pubKey
})

随机生成KeyPair密钥对【同步】

let keyPair = rsaGenerateAsyKeySync()
let pubKey1 = keyPair.pubKey //公钥
let priKey1 = keyPair.priKey //私钥
this.priKey = priKey1
this.pubKey = pubKey1

随机生成字符串密钥对 【异步】

rsaGenerateAsyKeyPem().then((keyPairPem) => {
  let pubKey = keyPairPem.pubKey //公钥
  let priKey = keyPairPem.priKey //私钥
  console.log("===公钥:" + pubKey)
  console.log("===私钥:" + priKey)
})

随机生成字符串密钥对【同步】

let keyPairPem = generateAsyKeyPemSync()
let pubKeyPem = keyPairPem.pubKey //公钥
let priKeyPem = keyPairPem.priKey //私钥
console.log("===公钥:" + pubKeyPem)
console.log("===私钥:" + priKeyPem)

随机生成密钥对二进制【异步】

rsaGenerateAsyKeyDataBlob().then((dataBlobArray) => {
  let pubKey: cryptoFramework.DataBlob = dataBlobArray[0]
  let priKey: cryptoFramework.DataBlob = dataBlobArray[1]
  console.log("===公钥二进制:" + JSON.stringify(pubKey))
  console.log("===私钥二进制:" + JSON.stringify(priKey))
})

随机生成密钥对二进制【同步】

let dataBlobArray = rsaGenerateAsyKeyDataBlobSync()
let pubKey: cryptoFramework.DataBlob = dataBlobArray[0]
let priKey: cryptoFramework.DataBlob = dataBlobArray[1]
console.log("===公钥二进制:" + JSON.stringify(pubKey))
console.log("===私钥二进制:" + JSON.stringify(priKey))

指定二进制数据生成KeyPair密钥对【异步】

rsaGenKeyPairByData(this.pkData, this.skData).then((keyPair) => {
  let pubKey = keyPair.pubKey //公钥
  let priKey = keyPair.priKey //私钥
  this.priKey = priKey
  this.pubKey = pubKey
})

指定二进制数据生成KeyPair密钥对【同步】

let keyPairByDataSync = rsaGenKeyPairByDataSync(this.pkData, this.skData)
let pubKeyPairByData = keyPairByDataSync.pubKey //公钥
let priKeyPairByData = keyPairByDataSync.priKey //私钥
this.priKey = priKeyPairByData
this.pubKey = pubKeyPairByData

二进制数据生成字符串密钥对【异步】

rsaGenKeyPairByDataPem(this.pkData, this.skData).then((keyPairPem) => {
  let pubKeyPem = keyPairPem.pubKey //公钥
  let priKeyPem = keyPairPem.priKey //私钥
  console.log("===公钥:" + pubKeyPem)
  console.log("===私钥:" + priKeyPem)
})

二进制数据生成字符串密钥对【同步】

let keyPairByDataPemSync = rsaGenKeyPairByDataPemSync(this.pkData, this.skData)
let pubKeyPairByDataPem = keyPairByDataPemSync.pubKey //公钥
let priKeyPairByDataPem = keyPairByDataPemSync.priKey //私钥
console.log("===公钥:" + pubKeyPairByDataPem)
console.log("===私钥:" + priKeyPairByDataPem)

字符串数据生成KeyPair密钥对【异步】

rsaGenKeyPairString(this.appRsaPublicKey, this.appRsaPrivateKey).then((keyPair) => {
  let pubKey = keyPair.pubKey
  let priKey = keyPair.priKey
  this.priKey = priKey
  this.pubKey = pubKey
})

字符串数据生成KeyPair密钥对【同步】

let keyPair2 = rsaGenKeyPairStringSync(this.publicPkcs1Str1024, this.priKeyPkcs1Str1024)
let pubKey3 = keyPair2.pubKey
let priKey3 = keyPair2.priKey
this.priKey = priKey3
this.pubKey = pubKey3

字符串数据生成字符串密钥对【异步】

rsaGenKeyPairStringPem(this.appRsaPublicKey, this.appRsaPrivateKey).then((keyPair) => {
          let pubKeyPem = keyPair.pubKey //公钥
          let priKeyPem = keyPair.priKey //私钥
          console.log("===公钥:" + pubKeyPem)
          console.log("===私钥:" + priKeyPem)
        })

字符串数据生成字符串密钥对【同步】

let keyPairStringPemSync = rsaGenKeyPairStringPemSync(this.publicPkcs1Str1024, this.priKeyPkcs1Str1024)
        let pubKeyPairStringPemSync = keyPairStringPemSync.pubKey //公钥
        let priKeyPairStringPemSync = keyPairStringPemSync.priKey //私钥
        console.log("===公钥:" + pubKeyPairStringPemSync)
        console.log("===私钥:" + priKeyPairStringPemSync)

字符串密钥方式加密【异步】

let message = "我是一段要加密的数据"
        console.log("===加密前数据:" + message)
        rsaEncryptString(message, this.publicKey).then((data) => {
          this.encryptString = data
          console.log("===加密后数据:" + data)
        }).catch((e: BusinessError) => {
          console.log("===加密错误:" + JSON.stringify(e.message))
        })

字符串密钥方式解密【异步】

//必须有私钥,还有要解密的数据
rsaDecryptString(this.encryptString, this.privateKey).then((data) => {
  console.log("===解密后数据:" + data)
})

字符串密钥方式加密【同步】

let message1 = "我是一段要加密的数据"
console.log("===加密前数据:" + message1)
this.encryptString = rsaEncryptStringSync(message1, this.publicKey)
console.log("===加密后数据:" + this.encryptString)

字符串密钥方式解密【同步】

//必须有私钥,还有要解密的数据
let data = rsaDecryptStringSync(this.encryptString, this.privateKey)
console.log("===解密后数据:" + data)

加密 KeyPair密钥方式【异步】 需要cryptoFramework.PubKey

if (this.pubKey != undefined) {
          let message = "我是一段要加密的数据"
          console.log("===加密前数据:" + message)
          rsaEncryptDataBlob(message, this.pubKey!).then((data) => {
            this.encryptDataBlob = data
            console.log("===加密后数据:" + JSON.stringify(data))
          }).catch((e: BusinessError) => {
            console.log("===加密错误:" + JSON.stringify(e.message))
          })
        }

解密 KeyPair密钥方式【异步】

if (this.priKey != undefined && this.encryptDataBlob != undefined) {
          //必须有私钥,还有要解密的数据
          rsaDecryptDataBlob(this.encryptDataBlob, this.priKey).then((data) => {
            console.log("===解密后数据:" + data)
          })
        }

加密 KeyPair密钥方式【同步】

if (this.pubKey != undefined) {
          let message1 = "我是一段要加密的数据"
          console.log("===加密前数据:" + message1)
          this.encryptDataBlob = rsaEncryptDataBlobSync(message1, this.pubKey!)
          console.log("===加密后数据:" + JSON.stringify(this.encryptDataBlob))
        }

解密 KeyPair密钥方式【同步】

if (this.priKey != undefined && this.encryptDataBlob != undefined) {
          //必须有私钥,还有要解密的数据
          let data = rsaDecryptDataBlobSync(this.encryptDataBlob, this.priKey)
          console.log("===解密后数据:" + data)
        }

私钥签名 同步

let sign = rsaEncryptPriKeyContentSync("123", this.privateKey)
console.log("=======签名:" + sign)

公钥验签 同步

//this.signData为签名内容
  let signResult = rsaDecryptPubKeyContentSync("123",this.signData, this.publicKey)
        console.log("=======验签:" + signResult)

私钥签名 异步

rsaEncryptPriKeyContent("123", this.privateKey).then((sign) => {
  console.log("=======签名:" + sign)
})

公钥验签 异步

//this.signData为签名内容
rsaDecryptPubKeyContent("123",this.signData, this.publicKey).then((signResult) => {
  console.log("=======验签:" + signResult)
})

程序员一鸣
4 声望0 粉丝