DEV Community

Cover image for HarmonyOS Development: Encryption Algorithm Encapsulation
程序员一鸣
程序员一鸣

Posted on

HarmonyOS Development: Encryption Algorithm Encapsulation

Foreword 

this article is based on Api12 

encryption algorithm is a common business in development. For the sake of security, the client and the server transmit data through encryption, which can ensure the confidentiality of data and prevent sensitive data leakage. In Hongmeng system, encryption algorithm is relatively easy to implement. After all, ArkTs is based on TypeScript, so some algorithms are basically common. 

There are many encryption methods, such as symmetric encryption, asymmetric encryption, and Common message digest algorithm MD5,SHA and so on, this article mainly outlines several common algorithms, and simple package after use. 

Message Digest Algorithm 

message digest algorithm, that is, hash algorithm or one-way hash algorithm, through any length of message, Operation to generate fixed-length summary algorithm, Hongmeng is mainly through. Cryptoframe.createmd method to implement each algorithm. 

Currently, the supported algorithms and specifications are as follows: 

summary algorithm types of Support API version
HASH  SHA1  9 + 
HASH  SHA224  9 + 
HASH  SHA256  9 + 
HASH SHA384  9 + 
HASH  SHA512  9 + 
HASH  MD5  9 + 
HASH  SM3  10 + 

take a very simple SHA256 algorithm, other specifications, only need to change the type.

 

let md = cryptoFramework.createMd("SHA256")
Await md. update ({data: new Uint8Array (buffer. rom, 'utf-8'. buffer)})
let mdResult = await md.digest()
Console.info ('===encrypted result: '+mdResult.data)
let sha256Result = this.uint8ArrayToString(mdResult.data)
Console.info ('===converted to string result:'+sha256Result)
let mdLen = md.getMdLength()
Console.info ("===encrypted length:"+mdLen)
Enter fullscreen mode Exit fullscreen mode

For example, MD5:

 

let md = cryptoFramework.createMd("MD5")
Await md. update ({data: new Uint8Array (buffer. rom, 'utf-8'. buffer)})
let mdResult = await md.digest()
Console.info ('===encrypted result: '+mdResult.data)
let sha256Result = this.uint8ArrayToString(mdResult.data)
Console.info ('===converted to string result:'+sha256Result)
let mdLen = md.getMdLength()
Console.info ("===encrypted length:"+mdLen)
Enter fullscreen mode Exit fullscreen mode

as can be seen from the above code, the Api provided by the system is basically concise enough. 

Base64 

in fact, strictly speaking, base64 is not an encryption algorithm, but the corresponding the encoding format is used to represent binary data in the text protocol. By using Base64 encoding, binary data can be converted into printable ACSII characters, that is, Base64 encoding is the process from binary to character, so as to ensure that data is not lost during transmission. 

The encoding and decryption of Base64 are also provided in Hongmeng, which is also very simple to use.

 


  // 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")
  }
Enter fullscreen mode Exit fullscreen mode

AES symmetric encryption 

symmetric encryption has a remarkable feature, that is, the encryptor and The Decryptor use the same key. This method has a faster encryption and decryption speed and is suitable for long-term use of data. However, the process of key transmission is not safe and easy to crack. Key management is also troublesome. Common symmetric encryption includes AES,DES, and AES is the most commonly used.

Symmetric encryption AES provides seven encryption modes: ECB, CBC, OFB, CFB, CTR, GCM, and CCM. Different encryption modes apply different encryption and decryption parameters. 

Grouping Mode key length (bit) fill mode API version
ECB  [128 192 256] 
CBC  [128 192 256] 
CTR  [128 192 256] 
OFB  [128 192 256] 
CFB  [128 192 256] 
GCM  [128 192 256] 
CCM  [128 192 256] 

A simple example of several modes of actual code execution, no matter which way, is to need the secret key and encryption and decryption content, generally we AES development, first to determine the secret key, and then determine the encrypted content and decryption content. 

