• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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