问题
import android.os.Bundle;
import android.util.Base64;
import android.widget.Toast;
import org.bouncycastle.jce.provider.BouncyCastleProvider; // implementation 'org.bouncycastle:bcprov-jdk16:1.46'
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
static final String PUBLIC_KEY = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMEV3EPREEDc0t4MPeuYgreLMHMVfD7iYJ2Cnkd0ucwf3GYVySvYTttMVMNMEKF554NYmdrOlqwo2s8J2tKt/oQ==";
static final String DATA = "Hello";
static final String SIGNATURE = "MEUCIQCsuI4OcBAyA163kiWji1lb7xAtC8S0znf62EpdA+U4zQIgBcLbXtcuxXHcwQ9/DmiVfoiigKnefeYgpVXZzjIuYn8=";
static boolean verifyData() throws Exception {
PublicKey pk = getPublicKey();
byte[] signatureBytes = Base64.decode(SIGNATURE, Base64.NO_WRAP);
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initVerify(pk);
signature.update(DATA.getBytes("UTF-8"));
return signature.verify(signatureBytes);
}
static PublicKey getPublicKey() throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(PUBLIC_KEY, Base64.NO_WRAP));
PublicKey key = keyFactory.generatePublic(x509EncodedKeySpec);
return key;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Toast.makeText(this, verifyData() + "", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(this, "Failure: " + e.getMessage(), Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
}
The code above performs ECDSA digital signature verification. This code works fine on every android version below Android P. On Android P I get this exception.
java.security.NoSuchAlgorithmException: The BC provider no longer provides an implementation for Signature.SHA1withRSA. Please see https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html for more details.
So as mentioned here I tried to remove the provider parameter from these statements like this:
Signature signature = Signature.getInstance("SHA256withECDSA");
KeyFactory keyFactory = KeyFactory.getInstance("EC");
But it didn't solve the problem? How come? Now I'm getting this exception:
java.security.InvalidKeyException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing public key
One of the possible solutions is to lower targetSdkVersion to 27 but this not good enough. Is there a better solution to the problem?
回答1:
I can reproduce the issue on my machine (Android P, API Level 28). One possible solution of the problem is to delete the pre-installed version before adding the BC Provider:
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
or alternatively:
Security.removeProvider("BC");
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Additionally the BC Provider must be specified explicitly:
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
...
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
In this constellation the signature can be verified.
The different behavior compared to lower API levels might be related to the changes concerning the BC Provider that were implemented in Android P, here.
来源:https://stackoverflow.com/questions/63578955/ecdsa-digital-signature-verification-on-android-p