1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import cryptoFramework from '@ohos.security.cryptoFramework'; 17import promptAction from '@ohos.promptAction'; 18import Logger from '../util/Logger'; 19 20const TAG: string = '[Crypto_Framework]'; 21const BASE_16: number = 16; 22const SLICE_NUMBER: number = -2; 23 24// 字节流以16进制字符串输出 25function uint8ArrayToShowStr(uint8Array: Uint8Array): string { 26 let ret: string = Array.prototype.map 27 .call(uint8Array, (x) => ('00' + x.toString(BASE_16)).slice(SLICE_NUMBER)).join(''); 28 return ret; 29} 30 31// 16进制字符串转字节流 32function fromHexString(hexString: string): Uint8Array { 33 let ret: Uint8Array = new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, BASE_16))); 34 return ret; 35} 36 37 38// 字节流转字符串 39function arrayBufferToString(buffer: ArrayBuffer): string { 40 let ret: string = String.fromCharCode.apply(null, new Uint8Array(buffer)); 41 return ret; 42} 43 44// 可理解的字符串转成字节流 45function stringToUint8Array(str: string): Uint8Array { 46 let arr = []; 47 for (let i = 0, j = str.length; i < j; ++i) { 48 arr.push(str.charCodeAt(i)); 49 } 50 let ret: Uint8Array = new Uint8Array(arr); 51 return ret; 52} 53 54function genGcmParamsSpec(): cryptoFramework.GcmParamsSpec { 55 let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 bytes 56 let dataIv = new Uint8Array(arr); 57 let ivBlob = { data: dataIv }; 58 59 arr = [0, 0, 0, 0, 0, 0, 0, 0]; // 8 bytes 60 let dataAad = new Uint8Array(arr); 61 let aadBlob = { data: dataAad }; 62 63 arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes 64 let dataTag = new Uint8Array(arr); 65 let tagBlob = { data: dataTag }; // GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中 66 67 let gcmParamsSpec = { iv: ivBlob, aad: aadBlob, authTag: tagBlob, algName: 'GcmParamsSpec' }; 68 return gcmParamsSpec; 69} 70 71export class CryptoOperation { 72 async generateAesKey(): Promise<string> { 73 let symKeyGenerator; 74 let encodedKey; 75 // 创建对称密钥生成器 76 try { 77 symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256'); 78 } catch (error) { 79 Logger.error(TAG, 'create generator failed'); 80 return null; 81 } 82 83 // 通过密钥生成器随机生成对称密钥 84 try { 85 let symKey = await symKeyGenerator.generateSymKey(); 86 // 获取对称密钥的二进制数据,输出长度为256bit的字节流 87 encodedKey = symKey.getEncoded(); 88 let data: Uint8Array = encodedKey.data; 89 Logger.info('success, key bytes: ' + data); 90 Logger.info('success, key hex:' + uint8ArrayToShowStr(data)); 91 // 将二进制数据转为16进制string。 92 return uint8ArrayToShowStr(data); 93 } catch (error) { 94 Logger.error(TAG, 'create symKey failed'); 95 return null; 96 } 97 } 98 99 async convertAesKey(aesKeyBlobString: string): Promise<cryptoFramework.SymKey> { 100 let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256'); 101 Logger.info(TAG, 'success, read key string' + aesKeyBlobString); 102 Logger.info(TAG, 'success, blob key ' + fromHexString(aesKeyBlobString)); 103 let symKeyBlob = { data: fromHexString(aesKeyBlobString) }; 104 try { 105 let key = await symKeyGenerator.convertKey(symKeyBlob); 106 let aesKey: cryptoFramework.SymKey = key; 107 return aesKey; 108 } catch (error) { 109 Logger.error(TAG, `convert aes key failed, ${error.code}, ${error.message}`); 110 return null; 111 } 112 } 113 114 async aesGcmEncrypt(globalKey, textString: string): Promise<string> { 115 let cipherAlgName = 'AES256|GCM|PKCS7'; 116 let cipher; 117 let cipherText: string; 118 let globalGcmParams = genGcmParamsSpec(); 119 let aesEncryptJsonStr = null; 120 try { 121 cipher = cryptoFramework.createCipher(cipherAlgName); 122 Logger.info(TAG, `cipher algName: ${cipher.algName}`); 123 } catch (error) { 124 Logger.error(TAG, `createCipher failed, ${error.code}, ${error.message}`); 125 return aesEncryptJsonStr; 126 } 127 let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE; 128 try { 129 await cipher.init(mode, globalKey, globalGcmParams); 130 } catch (error) { 131 Logger.error(TAG, `init cipher failed, ${error.code}, ${error.message}`); 132 return aesEncryptJsonStr; 133 } 134 let plainText = { data: stringToUint8Array(textString) }; 135 Logger.info(TAG, `plain text: ${plainText.data}`); 136 try { 137 let cipherTextBlob = await cipher.update(plainText); 138 let tmpArr: Uint8Array = cipherTextBlob.data; 139 cipherText = uint8ArrayToShowStr(tmpArr); 140 Logger.info(TAG, `cipher text: ${cipherText}`); 141 } catch (error) { 142 Logger.error(TAG, `update cipher failed, ${error.code}, ${error.message}`); 143 return aesEncryptJsonStr; 144 } 145 try { 146 let authTag = await cipher.doFinal(null); 147 let tmoTagArr: Uint8Array = authTag.data; 148 let aesEncryptJson = ({ aesGcmTag: uint8ArrayToShowStr(tmoTagArr), encryptedText: cipherText }); 149 aesEncryptJsonStr = JSON.stringify(aesEncryptJson); 150 Logger.info(TAG, `success, authTag blob ${authTag.data}`); 151 Logger.info(TAG, `success, authTag blob.length = ${authTag.data.length}`); 152 return aesEncryptJsonStr; 153 } catch (error) { 154 Logger.error(TAG, `doFinal cipher failed, ${error.code}, ${error.message}`); 155 return aesEncryptJsonStr; 156 } 157 } 158 159 async aesGcmDecrypt(globalKey, aesEncryptJsonStr: string): Promise<string> { 160 let cipherAlgName = 'AES256|GCM|PKCS7'; 161 let decode; 162 let plainTextBlob; 163 let plainText: string; 164 let aesEncryptJson; 165 try { 166 aesEncryptJson = JSON.parse(aesEncryptJsonStr); 167 } catch (error) { 168 Logger.error(TAG, `trans from json string failed, ${error.code}, ${error.message}`); 169 return null; 170 } 171 let authTagStr: string = aesEncryptJson.aesGcmTag; 172 let textString: string = aesEncryptJson.encryptedText; 173 let globalGcmParams = genGcmParamsSpec(); 174 globalGcmParams.authTag = { data: fromHexString(authTagStr) }; 175 Logger.info(TAG, 'success, decrypt authTag string' + authTagStr); 176 Logger.info(TAG, 'success, decrypt authTag blob' + globalGcmParams.authTag.data); 177 Logger.info(TAG, 'success, decrypt authTag blob.length = ' + globalGcmParams.authTag.data.length); 178 try { 179 decode = cryptoFramework.createCipher(cipherAlgName); 180 } catch (error) { 181 Logger.error(TAG, `createCipher failed, ${error.code}, ${error.message}`); 182 return null; 183 } 184 let mode = cryptoFramework.CryptoMode.DECRYPT_MODE; 185 try { 186 await decode.init(mode, globalKey, globalGcmParams); 187 } catch (error) { 188 Logger.error(TAG, `init decode failed, ${error.code}, ${error.message}`); 189 return null; 190 } 191 let cipherText = { data: fromHexString(textString) }; 192 Logger.info(TAG, `success, cipher text: ${cipherText.data}`); 193 try { 194 plainTextBlob = await decode.update(cipherText); 195 let tmpArr: Uint8Array = plainTextBlob.data; 196 plainText = arrayBufferToString(tmpArr); 197 Logger.info(TAG, `success, plain text: ${plainText}`); 198 } catch (error) { 199 Logger.error(TAG, `update decode failed, ${error.code}, ${error.message}`); 200 return null; 201 } 202 try { 203 let finalOut = await decode.doFinal(null); 204 } catch (error) { 205 Logger.error(TAG, `doFinal decode failed, ${error.code}, ${error.message}`); 206 return null; 207 } 208 return plainText; 209 } 210 211 async aesConvertAndEncrypt(aesKeyBlobString: string, textString: string): Promise<string> { 212 let aesEncryptJsonStr = ''; 213 try { 214 let key = await this.convertAesKey(aesKeyBlobString); 215 try { 216 aesEncryptJsonStr = await this.aesGcmEncrypt(key, textString); 217 } catch (error) { 218 Logger.error(TAG, `encrypt error, ${error.code}, ${error.message}`); 219 } 220 } catch (error) { 221 Logger.error(TAG, `convert key error, ${error.code}, ${error.message}`); 222 return null; 223 } 224 return aesEncryptJsonStr; 225 } 226 227 async aesConvertAndDecrypt(aesKeyBlobString: string, textString: string): Promise<string> { 228 let plainText = ''; 229 try { 230 let key = await this.convertAesKey(aesKeyBlobString); 231 try { 232 plainText = await this.aesGcmDecrypt(key, textString); 233 } catch (error) { 234 Logger.error(TAG, `encrypt error, ${error.code}, ${error.message}`); 235 } 236 } catch (error) { 237 Logger.error(TAG, `convert key error, ${error.code}, ${error.message}`); 238 return null; 239 } 240 return plainText; 241 } 242 243 async generateRsaKey(): Promise<string> { 244 // 创建非对称密钥生成器 245 let rsaKeyGenerator; 246 let jsonStr; 247 // 创建对称密钥生成器 248 try { 249 rsaKeyGenerator = cryptoFramework.createAsyKeyGenerator('RSA3072'); 250 } catch (error) { 251 Logger.error(TAG, 'create generator failed'); 252 return null; 253 } 254 // 通过密钥生成器随机生成非对称密钥 255 try { 256 // 通过密钥生成器随机生成非对称密钥 257 let keyPair = await rsaKeyGenerator.generateKeyPair(); 258 // 获取非对称密钥的二进制数据 259 let encodedPriKey = keyPair.priKey.getEncoded(); 260 let priKeyData: Uint8Array = encodedPriKey.data; 261 let encodedPubKey = keyPair.pubKey.getEncoded(); 262 let pubKeyData: Uint8Array = encodedPubKey.data; 263 let rsaKeyJson = ({ priKey: uint8ArrayToShowStr(priKeyData), pubKey: uint8ArrayToShowStr(pubKeyData) }); 264 jsonStr = JSON.stringify(rsaKeyJson); 265 Logger.info(TAG, 'success, key string: ' + jsonStr.length); 266 return jsonStr; 267 } catch (error) { 268 Logger.error(TAG, 'create symKey failed'); 269 return null; 270 } 271 } 272 273 async convertRsaKey(rsaJsonString: string): Promise<cryptoFramework.KeyPair> { 274 let rsaKeyGenerator = cryptoFramework.createAsyKeyGenerator('RSA3072'); 275 Logger.info(TAG, 'success, read key string' + rsaJsonString.length); 276 let jsonRsaKeyBlob; 277 try { 278 jsonRsaKeyBlob = JSON.parse(rsaJsonString); 279 } catch (error) { 280 Logger.error(TAG, `trans from json string failed, ${error.code}, ${error.message}`); 281 return null; 282 } 283 let priKeyStr: string = jsonRsaKeyBlob.priKey; 284 let pubKeyStr: string = jsonRsaKeyBlob.pubKey; 285 Logger.info(TAG, 'success, read rsa pri str ' + priKeyStr.length); 286 Logger.info(TAG, 'success, read rsa pub str ' + pubKeyStr.length); 287 let priKeyBlob = fromHexString(priKeyStr); 288 let pubKeyBlob = fromHexString(pubKeyStr); 289 Logger.info(TAG, 'success, read rsa pri blob key ' + priKeyBlob.length); 290 Logger.info(TAG, 'success, read rsa pub blob key ' + pubKeyBlob.length); 291 try { 292 let key: cryptoFramework.KeyPair = await rsaKeyGenerator.convertKey({ data: pubKeyBlob }, { data: priKeyBlob }); 293 return key; 294 Logger.info(TAG, 'success, read and convert key'); 295 } catch (error) { 296 Logger.error(TAG, `convert rsa key failed, ${error.code}, ${error.message}`); 297 return null; 298 } 299 } 300 301 async rsaSign(globalKey, textString: string): Promise<string> { 302 let signer = cryptoFramework.createSign('RSA3072|PKCS1|SHA256'); 303 let keyPair = globalKey; 304 try { 305 await signer.init(keyPair.priKey); 306 let signBlob = stringToUint8Array(textString); 307 try { 308 let signedBlob = await signer.sign({ data: signBlob }); 309 let tmpArr: Uint8Array = signedBlob.data; 310 Logger.info(TAG, 'success,RSA sign output is' + signedBlob.data.length); 311 let rsaSignedBlobString = uint8ArrayToShowStr(tmpArr); 312 Logger.info(TAG, 'success,RSA sign string is' + rsaSignedBlobString); 313 return rsaSignedBlobString; 314 } catch (error1) { 315 Logger.error(TAG, `sign text failed, ${error1.code}, ${error1.message}`); 316 return null; 317 } 318 } catch (error) { 319 Logger.error(TAG, `sign init failed, ${error.code}, ${error.message}`); 320 return null; 321 } 322 } 323 324 async rsaVerify(globalKey, textString: string, rsaSignedText: string): Promise<Boolean> { 325 let verifyer = cryptoFramework.createVerify('RSA3072|PKCS1|SHA256'); 326 let keyPair = globalKey; 327 let signBlob = stringToUint8Array(textString); 328 let signedBlob = fromHexString(rsaSignedText); 329 Logger.info('success,RSA sign input is ' + signBlob); 330 Logger.info('success,RSA signed file length ' + signedBlob.length); 331 try { 332 await verifyer.init(keyPair.pubKey); 333 try { 334 let result: Boolean = await verifyer.verify({ data: signBlob }, { data: signedBlob }); 335 if (result === false) { 336 // flag = false; 337 Logger.error(TAG, 'RSA Verify result = fail'); 338 } else { 339 Logger.info(TAG, 'success, RSA Verify result = success'); 340 } 341 return result; 342 } catch (error) { 343 Logger.error(TAG, `verify dofinal failed, ${error.code}, ${error.message}`); 344 } 345 } catch (err) { 346 Logger.error(TAG, `verify init failed, ${err.code}, ${err.message}`); 347 } 348 return null; 349 } 350 351 async rsaConvertAndSign(rsaJsonString: string, textString: string): Promise<string> { 352 let rsaSignString; 353 try { 354 let key = await this.convertRsaKey(rsaJsonString); 355 try { 356 rsaSignString = await this.rsaSign(key, textString); 357 } catch (error) { 358 Logger.error(TAG, `sign error, ${error.code}, ${error.message}`); 359 return null; 360 } 361 } catch (error) { 362 Logger.error(TAG, `convert rsa key error, ${error.code}, ${error.message}`); 363 return null; 364 } 365 return rsaSignString; 366 } 367 368 async rsaConvertAndVerify(rsaJsonString: string, textString: string, rsaSignedText: string): Promise<Boolean> { 369 let rsaVerifyRes; 370 try { 371 let key = await this.convertRsaKey(rsaJsonString); 372 try { 373 rsaVerifyRes = await this.rsaVerify(key, textString, rsaSignedText); 374 } catch (error) { 375 Logger.error(TAG, `sign error, ${error.code}, ${error.message}`); 376 return null; 377 } 378 } catch (error) { 379 Logger.error(TAG, `convert rsa key error, ${error.code}, ${error.message}`); 380 return null; 381 } 382 return rsaVerifyRes; 383 } 384} 385 386