1. 介绍
接上篇“HarmonyOS 对称加密”,本篇将介绍RSA非对称加密,官方也给出了一些样例使用代码,可供开发者参考。
本篇从实践出发,完整的通过代码方式来深入了解HarmonyOS中的非对称加密用法。
2. 基础概念
字符串样例:RSA1024|PKCS1|MD5|MGF1_MD5
- 密钥算法 : RSA
- 密文组长度 : 1024
- 填充模式 : PKCS1
- 摘要: MD5
- 摘要掩码: MGF1_MD5
关于“RSA算法”,“填充模式”, “摘要”, "摘要掩码"的具体概念,可自行搜索。
3. 实践
加密使用的测试数据源有三个,具体见下图
- “92字节” (即,占用了92个字节的字符串)
- “117字节” (即,占用了117个字节的字符串)
- “128字节” (即,占用了128个字节的字符串)
3.1 MMI入口
3.2 RSA加解密
- RSA加密算法密文分组长度有七种:512,718,1024,2048,3072,4096,8192;
- 支持3种填充模式:NoPadding, PKCS1, PKCS1_OAEP;
- 在PCKCS1_OAEP填充模式下,支持六种摘要:MD5, SHA1, SHA224, SHA256, SHA384, SHA512;
- 在PCKCS1_OAEP填充模式下,支持六种摘要掩码:MGF1_MD5, MGF1_SHA1, MGF1_SHA224, MGF1_SHA256, MGF1_SHA384, MGF1_SHA512
本篇仅以1024密文组长度做为实践验证,默认选择“128字节”数据集
片段代码以 “RSA1024|PKCS1_OAEP|MD5|MGF1_MD5” 为例
3.2.1 加密
生成对动态密钥
//导入加密框架
import cryptoFramework from '@ohos.security.cryptoFramework';
......
//创建密钥生成器,参数为(密钥算法+密文组长度+素数,如:RSA1024|PRIMES_2)
let symKeyGenerator = cryptoFramework.createAsyKeyGenerator('RSA1024|PRIMES_2');
//生成对称密钥
let promiseSymKey = symKeyGenerator.generateKeyPair();
//获取密钥
promiseSymKey( key => {
//密钥对
this.keyPair = rsaKeyPair;
})
初始化Cipher
//创建Cipher
globalCipher = cryptoFramework.createCipher('RSA1024|PKCS1_OAEP|MD5|MGF1_MD5');
//使用公钥初始化Cipher
let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
globalCipher.init(mode, this.keyPair.pubKey, null)
加密
//文字转换为Uint8Array
const encoder = new util.TextEncoder()
let u8a_encoder = encoder.encodeInto('测试')
//封装Uint8Array 数据,必须是一个带data属性的对象
let plainText = { data: u8a_encoder };
//开始加密
let promiseUpdate = globalCipher.doFinal(plainText);
//获取加密结果
promiseUpdate( result => {
//密文
let this.cipherText = result.data
})
至此,加密已经结束。
3.2.2 解密
生成密钥对象
//创建密钥生成器,参数为(密钥算法+密文组长度+素数,如:RSA1024|PRIMES_2)
let symKeyGenerator = cryptoFramework.createSymKeyGenerator('RSA1024|PRIMES_2');
//密钥生成器使用密钥数据,开始生成密钥对象
symKeyGenerator.convertKey(this.keyPair.pubKey.getEncoded(), this.keyPair.priKey.getEncoded()).then( key => {
//key 为生成的密钥对象
})
初始化Cipher
//创建Cipher
globalCipher = cryptoFramework.createCipher('RSA1024|PKCS1_OAEP|MD5|MGF1_MD5');
//初始化Cipher,参数keyPair.priKey由第一步生成的
let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
globalCipher.init(mode, keyPair.priKey
, null)
解密
//this.cipherText 代表密文,本篇文章中,此值来源于上述加密结果
globalCipher.doFinal({ data: this.cipherText })
3.2.3 注意点
这些是基于RSA1024场景下,实践出的结论
- NoPadding填充模式下,明文字节长度必须为128个字节长度的整数倍
- PKCS1填充模式下,单次加密(即: 调用一次doFinal)明文字节长度最大为117个字节
- PKCS1_OAEP填充模式下,单词加密(即: 调用一次doFinal)明文字节长度最大为92个字节
- 摘要和摘要掩码只有在PKCS1_OAEP填充模式下,才会出现在初始化Cipher参数中
本篇仅以1024密文组长度做为实践验证,默认选择“128字节”数据集
片段代码以 “RSA1024|PKCS1_OAEP|MD5|MGF1_MD5” 为例
3.2.4 源码
import cryptoFramework from '@ohos.security.cryptoFramework';
import util from '@ohos.util';
import Logger from '../../common/Logger';
import OriginData from './OriginData';
import emitter from "@ohos.events.emitter";
/**
* 非对称密钥
* 密钥算法:RSA
* 密钥规格格式:(密钥算法名称 + 密钥长度) | 素数
* 密钥长度:512,718,1024, 2048, 3072, 4096, 8192
* 密钥规格列表:AES512|PRIMES_2, RSA768|PRIMES_2, RSA1024|PRIMES_2, RSA1024|PRIMES_3, RSA2048|PRIMES_2
* RSA2048|PRIMES_3, RSA3072|PRIMES_2, RSA3072|PRIMES_3, RSA4096|PRIMES_2, RSA4096|PRIMES_3
* RSA4096|PRIMES_4, RSA8192|PRIMES_2, RSA8192|PRIMES_3, RSA8192|PRIMES_4, RSA8192|PRIMES_5
*
* 非对称对称加密
* 加密算法:RSA
* 加密规格格式:密钥算法名称 + 密钥长度 + 填充模式 + [摘要 + 摘要掩码]
* 密钥长度:512,718,1024, 2048, 3072, 4096, 8192
* 填充模式:NoPadding,PKCS1,PKCS1_OAEP
* 摘要: MD5, SHA1, SHA224, SHA256, SHA384, SHA512
* 摘要掩码: MGF1_MD5, MGF1_SHA1, MGF1_SHA224, MGF1_SHA256, MGF1_SHA384, MGF1_SHA512
* 加密规格样例:RSA512|NoPadding,RSA512|PKCS1,RSA512|PKCS1_OAEP|MD5|MGF1_SHA224
*
*
*/
class TestAsyRSAEncryptDecrypt {
private keyPair: cryptoFramework.KeyPair;
private cipherText: Uint8Array;
private algorithmWithLength: string = 'RSA1024'
private paddingMode: string = 'NoPadding' //NoPadding,PKCS5,PKCS1_OAEP
private digest: string = 'MD5' //MD5、SHA1、SHA224、SHA256、SHA384、SHA512
private digestMask: string = 'MGF1_MD5' //MGF1_MD5、MGF1_SHA1、MGF1_SHA224、MGF1_SHA256、MGF1_SHA384、MGF1_SHA512
//对称加密:RSA1024|PKCS1_OAEP|MD5|MGF1_MD5
testAsyRASEncrypt(paddingMode: string, digest: string, digestMask, dataSource:number) {
let globalCipher: cryptoFramework.Cipher
let originData: string
if(dataSource == 92){
originData = OriginData.RSA_1024_CONTENT_92
} else if(dataSource == 117){
originData = OriginData.RSA_1024_CONTENT_117
} else {
originData = OriginData.RSA_1024_CONTENT_128
}
this.paddingMode = paddingMode
this.digest = digest
this.digestMask = digestMask
let symKeyGenerator = cryptoFramework.createAsyKeyGenerator(this.algorithmWithLength+'|PRIMES_2');
let promiseSymKey = symKeyGenerator.generateKeyPair();
promiseSymKey.then( rsaKeyPair => {
this.keyPair = rsaKeyPair;
let p: string = ''
for(let a of rsaKeyPair.priKey.getEncoded().data){
p = p.concat(a+',')
}
Logger.d('原始私钥',p)
let spec = ''
if(this.paddingMode == 'PKCS1_OAEP'){
spec = this.algorithmWithLength + '|' + this.paddingMode + '|' + this.digest + '|' + this.digestMask
} else {
spec = this.algorithmWithLength + '|' + this.paddingMode
}
console.log('加密规格:', spec)
globalCipher = cryptoFramework.createCipher(spec);
let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
return globalCipher.init(mode, this.keyPair.pubKey, null);
}).then(() => {
const encoder = new util.TextEncoder()
let u8a_encoder = encoder.encodeInto(originData)
Logger.d('开始加密')
let plainText = { data: u8a_encoder };
let promiseUpdate = globalCipher.doFinal(plainText);
return promiseUpdate;
}).then(updateOutput => {
if(updateOutput != null && updateOutput.data != null){
this.cipherText = updateOutput.data
console.log('密文:', this.cipherText)
}
}).then(() => {
this.testSymAESDecrypt()
return
}).catch( error => {
console.error(`catch error, ${error.code}, ${error.message}`);
this.notificationStatus('加密中-error', error.code + '-' + error.message)
})
}
//非对称解密: RSA1024|PKCS1_OAEP|MD5|MGF1_MD5
testSymAESDecrypt() {
let globalCipher: cryptoFramework.Cipher
let symKeyGenerator = cryptoFramework.createAsyKeyGenerator(this.algorithmWithLength);
// 根据指定的二进制密钥数据,生成对称密钥对象
symKeyGenerator.convertKey(this.keyPair.pubKey.getEncoded(), this.keyPair.priKey.getEncoded())
.then( keyPair => {
console.log('解密-初始化Cipher')
let spec = ''
if(this.paddingMode == 'PKCS1_OAEP'){
spec = this.algorithmWithLength + '|' + this.paddingMode + '|' + this.digest + '|' + this.digestMask
} else {
spec = this.algorithmWithLength + '|' + this.paddingMode
}
globalCipher = cryptoFramework.createCipher(spec);
let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
let p: string = ''
for(let a of keyPair.priKey.getEncoded().data){
p = p.concat(a+',')
}
Logger.d('解密私钥',p)
globalCipher.init(mode, keyPair.priKey, null);
return
})
.then(() => {
console.log('开始解密', '密文')
return globalCipher.doFinal({ data: this.cipherText });
})
.then( updateOutput => {
let textDecoder = util.TextDecoder.create()
let key = textDecoder.decodeWithStream(updateOutput.data);
Logger.d('解密完成1: ', key);
this.notificationStatus('解密完成', key)
})
.catch(error => {
console.error(`catch error, ${error.code}, ${error.message}`);
this.notificationStatus('解密中-error', error.code + '-' + error.message)
})
}
notificationStatus(status:string, result: string){
// 定义一个eventId为1的事件,事件优先级为Low
let event = {
eventId: 202404063287,
priority: emitter.EventPriority.HIGH
};
let eventData = {
data: {
"content": result,
'status': status,
}
};
// 发送eventId为1的事件,事件内容为eventData
emitter.emit(event, eventData);
}
}
export default new TestAsyRSAEncryptDecrypt();
3.4 实践结果
以1024长度分组,“92字节”,“117字节”, “128字节”作为数据源
数据集
//117字节,PKCS1 M最大
public static readonly RSA_1024_CONTENT_117: string =
"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567"
//92字节,PKCS1_OAEP 最大
public static readonly RSA_1024_CONTENT_92: string =
"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012"
//128字节,RSA|NoPadding 固定
public static readonly RSA_1024_CONTENT_128: string =
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ "1234567890123456789012345678"
组合实验结果
- NoPadding填充模式下,使用“128字节”数据源, ✅
- PKCS1填充模式下,使用“117字节”数据源 ,✅
- PKCS1_OAEP填充模式下,使用“92字节”数据源 ,组合所有摘要和摘要掩码,✅
最后呢,很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。
而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点
如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
高清完整版请点击→《鸿蒙NEXT星河版开发学习文档》
针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。
《鸿蒙 (OpenHarmony)开发学习视频》
《鸿蒙生态应用开发V2.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
《鸿蒙开发基础》
《鸿蒙开发进阶》
《鸿蒙开发实战》
获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》
总结
鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。
并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!