ECB mode, encryption and decryption


 


  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
Enter fullscreen mode Exit fullscreen mode

GCM mode, encryption and decryption


 

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
};
//The authTag of GCM is obtained from the doFinal result during encryption and filled into the params parameter of the init function during decryption
let gcmParamsSpec: cryptoFramework.GcmParamsSpec = {
iv: ivBlob,
aad: aadBlob,
authTag: tagBlob,
algName: "GcmParamsSpec"
};
return gcmParamsSpec;
}

gcmParams = this.genGcmParamsSpec();

//Encrypt messages
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);
//When encrypting doFinal in gcm mode, pass in empty space, obtain tag data, and update it to the gcmParams object.
this.gcmParams.authTag = await cipher.doFinal(null);
return encryptUpdate;
}

//Decrypt message
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);
//When decrypting doFinal in gcm mode, empty data is passed in. When verifying init, tag data is passed in. If verification fails, an exception will be thrown.
let decryptData = await decoder.doFinal(null);
if (decryptData == null) {
console.info('GCM decrypt success, decryptData is null');
}
return decryptUpdate;
}
Enter fullscreen mode Exit fullscreen mode

CCM mode, encryption and decryption


 

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's authTag is obtained from the doFinal result during encryption and filled into the params parameter of the init function during decryption
let ccmParamsSpec: cryptoFramework.CcmParamsSpec = {
iv: ivBlob,
aad: aadBlob,
authTag: tagBlob,
algName: "CcmParamsSpec"
};
return ccmParamsSpec;
}

ccmParams = this.genCcmParamsSpec();

//Encrypt messages
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);
//When encrypting doFinal in CCM mode, pass in empty space, obtain tag data, and update it to the ccmParams object.
this.ccmParams.authTag = await cipher.doFinal(null);
return encryptUpdate;
}

//Decrypt message
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;
}
Enter fullscreen mode Exit fullscreen mode

in actual development, we can generate our secret key according to the provided string or other specific characters, generally in the form of a string key after Base64 encoding, and then decode it when encrypting and decrypting. 

RSA asymmetric encryption 

the difference between asymmetric encryption and symmetric encryption is that it has two secret keys, a public key and a private key. The public key is used for encryption and the private key is used for decryption. Compared with symmetric encryption, the security factor is on a higher level, but there is also the risk of man-in-the-middle attack. Common asymmetric encryption includes RSA,DSA,ECC, etc. Generally, the most commonly used is RSA. 

RSA also provides a variety of encryption methods, such as PKCS1 mode PKCS1_OAEP mode, and NoPadding. 

PKCS1 mode


  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;
  }
Enter fullscreen mode Exit fullscreen mode

Other modes, no longer examples, you can go to the official website to check. 

Encapsulation Use 

you can use the above methods to encrypt and decrypt the data. Of course, you can also package it yourself or use someone else's package. For the above, I also simply packaged it, and friends who need it can use it. 

Simple Feature List 

Image description

quick Use 

method 1: in the Terminal window, run the following command to install the third-party package. DevEco Studio automatically adds the third-party package dependency to the project oh-package.json5. 

Suggestion: Execute the command under the module path used.


ohpm install @abner/security
Enter fullscreen mode Exit fullscreen mode

Method 2: Set the three-party package dependency in the project oh-package.json5. The configuration example is as follows:

 

"dependencies": { "@abner/security": "^1.0.0"}
Enter fullscreen mode Exit fullscreen mode

code Use 

1, MD5 

synchronization

 

Let encryptContent=md5EncryptSync ("encrypted data")
Console.log ("===encrypted:"+encryptContent)
Enter fullscreen mode Exit fullscreen mode

asynchronous

 

Md5Encrypt ("encrypted data"). then ((content)=>{
Console.log ("===encrypted:"+content)
})
Enter fullscreen mode Exit fullscreen mode

2, BASE64 

