如何使用公钥验证 ECDSA?
Posted
技术标签:
【中文标题】如何使用公钥验证 ECDSA?【英文标题】:How to verify ECDSA with Public Key? 【发布时间】:2019-05-20 09:07:30 【问题描述】:我有以下方法来生成密钥和签署密码消息。
public void generateKeys()
try
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
if (!keyStore.containsAlias(KEY_NAME))
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, KEYSTORE_NAME);
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
// Require the user to authenticate with a fingerprint to authorize
// every use of the private key
.setUserAuthenticationRequired(true)
.build());
keyPairGenerator.generateKeyPair();
loadKeys();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (NoSuchProviderException e)
e.printStackTrace();
catch (InvalidAlgorithmParameterException e)
e.printStackTrace();
catch (CertificateException e)
e.printStackTrace();
catch (KeyStoreException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
public BiometricPrompt.CryptoObject getCryptoObject()
cryptoObject = new BiometricPrompt.CryptoObject(signature);
return cryptoObject;
private void loadKeys()
try
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
if (keyStore.containsAlias(KEY_NAME))
publicKey = keyStore.getCertificate(KEY_NAME).getPublicKey();
privateKey = (PrivateKey) keyStore.getKey(KEY_NAME, null);
signature = Signature.getInstance(Constants.SIGNATURE);
signature.initSign(privateKey);
catch (IOException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (CertificateException e)
e.printStackTrace();
catch (KeyStoreException e)
e.printStackTrace();
catch (UnrecoverableKeyException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
public String sign(String inputStr)
try
Signature signature = cryptoObject.getSignature();
signature.update(inputStr.getBytes());
byte[] signedBytes = signature.sign();
String result = HexManager.bytesToHex(signedBytes);
Log.d("TAG", result);
return result;
catch (SignatureException e)
e.printStackTrace();
return null;
之后,我将签名密码保存在共享首选项中。稍后,我想用指纹验证的新密码验证保存的密码。
这是我的验证方法:
public boolean verify(String inputStr, String savedStr)
try
Signature signature = cryptoObject.getSignature();
signature.initVerify(publicKey);
signature.update(inputStr.getBytes());
boolean isVerified = signature.verify(savedStr.getBytes());
return isVerified;
catch (InvalidKeyException e)
e.printStackTrace();
catch (SignatureException e)
e.printStackTrace();
return false;
但它总是返回 false。
有人知道为什么吗?
【问题讨论】:
您不应该在签名验证过程中的某个时刻撤消bytesToHex
步骤吗?
【参考方案1】:
看起来在您的sign()
方法中,您正在返回从signature.sign()
方法获得的byte[]
的Hex
。如果这是您保存为savedStr
的内容。那么验证方式要改成将Hex
编码的字符串转换为byte[]
。您可以使用HexManager.hexToBytes()
(或等效项)(如果存在)将savedStr
转换为byte[] savedStrBytes
。
public boolean verify(String inputStr, String savedStr)
try
byte[] savedStrBytes = HexManager.hexToByes(savedStr);
Signature signature = cryptoObject.getSignature();
signature.initVerify(publicKey);
signature.update(inputStr.getBytes());
boolean isVerified = signature.verify(savedStrBytes);
return isVerified;
catch (InvalidKeyException e)
e.printStackTrace();
catch (SignatureException e)
e.printStackTrace();
return false;
【讨论】:
以上是关于如何使用公钥验证 ECDSA?的主要内容,如果未能解决你的问题,请参考以下文章
ECDSA Android 使用公钥验证总是返回 false
如何使用证书中的公钥检查 ECDSA(在 p-256 上)签名
当我只有原始签名(R,S)和原始公钥点(Qx,Qy)时,ECDSA如何验证Java中的数据块