Android/Python 如何验证签名 SHA256withRSA 和 PKCS1 填充

标签 android python python-2.7 rsa digital-signature

我是新成员,我等了两天才找到从android客户端到python服务器验证签名的解决方案。 首先我创建 key 对并从私钥生成签名。谢谢 pedrofb 我已经更新了完整的代码。在 python 服务器中验证完成。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    KeyPairGenerator keyPairGenerator = null;
    try {
        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
        //keyStore.deleteEntry("key1");
        keyPairGenerator = KeyPairGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
        try {
            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("key1", KeyProperties.PURPOSE_SIGN)
                    .setKeySize(2048)
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setDigests(KeyProperties.DIGEST_SHA256)
                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
            keyPairGenerator.initialize(builder.build());
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = (PrivateKey) keyStore.getKey("key1", null);
        PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey();
        String publicKeyStr = Base64.encodeToString(publicKey.getEncoded(), Base64.NO_WRAP);
        Log.d("Hahaha", publicKeyStr);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        String data = "haha";
        signature.update(data.getBytes());
        byte[] signatureBytes = signature.sign();
        String signatureBase64 = Base64.encodeToString(signatureBytes, Base64.NO_WRAP);
        Log.d("Hahaha", signatureBase64);
        Signature verifySignature = Signature.getInstance("SHA256withRSA");
        verifySignature.initVerify(publicKey);
        verifySignature.update(data.getBytes());
        boolean isVerify = verifySignature.verify(Base64.decode(signatureBase64, Base64.NO_WRAP));
        Log.d("Hahaha", isVerify + "");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static String sha256(String rawString){
    MessageDigest shaDigest;
    byte[] data;
    try {
        data = rawString.getBytes("UTF-8");
        shaDigest = MessageDigest.getInstance("SHA-256");
    } catch (Exception e) {
        return null;
    }
    shaDigest.update(data);
    return toHex(shaDigest.digest());
}

public static String toHex(byte[] tmp) {
    char hexDigits[] =
            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
                    'e', 'f'};
    int nBytesLen = tmp.length;
    char str[] = new char[nBytesLen * 2];
    int k = 0;
    for (byte byte0 : tmp) {
        str[k++] = hexDigits[byte0 >>> 4 & 0xf];
        str[k++] = hexDigits[byte0 & 0xf];
    }
    return new String(str);
}

和服务器,我使用PKCS1_v1_5来验证签名,它将从android客户端发送

from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from base64 import b64decode

keyDER = b64decode(open('public.der').read())
key = RSA.importKey(keyDER)
message = "haha"
h = SHA256.new(message)
print h.hexdigest()
signature = b64decode(open('signature.der').read())
verifier = PKCS1_v1_5.new(key)
if verifier.verify(h, signature):
    print "The signature is authentic."
else:
    print "The signature is not authentic."

我已经检查了客户端和服务器的散列​​数据,它是相同的,但是 verifier.verify 返回 false,public.der 是变量 PublicKeyStrsignature 的值.der 是变量 SignatureBase64 的值 请帮助我。

最佳答案

[在评论中解决]你的 Java 代码中有几个错误

1) 在 Java 代码中,您使用 SHA256 对消息进行两次摘要并签署一个十六进制值,而不是二进制消息。

在 java 中,SHA256withRSA 执行多个操作,首先对消息应用 SHA256 摘要算法,然后应用 RSA PKCS #1 v1.5 算法。在 python(或其他语言)中,它可以分两步以编程方式完成

改变

signature.update(sha256(data).getBytes());
verifySignature.update(sha256(data).getBytes());

signature.update(data.getBytes());
verifySignature.update(data.getBytes());

2) 删除 .setBlockModes(KeyProperties.BLOCK_MODE_CBC)。这是一个加密参数,不适用于数字签名

3) 您应该创建一次 key 对,而不是每次调用 onCreate

关于Android/Python 如何验证签名 SHA256withRSA 和 PKCS1 填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47749257/

相关文章:

python - pip install 'what you want to install' 不起作用

macos - python3.6 ffmpeg调用MacOSX(关闭)

python - AppEngine bulkloader、高复制存储和 python27 运行时

python - 将 Pandas 日期时间月份转换为字符串表示形式

python - 以简单的方式比较两个列表,字典

python - 使用管道运算符在两个Python脚本之间流式传输多批数据

android - 如何从 Android 读取和写入 NfcA 卡

java - 相机预览颠倒

javascript - window.innerwidth 的意外行为

android - 更改 Android TextView 项目符号颜色