code synchronization

 

Let encryptContent=base64EncodeSync ("I am test data")
this.mBase64EncodeString = encryptContent
Console.log ("===encoded:"+encryptContent)
Enter fullscreen mode Exit fullscreen mode

coding asynchronous

 

Base64Encode ("I am test data"). then ((encryptContent)=>{
this.mBase64EncodeString = encryptContent
Console.log ("===encoded:"+encryptContent)
})
Enter fullscreen mode Exit fullscreen mode

decode synchronization

 

base64Decode(this.mBase64EncodeString).then((decode) => {
Console.log ("===decoded:"+decode)
})
Enter fullscreen mode Exit fullscreen mode

3, SHA 

the default sha is SHA256, which can be modified as needed. Just pass in the second parameter. 

Synchronization

 

let encryptContent = shaEncryptSync("1")
Enter fullscreen mode Exit fullscreen mode

asynchronous

 

shaEncrypt("1").then((content) => {

})
Enter fullscreen mode Exit fullscreen mode

modify the algName

 

let encryptContent = shaEncryptSync("1","SHA256")
Enter fullscreen mode Exit fullscreen mode

4. SM3 

synchronization

 

Let encryptContent=sM3EncryptSync ("encrypted data")
Console.log ("===encrypted:"+encryptContent)
Enter fullscreen mode Exit fullscreen mode

asynchronous

SM3Encrypt ("encrypted data"). then ((content)=>{
Console.log ("===encrypted:"+content)
})
Enter fullscreen mode Exit fullscreen mode

5, AES 

randomly generate SymKey [asynchronous]]

 

aesGenerateSymKey().then((symKey) => {
this.mSymKey = symKey
Console.log (===Key:+symKey)
})
Enter fullscreen mode Exit fullscreen mode

randomly generate SymKey key [synchronization]]

 

let symKey = aesGenerateSymKeySync()
this.mSymKey = symKey
Console.log (===Key:+symKey)
Enter fullscreen mode Exit fullscreen mode

string Generation Key [Asynchronous]]

 

aesGenerateSymKey("1234").then((symKey) => {
  this.mSymKey = symKey

})
Enter fullscreen mode Exit fullscreen mode

string Generation Key [Sync]]

 

let symKeyString = aesGenerateSymKeySync("1234")
this.mSymKey = symKeyString
Enter fullscreen mode Exit fullscreen mode

encrypted data [asynchronous] [ECB mode]]

 

aesEncryptString("123", this.mSymKey).then((result) => {
  this.encryptString = result

})
Enter fullscreen mode Exit fullscreen mode

decryption data [asynchronous] [ECB mode]]

 

aesDecryptString(this.encryptString, this.mSymKey).then((result) => {

})
Enter fullscreen mode Exit fullscreen mode

encrypted data [synchronization] [ECB mode]]

 

let result = aesEncryptStringSync("123", this.mSymKey)
this.encryptString = result
Enter fullscreen mode Exit fullscreen mode

decryption data [synchronization] [ECB mode]]

 

let decryptString = aesDecryptStringSync(this.encryptString!, this.mSymKey!)
Enter fullscreen mode Exit fullscreen mode

6. RSA 

randomly generate KeyPair [asynchronous]]

 

rsaGenerateAsyKey().then((keyPair) => {
  let pubKey = keyPair.pubKey 
  let priKey = keyPair.priKey 
  this.priKey = priKey
  this.pubKey = pubKey
})
Enter fullscreen mode Exit fullscreen mode

randomly generate KeyPair [synchronization]]

 

let keyPair = rsaGenerateAsyKeySync()
let pubKey1 = keyPair.pubKey 
let priKey1 = keyPair.priKey 
this.priKey = priKey1
this.pubKey = pubKey1
Enter fullscreen mode Exit fullscreen mode

randomly Generate String Key Pair [Asynchronous]]

 

