HarmonyOS Next非对称密钥加解密算法深度剖析
本文旨在深入探讨华为鸿蒙HarmonyOS Next系统(截止目前API12)中非对称密钥加解密算法的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。
在当今数字化的浪潮中,数据的安全性和完整性成为了至关重要的考量因素。HarmonyOS Next系统中的非对称密钥加解密算法在保障数据安全方面扮演着举足轻重的角色,特别是在判断数据来源及确保数据完整性方面,为我们的数字世界筑牢了一道坚固的防线。
一、非对称密钥加解密基础
非对称密钥加解密,简单来说,就是使用公钥和私钥这一对密钥进行加密和解密操作。公钥可以公开,任何人都可以使用它来加密数据,但只有持有对应私钥的人才能解密这些数据。这种机制在HarmonyOS Next中有广泛的应用场景。
在判断数据来源方面,当我们收到一份加密数据时,如果能够使用已知的公钥成功解密,那么我们就可以确信这份数据是由持有对应私钥的一方发送的。这就好比你有一把特制的锁(公钥),只有拥有对应钥匙(私钥)的人才能将东西锁在里面(加密),而你可以用这把锁来验证东西是不是那个人放进去的(解密)。在实际应用中,比如在设备与服务器之间的通信中,服务器可以将自己的公钥发送给设备,设备使用公钥对数据进行加密后发送给服务器,服务器再用私钥解密,这样就能确保数据是来自于合法的设备。
在确保数据完整性方面,非对称密钥加解密算法结合数字签名技术,可以防止数据在传输过程中被篡改。发送方使用私钥对数据的摘要(一种数据的特征值)进行签名,接收方收到数据后,使用发送方的公钥对签名进行验证,如果验证成功,说明数据在传输过程中没有被篡改。这就像是给数据加上了一个独一无二的“指纹”,只要“指纹”没有被破坏,数据就是完整的。
二、RSA算法核心
(一)填充模式特点与使用规则
RSA算法是一种非常重要的非对称加密算法,在HarmonyOS Next中提供了多种填充模式,每种模式都有其独特的特点和使用规则。
- PKCS1填充模式
- 特点:这是一种较为常用的填充模式,对应于RFC3447规范中的RSAES - PKCS1 - V1_5模式。在进行加密时,它会将源数据转化为Encryption block(EB),并且对输入数据的长度有一定要求,即输入的数据最大长度 <= RSA钥模 - 11。
- 使用规则:当我们使用PKCS1填充模式进行RSA运算时,需要先将源数据按照规定的格式进行转换。例如,在加密一个文件时,要确保文件内容的长度符合要求,然后使用私钥进行加密,加密后的密文长度与RSA钥模一样长。在解密时,使用公钥进行解密操作,同样会得到与原始数据长度相关的结果。 - PKCS1_OAEP填充模式
- 特点:此模式需要设置两个摘要(md和mgf1_md),提供了更高的安全性。它对应于RFC3447规范中的RSAES - OAEP模式。在加密时,输入的数据必须小于RSA钥模 - md摘要长度 - mgf1_md摘要长度 - 2(摘要长度以字节为单位)。
- 使用规则:假设我们要加密一份重要的合同文档,首先要选择合适的摘要算法(如SHA256),然后根据算法计算出摘要长度,确保文档内容长度满足上述要求。在创建Cipher实例时,需要指定填充模式为PKCS1_OAEP,并传入摘要和掩码摘要等参数。加密后的密文长度同样与RSA钥模一致。解密时,需要使用相同的参数进行初始化,然后对密文进行解密操作。 - OnlySign模式
- 特点:RSA签名不做摘要仅签名功能。对待签名数据有特定的长度要求,并且根据填充模式和是否设置摘要算法而有所不同。
- 使用规则:如果使用PKCS1填充模式且不设置摘要算法(NoHash),数据需要小于RSA密钥长度 - 11;若设置了摘要算法,则待签名的数据必须是对应的摘要数据。例如,在对一个小型配置文件进行签名时,如果采用PKCS1填充模式且设置了SHA256摘要算法,那么要先计算文件的SHA256摘要值,然后将其作为待签名数据进行签名操作。 - Recover模式
- 特点:提供签名恢复原始数据功能。使用时需要与签名时的参数保持一致,特别是填充模式和摘要算法。
- 使用规则:在对已签名的数据进行恢复操作时,首先要确保使用的公钥与签名时的私钥相对应,并且在创建Verify实例时,要使用与签名时相同的填充模式和摘要算法。例如,在验证一个已签名的消息并尝试恢复原始数据时,要按照签名时的参数设置进行初始化,然后进行恢复操作。
(二)代码示例展示
- PKCS1填充模式下的签名验签示例
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer } from '@kit.ArkTS';
// 生成RSA密钥对
async function generateRSAKeyPair() {
let keyGenAlg = "RSA1024";
let generator = cryptoFramework.createAsyKeyGenerator(keyGenAlg);
return await generator.generateKeyPair();
}
// 使用PKCS1填充模式进行签名
async function signMessagePKCS1(priKey, plainText) {
let signAlg = "RSA1024|PKCS1|SHA256";
let signer = cryptoFramework.createSign(signAlg);
await signer.init(priKey);
await signer.update(plainText);
return await signer.sign(null);
}
// 使用PKCS1填充模式进行验签
async function verifyMessagePKCS1(pubKey, cipherText, signData) {
let verifyAlg = "RSA1024|PKCS1|SHA256";
let verifier = cryptoFramework.createVerify(verifyAlg);
await verifier.init(pubKey);
await verifier.update(cipherText);
return await verifier.verify(signData);
}
async function main() {
try {
// 生成密钥对
let keyPair = await generateRSAKeyPair();
// 要签名的消息
let message = "This is a test";
let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
// 签名
let signData = await signMessagePKCS1(keyPair.priKey, plainText);
// 验签
let result = await verifyMessagePKCS1(keyPair.pubKey, plainText, signData);
if (result) {
console.info('verify success');
} else {
console.error('verify failed');
}
} catch (error) {
console.error(`RSA PKCS1 “${error}“, error code: ${error.code}`);
}
}
main();
在上述代码中,首先使用generateRSAKeyPair
函数生成了一个1024位的RSA密钥对。然后,在签名过程中,使用私钥和指定的PKCS1填充模式及SHA256摘要算法对消息进行签名。在验签时,使用公钥和相同的参数对签名和消息进行验证。
2. PKCS1_OAEP填充模式下的加密解密示例
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer } from '@kit.ArkTS';
// 生成RSA密钥对
async function generateRSAKeyPair() {
let keyGenAlg = "RSA2048";
let generator = cryptoFramework.createAsyKeyGenerator(keyGenAlg);
return await generator.generateKeyPair();
}
// 使用PKCS1_OAEP填充模式进行加密
async function encryptMessagePKCS1_OAEP(pubKey, plainText) {
let cipher = cryptoFramework.createCipher('RSA2048|PKCS1_OAEP|SHA256|MGF1_SHA256');
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null);
return await cipher.doFinal(plainText);
}
// 使用PKCS1_OAEP填充模式进行解密
async function decryptMessagePKCS1_OAEP(priKey, cipherText) {
let decoder = cryptoFramework.createCipher('RSA2048|PKCS1_OAEP|SHA256|MGF1_SHA256');
await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, priKey, null);
return await decoder.doFinal(cipherText);
}
async function main() {
try {
// 生成密钥对
let keyPair = await generateRSAKeyPair();
// 要加密的消息
let message = "This is a test";
let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
// 加密
let encryptText = await encryptMessagePKCS1_OAEP(keyPair.pubKey, plainText);
// 解密
let decryptText = await decryptMessagePKCS1_OAEP(keyPair.priKey, encryptText);
if (plainText.data.toString() === decryptText.data.toString()) {
console.info('decrypt ok');
console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8'));
} else {
console.error('decrypt failed');
}
} catch (error) {
console.error(`RSA PKCS1_OAEP “${error}“, error code: ${error.code}`);
}
}
main();
此代码展示了在PKCS1_OAEP填充模式下,使用RSA2048密钥对进行加密和解密的过程。在加密时,创建Cipher实例并指定填充模式、摘要算法和掩码摘要,使用公钥进行初始化后对消息进行加密。解密时则使用私钥进行初始化,对密文进行解密操作。
三、其他非对称算法
(一)基本原理与特点
- ECDSA算法
- 基本原理:ECDSA(Elliptic Curve Digital Signature Algorithm,椭圆曲线数字签名算法)是基于椭圆曲线密码(ECC)的数字签名算法。它利用椭圆曲线上的点运算来实现签名和验签操作。相比于传统的基于离散对数问题的算法(如RSA),椭圆曲线密码在相同的安全强度下,所需的密钥长度更短,计算效率更高。
- 特点:ECDSA算法具有较高的安全性和计算效率,适用于资源受限的环境,如移动设备或物联网设备。它在数字签名方面表现出色,能够有效地验证数据的来源和完整性。例如,在移动支付应用中,使用ECDSA算法对交易数据进行签名,可以确保交易的真实性和不可抵赖性。 - DSA算法
- 基本原理:DSA(Digital Signature Algorithm,数字签名算法)的安全性基于整数有限域离散对数问题的困难性。它通过生成公钥和私钥对,利用私钥对数据进行签名,公钥用于验签。
- 特点:DSA算法具有较好的兼容性和适用性,在一些特定的安全标准和协议中被广泛应用。然而,其计算效率相对较低,密钥长度较长,在资源受限的设备上可能会表现出性能瓶颈。例如,在一些传统的企业级安全系统中,可能会使用DSA算法来满足特定的安全需求。 - SM2算法
- 基本原理:SM2算法是我国自主设计的基于椭圆曲线的签名验签算法。它在椭圆曲线密码体制的基础上,进行了优化和改进,以适应国内的安全需求。
- 特点:SM2算法具有自主可控的优势,在国内的政务、金融等对安全性要求较高的领域得到广泛应用。它支持多种功能,如加密、签名、密钥交换等,并且在性能和安全性方面表现出色。例如,在电子政务系统中,使用SM2算法对公文进行签名和加密,保障公文的机密性、完整性和不可抵赖性。 - Ed25519算法
- 基本原理:Ed25519是基于椭圆曲线的签名验签算法,它采用了特定的椭圆曲线和签名方案,具有较高的安全性和计算效率。
- 特点:Ed25519算法以其简洁、高效和安全的特点而受到关注。它在签名验证速度方面表现优异,适用于对性能要求较高的场景,如高速网络通信中的数据签名验证。例如,在一些实时性要求较高的物联网应用中,Ed25519算法可以快速地对传感器数据进行签名和验证,确保数据的可靠性。
(二)与RSA算法的差异及优势场景
- 密钥长度与安全性
- ECDSA算法:与RSA算法相比,ECDSA算法在相同安全强度下所需的密钥长度更短。例如,使用256位的ECDSA密钥可以提供与3072位RSA密钥相当的安全级别。这使得ECDSA在资源受限的设备(如物联网设备)中具有明显优势,因为较短的密钥长度意味着更少的计算资源消耗和存储需求,同时能够保持较高的安全性。
- DSA算法:DSA算法的密钥长度通常也较长,相比RSA算法,其在计算效率上相对较低。然而,在某些特定的安全标准和协议中,DSA算法因其历史原因和兼容性需求而被采用。但在现代应用中,随着对计算效率和安全性平衡的追求,RSA算法在一些场景下可能更具优势,除非有特定的兼容性要求。
- SM2算法:作为国产算法,SM2在设计上针对国内的安全需求进行了优化。与RSA算法相比,它在自主可控方面具有绝对优势,适用于对国家安全和信息安全有严格要求的领域,如政务、金融等。在相同安全等级下,SM2算法的密钥长度和计算复杂度也有其自身特点,能够在保证安全性的同时,兼顾一定的计算效率。
- Ed25519算法:Ed25519算法以其高效的签名验证速度脱颖而出。与RSA算法相比,它在签名和验签操作上的计算开销更小,尤其适用于对性能要求极高的场景,如大规模物联网设备的数据签名验证或实时性要求很高的通信系统中,能够快速处理大量的签名验证请求,提高系统的整体性能。 - 计算效率
- ECDSA算法:在计算效率方面,ECDSA算法的签名和验签操作相对较快,特别是在椭圆曲线密码运算优化较好的情况下。例如,在移动设备上进行频繁的数字签名操作时,ECDSA算法能够更快地完成任务,减少用户等待时间,提高应用的响应速度。
- DSA算法:DSA算法的计算效率相对较低,其签名和验签过程涉及较为复杂的数学运算,导致在处理大量数据或高频率签名验签操作时可能会出现性能瓶颈。相比之下,RSA算法在一些场景下可能具有更高的计算效率,尤其是在硬件加速支持较好的环境中。
- SM2算法:SM2算法在计算效率上进行了优化,能够在保证安全性的前提下,提供较为高效的加解密和签名验签操作。在国内的实际应用中,它在政务和金融领域的大规模数据处理场景中表现良好,能够满足这些领域对数据安全和处理效率的双重要求。
- Ed25519算法:Ed25519算法以其卓越的计算效率著称,其签名验证速度比许多其他算法都要快。这使得它在对性能要求极高的场景中具有明显优势,如高速网络通信中的实时数据签名验证,能够快速处理大量的数据流量,确保系统的高效运行。 - 应用场景适应性
- ECDSA算法:由于其高效性和安全性,ECDSA算法广泛应用于资源受限的环境,如移动支付、物联网设备之间的安全通信等场景。在移动支付中,它可以确保交易的安全性和快速性,同时保护用户的隐私信息。在物联网设备中,能够在有限的计算资源下实现可靠的身份认证和数据签名。
- DSA算法:虽然计算效率相对较低,但在一些传统的安全系统和特定的安全协议中仍有应用。例如,在一些早期建立的企业级安全架构中,由于历史原因和兼容性考虑,可能会继续使用DSA算法进行数字签名操作。
- SM2算法:凭借自主可控的特性,SM2算法在国内的政务、金融等关键领域得到了广泛应用。在电子政务系统中,用于保障公文的安全传输、存储和处理;在金融领域,确保网上银行交易、电子合同签署等业务的安全性和合法性。
- Ed25519算法:适用于对性能要求极高的场景,如实时通信系统、大规模分布式系统中的数据签名验证。在实时通信中,能够快速验证消息的来源和完整性,保证通信的实时性和可靠性;在分布式系统中,可以高效地处理大量节点之间的数据交互和认证需求。
(三)示例代码展示
- ECDSA算法签名验签示例
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer } from '@kit.ArkTS';
// 生成ECDSA密钥对(以ECC256为例)
async function generateECDSAKeyPair() {
let keyGenAlg = "ECC256";
let generator = cryptoFramework.createAsyKeyGenerator(keyGenAlg);
return await generator.generateKeyPair();
}
// 使用ECDSA算法进行签名
async function signMessageECDSA(priKey, plainText) {
let signAlg = "ECC256|SHA256";
let signer = cryptoFramework.createSign(signAlg);
await signer.init(priKey);
await signer.update(plainText);
return await signer.sign(null);
}
// 使用ECDSA算法进行验签
async function verifyMessageECDSA(pubKey, cipherText, signData) {
let verifyAlg = "ECC256|SHA256";
let verifier = cryptoFramework.createVerify(verifyAlg);
await verifier.init(pubKey);
await verifier.update(cipherText);
return await verifier.verify(signData);
}
async function main() {
try {
// 生成密钥对
let keyPair = await generateECDSAKeyPair();
// 要签名的消息
let message = "This is a test";
let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
// 签名
let signData = await signMessageECDSA(keyPair.priKey, plainText);
// 验签
let result = await verifyMessageECDSA(keyPair.pubKey, plainText, signData);
if (result) {
console.info('verify success');
} else {
console.error('verify failed');
}
} catch (error) {
console.error(`ECDSA “${error}“, error code: ${error.code}`);
}
}
main();
在这个示例中,首先生成了ECC256的ECDSA密钥对,然后使用私钥对消息进行签名,最后使用公钥对签名进行验证。
2. SM2算法签名验签示例(假设当前环境支持SM2算法相关操作)
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer } from '@kit.ArkTS';
// 生成SM2密钥对
async function generateSM2KeyPair() {
let keyGenAlg = "SM2_256";
let generator = cryptoFramework.createAsyKeyGenerator(keyGenAlg);
return await generator.generateKeyPair();
}
// 使用SM2算法进行签名(当前仅支持SM3摘要)
async function signMessageSM2(priKey, plainText) {
let signAlg = "SM2_256|SM3";
let signer = cryptoFramework.createSign(signAlg);
await signer.init(priKey);
await signer.update(plainText);
return await signer.sign(null);
}
// 使用SM2算法进行验签
async function verifyMessageSM2(pubKey, cipherText, signData) {
let verifyAlg = "SM2_256|SM3";
let verifier = cryptoFramework.createVerify(verifyAlg);
await verifier.init(pubKey);
await verifier.update(cipherText);
return await verifier.verify(signData);
}
async function main() {
try {
// 生成密钥对
let keyPair = await generateSM2KeyPair();
// 要签名的消息
let message = "This is a test";
let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
// 签名
let signData = await signMessageSM2(keyPair.priKey, plainText);
// 验签
let result = await verifyMessageSM2(keyPair.pubKey, plainText, signData);
if (result) {
console.info('verify success');
} else {
console.error('verify failed');
}
} catch (error) {
console.error(`SM2 “${error}“, error code: ${error.code}`);
}
}
main();
此示例展示了在HarmonyOS Next中使用SM2算法进行签名验签的基本流程,注意当前SM2签名仅支持SM3摘要。
通过对HarmonyOS Next中的非对称密钥加解密算法,尤其是RSA算法的深入剖析以及对其他算法(ECDSA、DSA、SM2、Ed25519)的介绍,我们可以根据不同的应用场景和需求,选择最合适的算法来保障数据的安全性、完整性和来源可靠性。在实际开发中,充分理解这些算法的特点、差异和使用规则,能够帮助我们构建更加安全、高效的应用系统,为用户提供优质的数字体验,同时也为数字世界的安全稳定贡献力量。