ECDSA Digital Signature Verification on Android P

淺唱寂寞╮ 提交于 2021-01-27 13:19:42

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!