如何在Android项目中使用Curve25519椭圆曲线加密方法?
Android实现Curve25519密钥生成与文件加密方案
Curve25519属于椭圆曲线密钥协商算法,Android没有像iOS CryptoKit那样的专用封装类,但可以通过以下两种方式实现需求:
一、Android 10+ 原生API实现
从Android 10(API 29)开始,系统原生支持Curve25519密钥生成与协商,使用KeyGenerator和KeyAgreement类即可完成:
1. 生成Curve25519密钥对
import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties import java.security.KeyPairGenerator import java.security.KeyStore import java.security.spec.ECGenParameterSpec import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey import java.security.interfaces.ECPublicKey // 生成Curve25519密钥对(存储在系统密钥库,安全性更高) fun generateCurve25519KeyPair(alias: String): KeyPair? { val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } if (!keyStore.containsAlias(alias)) { val keyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore" ) val spec = KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_KEY_AGREEMENT ) .setAlgorithmParameterSpec(ECGenParameterSpec("Curve25519")) .setUserAuthenticationRequired(false) // 根据业务需求设置是否需要用户验证 .build() keyPairGenerator.initialize(spec) return keyPairGenerator.generateKeyPair() } return (keyStore.getKey(alias, null) as? PrivateKey)?.let { KeyPair(keyStore.getCertificate(alias).publicKey, it) } } // 导出公钥原始数据(对应iOS的rawRepresentation) fun getPublicKeyRawData(publicKey: PublicKey): ByteArray { // Curve25519公钥为32字节,直接提取X坐标原始数据 val ecPublicKey = publicKey as ECPublicKey return ecPublicKey.w.affineX.toByteArray().copyOfRange(1, 33) // 去除ASN.1前缀,保留32字节有效数据 }
2. 密钥协商与文件加密
Curve25519仅用于生成共享密钥,实际加密文件需要结合对称加密算法(如AES-GCM):
import javax.crypto.KeyAgreement import javax.crypto.SecretKey import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.SecretKeySpec import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.security.MessageDigest import java.security.SecureRandom // 协商生成共享密钥 fun generateSharedKey(privateKey: PrivateKey, peerPublicKey: PublicKey): SecretKey { val keyAgreement = KeyAgreement.getInstance("ECDH") keyAgreement.init(privateKey) keyAgreement.doPhase(peerPublicKey, true) // 从协商结果派生AES密钥(通过SHA-256哈希截断为32字节) val sharedSecret = keyAgreement.generateSecret() val hash = MessageDigest.getInstance("SHA-256").digest(sharedSecret) return SecretKeySpec(hash.copyOf(32), "AES") } // AES-GCM加密文件 fun encryptFile(secretKey: SecretKey, inputFile: File, outputFile: File) { val cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") val iv = ByteArray(12) // GCM推荐使用12字节IV SecureRandom().nextBytes(iv) cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKey, GCMParameterSpec(128, iv)) FileInputStream(inputFile).use { fis -> FileOutputStream(outputFile).use { fos -> // 先写入IV,解密时需要读取该数据 fos.write(iv) val buffer = ByteArray(8192) var bytesRead: Int while (fis.read(buffer).also { bytesRead = it } != -1) { val encryptedBytes = cipher.update(buffer, 0, bytesRead) fos.write(encryptedBytes) } val finalBytes = cipher.doFinal() fos.write(finalBytes) } } }
二、兼容低版本Android(BouncyCastle库)
如果需要支持Android 10以下设备,可引入BouncyCastle作为加密提供商:
1. 引入依赖(build.gradle)
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
2. 生成Curve25519密钥对与协商
import org.bouncycastle.crypto.generators.X25519KeyPairGenerator import org.bouncycastle.crypto.params.X25519PrivateKeyParameters import org.bouncycastle.crypto.params.X25519PublicKeyParameters import org.bouncycastle.jce.provider.BouncyCastleProvider import java.security.Security // 初始化BouncyCastle提供商 init { Security.addProvider(BouncyCastleProvider()) } // 生成Curve25519密钥对 fun generateX25519KeyPair(): Pair<ByteArray, ByteArray> { val generator = X25519KeyPairGenerator() generator.init(null) // 使用默认随机源 val keyPair = generator.generateKeyPair() val privateKeyBytes = (keyPair.private as X25519PrivateKeyParameters).encoded val publicKeyBytes = (keyPair.public as X25519PublicKeyParameters).encoded return Pair(privateKeyBytes, publicKeyBytes) } // 协商生成共享密钥 fun generateSharedKey(privateKeyBytes: ByteArray, peerPublicKeyBytes: ByteArray): ByteArray { val privateKey = X25519PrivateKeyParameters(privateKeyBytes, 0) val peerPublicKey = X25519PublicKeyParameters(peerPublicKeyBytes, 0) val sharedSecret = ByteArray(32) privateKey.generateSecret(peerPublicKey, sharedSecret, 0) return sharedSecret }
后续文件加密逻辑与原生API方案一致,使用共享密钥派生AES密钥后执行加密操作即可。
内容的提问来源于stack exchange,提问作者JuJu Juned
相关产品推荐
相关产品推荐

