RSA加解密开始构建工具类就是举步维艰,官方文档虽然很全,但是还是有很多小瑕疵,在自己经过几天的时间,彻底解决了中文乱码的问题、分段加密的问题。
首先看官方示例代码(以RSA非对称加解密(多次调用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;
}// 字节流转成可理解的字符串
function uint8ArrayToString(array) {let arrayString = '';for (let i = 0; i < array.length; i++) {arrayString += String.fromCharCode(array[i]);}return arrayString;
}function encryptLongMessagePromise() {let globalPlainText = "This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!";let globalCipherOutput;let globalDecodeOutput;var globalKeyPair;let plainTextSplitLen = 64; // RSA每次加解密允许的原文长度大小与密钥位数和填充模式等有关,详细规格内容见overview文档let cipherTextSplitLen = 128; // RSA密钥每次加密生成的密文数据长度计算方式:密钥位数/8let keyGenName = "RSA1024";let cipherAlgName = "RSA1024|PKCS1";let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName); // 创建非对称密钥生成器对象let cipher = cryptoFramework.createCipher(cipherAlgName); // 创建加密Cipher对象let decoder = cryptoFramework.createCipher(cipherAlgName); // 创建解密Decoder对象return new Promise((resolve, reject) => {setTimeout(() => {resolve("testRsaMultiDoFinal");}, 10);}).then(() => {return asyKeyGenerator.generateKeyPair(); // 生成rsa密钥}).then(keyPair => {globalKeyPair = keyPair; // 保存到密钥对全局变量return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, globalKeyPair.pubKey, null);}).then(async () => {globalCipherOutput = [];// 将原文按64字符进行拆分,循环调用doFinal进行加密,使用1024bit密钥时,每次加密生成128B长度的密文for (let i = 0; i < (globalPlainText.length / plainTextSplitLen); i++) {let tempStr = globalPlainText.substr(i * plainTextSplitLen, plainTextSplitLen);let tempBlob = { data : stringToUint8Array(tempStr) };let tempCipherOutput = await cipher.doFinal(tempBlob);globalCipherOutput = globalCipherOutput.concat(Array.from(tempCipherOutput.data));}console.info(`globalCipherOutput len is ${globalCipherOutput.length}, data is: ${globalCipherOutput.toString()}`);return;}).then(() =>{return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, globalKeyPair.priKey, null);}).then(async() => {globalDecodeOutput = [];// 将密文按128B进行拆分解密,得到原文后进行拼接for (let i = 0; i < (globalCipherOutput.length / cipherTextSplitLen); i++) {let tempBlobData = globalCipherOutput.slice(i * cipherTextSplitLen, (i + 1) * cipherTextSplitLen);let message = new Uint8Array(tempBlobData);let tempBlob = { data : message };let tempDecodeOutput = await decoder.doFinal(tempBlob);globalDecodeOutput += uint8ArrayToString(tempDecodeOutput.data);}if (globalDecodeOutput === globalPlainText) {console.info(`encode and decode success`);} else {console.info(`encode and decode error`);}return;}).catch(error => {console.error(`catch error, ${error.code}, ${error.message}`);})
}
let plainTextSplitLen = 64; // RSA每次加解密允许的原文长度大小与密钥位数和填充模式等有关,详细规格内容见overview文档
注意点:在解密中,这句代码就是产生中文乱码的关键。
鸿蒙OS开发 | 更多内容↓点击 | HarmonyOS与OpenHarmony技术 |
---|---|---|
鸿蒙技术文档 | 开发知识更新库gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md在这。 | 或+mau123789学习,是v喔 |
globalDecodeOutput += uint8ArrayToString(tempDecodeOutput.data);
好,加上我的代码
加密:
/*** 测试RSA加密*/
export function textRsaEncryption(value: string) {let keyGenName = "RSA1024";let cipherAlgName = "RSA1024|PKCS1";//64 RSA每次加解密允许的原文长度大小与密钥位数和填充模式等有关,详细规格内容见overview文档let plainTextSplitLen = 117;let globalKeyPair; //密钥对let globalEncryptionOutput; //加密输出let arrTest = StringUtils.string2Uint8Array1(value);//创建非对称密钥生成器对象let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName);// 创建加密Cipher对象let cipherEncryption = cryptoFramework.createCipher(cipherAlgName);return new Promise((resolve, reject) => {setTimeout(() => {resolve("textRsaEncryption");}, 10);}).then(() => {let base64 = Base64.getInstance()let pubKeyBlob = { data: new Uint8Array(base64.decode(publicKey)) }let priKeyBlob = { data: new Uint8Array(base64.decode(privateKey)) }return asyKeyGenerator.convertKey(pubKeyBlob, priKeyBlob);}).then(keyPair => {globalKeyPair = keyPair; // 保存到密钥对全局变量return cipherEncryption.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, globalKeyPair.pubKey, null);}).then(async () => {globalEncryptionOutput = [];// 将原文按64字符进行拆分,循环调用doFinal进行加密,使用1024bit密钥时,每次加密生成128B长度的密文for (let i = 0; i < (arrTest.length / plainTextSplitLen); i++) {let tempArr = arrTest.slice(i * plainTextSplitLen, (i + 1) * plainTextSplitLen);let tempBlob = { data: tempArr };let tempCipherOutput = await cipherEncryption.doFinal(tempBlob);globalEncryptionOutput = globalEncryptionOutput.concat(Array.from(tempCipherOutput.data));}let base64 = Base64.getInstance()let enStr = base64.encode(globalEncryptionOutput)LogUtils.i("加密总长度:" + globalEncryptionOutput.length + "\n生成加密串:\n" + enStr)return enStr}).catch(error => {LogUtils.i(`加密异常, ${error.code}, ${error.message}`);})
}
解密:
/*** 测试RSA解密*/
export function textRsaDecryption(value: string) {let keyGenName = "RSA1024";let cipherAlgName = "RSA1024|PKCS1";// RSA密钥每次加密生成的密文数据长度计算方式:密钥位数/8let cipherTextSplitLen = 128;let globalKeyPair; //密钥对//创建非对称密钥生成器对象let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName);// 创建解密Decoder对象let cipherDecryption = cryptoFramework.createCipher(cipherAlgName);return new Promise((resolve, reject) => {setTimeout(() => {resolve("textRsaEncryption");}, 10);}).then(() => {let base64 = Base64.getInstance()let pubKeyBlob = { data: new Uint8Array(base64.decode(publicKey)) }let priKeyBlob = { data: new Uint8Array(base64.decode(privateKey)) }return asyKeyGenerator.convertKey(pubKeyBlob, priKeyBlob);}).then(keyPair => {globalKeyPair = keyPair; // 保存到密钥对全局变量return cipherDecryption.init(cryptoFramework.CryptoMode.DECRYPT_MODE, globalKeyPair.priKey, null);}).then(async () => {let base64 = Base64.getInstance()let globalCipherOutput1 = new Uint8Array(base64.decode(value))let len = globalCipherOutput1.length//解密输出let globalDecryptionOutput = new Uint8Array(len);let globalOffset = 0// 将密文按128B进行拆分解密,得到原文后进行拼接for (let i = 0; i < (len / cipherTextSplitLen); i++) {let tempBlobData = globalCipherOutput1.subarray(i * cipherTextSplitLen, (i + 1) * cipherTextSplitLen);let message = new Uint8Array(tempBlobData);let tempBlob = { data: message };let tempDecodeOutput = await cipherDecryption.doFinal(tempBlob);//存入数组 解决边累加边转中文时 字节错乱出现乱码globalDecryptionOutput.set(tempDecodeOutput.data, globalOffset)//偏移量globalOffset += tempDecodeOutput.data.byteLength}let result = StringUtils.uint8Array2String(globalDecryptionOutput)LogUtils.i("解密串:cipherAlgName[" + cipherAlgName + "]\n" + result);}).catch(error => {LogUtils.i(`解密异常,cipherAlgName[${cipherAlgName}] ${error.code}, ${error.message}`);})
}
运行代码:
Text("RSA加解密联测").TextNormalStyle().fontSize(16).fontWeight(FontWeight.Normal).fontColor(Color.White).textAlign(TextAlign.Center).margin({ left: 5 }).layoutWeight(1).onClick(() => {let globalPlainText = ""globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "一二三四五六七八九十"globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"globalPlainText += "SDK向DevEco Studio提供全量API,DevEco Studio识别开发者项目中选择的设备形态,找到该设备的支持能力集,筛选支持能力集包含的API并提供API联想"//textRsaEncryption(globalPlainText).then(enStr => {if (enStr) textRsaDecryption(enStr)})})}.width('100%').height(50).margin({ top: 10 }).padding(5)
运行结果:
终于大功告成!!
最后呢,很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。
而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点
如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
高清完整版请点击→《鸿蒙NEXT星河版开发学习文档》
针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。
《鸿蒙 (OpenHarmony)开发学习视频》
《鸿蒙生态应用开发V2.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
-
ArkTS语言
-
安装DevEco Studio
-
运用你的第一个ArkTS应用
-
ArkUI声明式UI开发
-
.……
《鸿蒙开发进阶》
-
Stage模型入门
-
网络管理
-
数据管理
-
电话服务
-
分布式应用开发
-
通知与窗口管理
-
多媒体技术
-
安全技能
-
任务管理
-
WebGL
-
国际化开发
-
应用测试
-
DFX面向未来设计
-
鸿蒙系统移植和裁剪定制
-
……
《鸿蒙开发实战》
-
ArkTS实践
-
UIAbility应用
-
网络案例
-
……
获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》
总结
鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。
并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!