rsaGenerateAsyKeyPem().then((keyPairPem) => {
  let pubKey = keyPairPem.pubKey 
  let priKey = keyPairPem.priKey 
})
Enter fullscreen mode Exit fullscreen mode

randomly Generate String Key Pair [Synchronization]]

 

let keyPairPem = generateAsyKeyPemSync()
let pubKeyPem = keyPairPem.pubKey 
let priKeyPem = keyPairPem.priKey
Enter fullscreen mode Exit fullscreen mode

randomly generated key pair binary [asynchronous]]

 

rsaGenerateAsyKeyDataBlob().then((dataBlobArray) => {
  let pubKey: cryptoFramework.DataBlob = dataBlobArray[0]
  let priKey: cryptoFramework.DataBlob = dataBlobArray[1]

})
Enter fullscreen mode Exit fullscreen mode

randomly Generated Binary Key Pair [Synchronization]]

 

let dataBlobArray = rsaGenerateAsyKeyDataBlobSync()
let pubKey: cryptoFramework.DataBlob = dataBlobArray[0]
let priKey: cryptoFramework.DataBlob = dataBlobArray[1]
Enter fullscreen mode Exit fullscreen mode

generate KeyPair key pair by specifying binary data [asynchronous]]

 

rsaGenKeyPairByData(this.pkData, this.skData).then((keyPair) => {
  let pubKey = keyPair.pubKey 
  let priKey = keyPair.priKey 
  this.priKey = priKey
  this.pubKey = pubKey
})
Enter fullscreen mode Exit fullscreen mode

generate KeyPair key pair by specifying binary data [synchronization]]

 

let keyPairByDataSync = rsaGenKeyPairByDataSync(this.pkData, this.skData)
let pubKeyPairByData = keyPairByDataSync.pubKey 
let priKeyPairByData = keyPairByDataSync.priKey 
this.priKey = priKeyPairByData
this.pubKey = pubKeyPairByData
Enter fullscreen mode Exit fullscreen mode

generating String Key Pairs from Binary Data [Asynchronous]]

 

rsaGenKeyPairByDataPem(this.pkData, this.skData).then((keyPairPem) => {
  let pubKeyPem = keyPairPem.pubKey 
  let priKeyPem = keyPairPem.priKey 
})
Enter fullscreen mode Exit fullscreen mode

generate String Key Pair from Binary Data [Synchronization]]

 

let keyPairByDataPemSync = rsaGenKeyPairByDataPemSync(this.pkData, this.skData)
let pubKeyPairByDataPem = keyPairByDataPemSync.pubKey 
let priKeyPairByDataPem = keyPairByDataPemSync.priKey 
Enter fullscreen mode Exit fullscreen mode

string data generation KeyPair [asynchronous]]

 

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

string data generation KeyPair [synchronization]]

 

let keyPair2 = rsaGenKeyPairStringSync(this.publicPkcs1Str1024, this.priKeyPkcs1Str1024)
let pubKey3 = keyPair2.pubKey
let priKey3 = keyPair2.priKey
this.priKey = priKey3
this.pubKey = pubKey3
Enter fullscreen mode Exit fullscreen mode

string data generation string key pair [asynchronous]]

rsaGenKeyPairStringPem(this.appRsaPublicKey, this.appRsaPrivateKey).then((keyPair) => {
          let pubKeyPem = keyPair.pubKey
          let priKeyPem = keyPair.priKey 
        })
Enter fullscreen mode Exit fullscreen mode

String data generation string key pair [synchronization]]

 

let keyPairStringPemSync = rsaGenKeyPairStringPemSync(this.publicPkcs1Str1024, this.priKeyPkcs1Str1024)
        let pubKeyPairStringPemSync = keyPairStringPemSync.pubKey 
        let priKeyPairStringPemSync = keyPairStringPemSync.priKey 
Enter fullscreen mode Exit fullscreen mode

string key encryption [asynchronous]]

 

