You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 11:05:22