使用 BouncyCastle 验证 Android KeyStore 签名的负载
Use BouncyCastle to verify Android KeyStore signed payload
我正在尝试使用来自 Android 的 KeyStore API 对数据进行签名,并使用 BouncyCastle 和 C# 验证服务器中的数据。
我的验证过程是这样的:
- 在 android
上生成密钥对
- 发送 public 密钥到服务器
- 在服务器上生成挑战
- 使用私钥
在android上签署挑战
- 使用 public 密钥验证服务器上的签名质询
我无法使验证正常工作。我怎样才能使验证成功?是否存在重大逻辑错误?
这是我现在使用的代码:
使用 KeyPairGenerator
:
生成密钥对
val generator: KeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore")
val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder("KEY_ALIAS",
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
)
.setDigests(KeyProperties.DIGEST_SHA256)
.setKeySize(2048)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
.build()
generator.initialize(parameterSpec)
generator.generateKeyPair()
获取发送到服务器的public密钥:
val publicKeyBytes = keyStore.getCertificate("KEY_ALIAS").publicKey.encoded
val publicKey = Base64.encodeToString(publicKeyBytes, Base64.DEFAULT)
服务器然后生成一个挑战负载,该负载必须由 android 应用验证。签名是这样完成的:
val challengeBytes = Base64.decode(challenge, Base64.DEFAULT)
val entry = keyStore.getEntry("KEY_ALIAS", null) as KeyStore.PrivateKeyEntry
val signature = Signature.getInstance("SHA256withRSA/PSS")
signature.initSign(entry.privateKey)
signature.update(challengeBytes)
val signedBytes = signature.sign()
val signedChallenge = Base64.encodeToString(signedBytes, Base64.NO_WRAP)
然后将此 signedChallenge
发送到服务器,服务器将使用 C# 中的 BouncyCastle 对其进行验证:
byte[] challengeBytes = // Original challenge
byte[] signedBytes = Convert.FromBase64String(signedChallenge);
ISigner signer = SignerUtilities
.GetSigner(
SignerUtilities
.GetObjectIdentifier("SHA256withRSA/PSS"));
var pKeyParams = (RsaKeyParameters) PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
signer.Init(false, pKeyParams);
signer.BlockUpdate(challengeBytes, 0, challengeBytes.Length);
isVerified = signer.VerifySignature(signedBytes);
设置
Android:SDK 23+
服务器是使用 NuGet 包 Portable.BouncyCastle 版本 1.8.10
用 C# 编写的
问题出在 C# 代码中 ISigner
的实例化。
为了让它工作,我必须让签名者像这样:
ISigner signer = SignerUtilities.GetSigner("SHA256withRSA/PSS");
我正在尝试使用来自 Android 的 KeyStore API 对数据进行签名,并使用 BouncyCastle 和 C# 验证服务器中的数据。
我的验证过程是这样的:
- 在 android 上生成密钥对
- 发送 public 密钥到服务器
- 在服务器上生成挑战
- 使用私钥 在android上签署挑战
- 使用 public 密钥验证服务器上的签名质询
我无法使验证正常工作。我怎样才能使验证成功?是否存在重大逻辑错误?
这是我现在使用的代码:
使用 KeyPairGenerator
:
val generator: KeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore")
val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder("KEY_ALIAS",
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
)
.setDigests(KeyProperties.DIGEST_SHA256)
.setKeySize(2048)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
.build()
generator.initialize(parameterSpec)
generator.generateKeyPair()
获取发送到服务器的public密钥:
val publicKeyBytes = keyStore.getCertificate("KEY_ALIAS").publicKey.encoded
val publicKey = Base64.encodeToString(publicKeyBytes, Base64.DEFAULT)
服务器然后生成一个挑战负载,该负载必须由 android 应用验证。签名是这样完成的:
val challengeBytes = Base64.decode(challenge, Base64.DEFAULT)
val entry = keyStore.getEntry("KEY_ALIAS", null) as KeyStore.PrivateKeyEntry
val signature = Signature.getInstance("SHA256withRSA/PSS")
signature.initSign(entry.privateKey)
signature.update(challengeBytes)
val signedBytes = signature.sign()
val signedChallenge = Base64.encodeToString(signedBytes, Base64.NO_WRAP)
然后将此 signedChallenge
发送到服务器,服务器将使用 C# 中的 BouncyCastle 对其进行验证:
byte[] challengeBytes = // Original challenge
byte[] signedBytes = Convert.FromBase64String(signedChallenge);
ISigner signer = SignerUtilities
.GetSigner(
SignerUtilities
.GetObjectIdentifier("SHA256withRSA/PSS"));
var pKeyParams = (RsaKeyParameters) PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
signer.Init(false, pKeyParams);
signer.BlockUpdate(challengeBytes, 0, challengeBytes.Length);
isVerified = signer.VerifySignature(signedBytes);
设置
Android:SDK 23+ 服务器是使用 NuGet 包 Portable.BouncyCastle 版本 1.8.10
用 C# 编写的问题出在 C# 代码中 ISigner
的实例化。
为了让它工作,我必须让签名者像这样:
ISigner signer = SignerUtilities.GetSigner("SHA256withRSA/PSS");