Let message="I am a piece of data that needs to be encrypted"
Console.log ("===Data before encryption:"+message)
rsaEncryptString(message, this.publicKey).then((data) => {
this.encryptString = data
Console.log ("===encrypted data:"+data)
}).catch((e: BusinessError) => {
Console.log ("===Encryption Error:"+JSON. stringify (e.message))
})
Enter fullscreen mode Exit fullscreen mode

string Key Mode Decryption [Asynchronous]]

 

//There must be a private key and the data to be decrypted
rsaDecryptString(this.encryptString, this.privateKey).then((data) => {
Console.log ("==decrypted data:"+data)
})
Enter fullscreen mode Exit fullscreen mode

string key encryption [synchronization]]

 

Let message1="I am a piece of data that needs to be encrypted"
Console.log ("===Data before encryption:"+message1)
this.encryptString = rsaEncryptStringSync(message1, this.publicKey)
Console.log ("===encrypted data:"+this. encryptString)
Enter fullscreen mode Exit fullscreen mode

string Key Mode Decryption [Synchronization]]

 

//There must be a private key and the data to be decrypted
let data = rsaDecryptStringSync(this.encryptString, this.privateKey)
Console.log ("==decrypted data:"+data)
Enter fullscreen mode Exit fullscreen mode

encryption KeyPair key method [asynchronous] requires cryptoFramework.PubKey

 

if (this.pubKey != undefined) {
Let message="I am a piece of data that needs to be encrypted"
Console.log ("===Data before encryption:"+message)
rsaEncryptDataBlob(message, this.pubKey!).then((data) => {
this.encryptDataBlob = data
Console.log ("===encrypted data:"+JSON. stringify (data))
}).catch((e: BusinessError) => {
Console.log ("===Encryption Error:"+JSON. stringify (e.message))
})
}
Enter fullscreen mode Exit fullscreen mode

decrypt KeyPair key method [asynchronous]]

 

if (this.priKey != undefined && this.encryptDataBlob != undefined) {
//There must be a private key and the data to be decrypted
rsaDecryptDataBlob(this.encryptDataBlob, this.priKey).then((data) => {
Console.log ("==decrypted data:"+data)
})
}
Enter fullscreen mode Exit fullscreen mode

encryption KeyPair key mode [synchronization]]

 

if (this.pubKey != undefined) {
Let message1="I am a piece of data that needs to be encrypted"
Console.log ("===Data before encryption:"+message1)
this.encryptDataBlob = rsaEncryptDataBlobSync(message1, this.pubKey!)
Console.log ("===encrypted data:"+JSON. stringify (this. encryptDataBlob))
}
Enter fullscreen mode Exit fullscreen mode

decrypt KeyPair key mode [synchronization]]

 

if (this.priKey != undefined && this.encryptDataBlob != undefined) {
//There must be a private key and the data to be decrypted
let data = rsaDecryptDataBlobSync(this.encryptDataBlob, this.priKey)
Console.log ("==decrypted data:"+data)
}
Enter fullscreen mode Exit fullscreen mode

private key signature synchronization

 

let sign = rsaEncryptPriKeyContentSync("123", this.privateKey)
Console.log ("======Signature:"+sign)
Enter fullscreen mode Exit fullscreen mode

public Key Signature Verification Synchronization

 

//This. signData is the signature content
let signResult = rsaDecryptPubKeyContentSync("123",this.signData, this.publicKey)
Console.log ("=====signature verification:"+signResult)
Enter fullscreen mode Exit fullscreen mode

private key signing asynchronous

 

rsaEncryptPriKeyContent("123", this.privateKey).then((sign) => {
Console.log ("======Signature:"+sign)
})
Enter fullscreen mode Exit fullscreen mode

public Key Signature Verification Asynchronous

rsaEncryptPriKeyContent("123", this.privateKey).then((sign) => {
Console.log ("======Signature:"+sign)
})
Enter fullscreen mode Exit fullscreen mode

Top comments (0)