ECDSA Android 使用公钥验证总是返回 false
Posted
技术标签:
【中文标题】ECDSA Android 使用公钥验证总是返回 false【英文标题】:ECDSA Android verify with Public Key always return false 【发布时间】:2017-08-26 14:57:47 【问题描述】:我有一些令牌,我需要先使用 SHA256 和 ECDSA 根据 KeyStore 中的私钥和公钥对其进行签名。
每次我尝试验证值时,我都会得到错误的结果。我不知道为什么。
有人知道如何解决这个问题吗?
这是我生成和加载密钥的函数:
private 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 | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(false)
.build());
keyPairGenerator.generateKeyPair();
setRegistred(true);
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();
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);
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();
这是符号值的方式:
public String sign(String inputStr, FingerprintManager.CryptoObject cryptoObject)
try
Signature signature = Signature.getInstance(SecurityConstants.SIGNATURE);
signature.initSign(privateKey);
signature.update(inputStr.getBytes());
byte[] signedBytes = signature.sign();
String result = Base64.encodeToString(signedBytes, Base64.DEFAULT);
Log.d("TAG", result);
return result;
catch (SignatureException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
return null;
这是我用公钥验证的尝试:
public boolean verifyWithPublicKey(String input, FingerprintManager.CryptoObject cryptoObject)
try
Signature signature = Signature.getInstance(SecurityConstants.SIGNATURE);
keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
PublicKey pk = getPublicKeyForVerification();
signature.initVerify(pk);
signature.update(input.getBytes());
boolean isVerifed = signature.verify(input.getBytes());
Log.d("TAG", String.valueOf(isVerifed));
return isVerifed;
catch (SignatureException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
catch (CertificateException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (KeyStoreException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
return false;
【问题讨论】:
【参考方案1】:错误就在这里,当你编写以下代码来验证签名时:
signature.update(input.getBytes());
boolean isVerifed = signature.verify(input.getBytes());
使用此代码,您尝试验证签名是否已与自己签名!
你应该有:
signature.update(MY_BYTES_ARRAY_OF_DATA);
boolean isVerifed = signature.verify(MY_SIGNATURE);
不要忘记签名默认不封装签名数据。
如果您想要包含签名数据和相关签名的格式,请使用 S/MIME、OpenPGP 等。
【讨论】:
以上是关于ECDSA Android 使用公钥验证总是返回 false的主要内容,如果未能解决你的问题,请参考以下文章
如何使用使用 sha1ecdsa 的公钥验证数据是不是符合签名?
验证充气城堡上的 javacard 签名 ALG_ECDSA_SHA
如何使用证书中的公钥检查 ECDSA(在 p-256 上)签名