我正在尝试与Android和Nodejs建立一个加密通信桥梁。在这两种情况下,它都可以使用私钥和公钥生成密钥对。仅当生成共享密钥时,我才会收到错误消息,并显示以下消息“解析公钥时出错”。
我会一步步解释:
第1步:在Android(Kotlin)中生成密钥对
private fun generateKeyPair(): KeyPair {
val keyPairGenerator = KeyPairGenerator.getInstance("EC")
keyPairGenerator.initialize(ECGenParameterSpec("secp256r1"))
return keyPairGenerator.generateKeyPair()
}
val pk = generateKeyPair()
val publicKey = Base64.getEncoder().encodeToString(pk.public.encoded)
//Send "publicKey" to NodeJS Server
第2步:生成密钥对+在NodeJS中生成共享密钥
const publicKey = post.publicKey; //get public key of android device
const keyPair = crypto.createECDH('prime256v1');
keyPair.generateKeys();
// Define the EC public key schema
const ECPublicKey = asn1.define('ECPublicKey', function() {
this.seq().obj(
this.key('algorithm').seq().obj(
this.key('id').objid(),
this.key('curve').objid()
),
this.key('pub').bitstr()
);
});
fun getAESKey(sharedSecret: ByteArray): ByteArray {
val digest = MessageDigest.getInstance("SHA-512")
return digest.digest(sharedSecret).copyOfRange(0, 32)
}
const publicKeyDer = Buffer.from(publicKey, 'base64');
const publicKeyParsed = ECPublicKey.decode(publicKeyDer, 'der');
const publicKeyBuffer = Buffer.from(publicKeyParsed.pub.data, 'base64');
const sharedSecret = keyPair.computeSecret(publicKeyBuffer);
console.log("This is the sharedSecret:",sharedSecret.toString('base64'))
const pubKeyBase = keyPair.getPublicKey().toString('base64')
//reply the value of "pubKeyBase" to android device
第 3 步:在 Android 中生成共享密钥
val publicKeyB: String = "PUBLICKEY-OF-NODEJS"
val decKey: ByteArray = Base64.getDecoder().decode(publicKeyB)
val keyFactory = KeyFactory.getInstance("EC")
val genPublicKey = keyFactory.generatePublic(X509EncodedKeySpec(decKey)) //Error: java.security.spec.InvalidKeySpecException
val sharedSecret = getSharedSecret(pk.private, genPublicKey)
val aesKey = getAESKey(sharedSecret)
在第 3 行中: keyFactory.generatePublic(X509EncodedKeySpec(decKey)) 这是我收到错误的地方:
java.security.spec.InvalidKeySpecException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing public key
我查了一下,但似乎我使用了错误的EncodesKeySPec? 我哪里出错了?
X509EncodedKeySpec()
需要 X.509/SPKI 格式的 DER 编码密钥。相比之下,NodeJS 代码中的 keyPair.getPublicKey()
是未压缩格式的公钥。
未压缩格式的公钥可以使用例如 X.509/SPKI 格式转换为 PEM 编码密钥eckey-utils 包和
generatePem()
函数。
然后,通过删除页眉、页脚和换行符并对其余部分进行 Base64 解码,可以轻松将 PEM 编码密钥转换为 DER 编码密钥。或者,可以使用
createPublicKey()
和 export()
与加密模块进行转换。
示例代码:
const crypto = require('crypto')
const ecKeyUtils = require('eckey-utils');
// create key pair
const keyPair = crypto.createECDH('prime256v1')
keyPair.generateKeys()
// get public key
const publicKey = keyPair.getPublicKey()
// export as hex encoded uncompressed key (0x04 + <x> + <y>)
console.log(publicKey.toString('hex'))
// export as PEM encoded key in X.509/SPKI format: -----BEGIN PUBLIC KEY-----...
var x509Pem = ecKeyUtils.generatePem({curveName: 'prime256v1', publicKey: publicKey}).publicKey // PEM encoded
console.log(x509Pem)
// export as Base64 encoded DER encoded key in X.509/SPKI format (X509EncodedKeySpec() requires the DER encoded key in X.509/SPKI format)
var x509Der = crypto.createPublicKey(x509Pem).export({type: 'spki', format: 'der'}) // DER encoded
var x509DerB64 = x509Der.toString('base64') // Base64 encoded DER encoded
console.log(x509DerB64)
Kotlin 端的导入成功:
...
val x509DerB64 = "MFkwEw..."
val decKey = Base64.getDecoder().decode(x509DerB64)
val keyFactory = KeyFactory.getInstance("EC")
val genPublicKey = keyFactory.generatePublic(X509EncodedKeySpec(decKey))
...