Python如何使用RSA和PKCS1填充来验证签名SHA256

Python如何使用RSA和PKCS1填充来验证签名SHA256

本文介绍了Android / Python如何使用RSA和PKCS1填充来验证签名SHA256的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new member, I have waited two days to find solution verify signature from android client to python server.First I create Key pair and generate signature from private key. Thank you pedrofb I have updated full code. verify done in python server.

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客户端发送

and Server, I use PKCS1_v1_5 to verify signature, it will be sent from android client

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 是变量 PublicKeyStr signature.der 的值是变量 SignatureBase64
的值。

I have check data hashed both client and server, it's same, but verifier.verify return false, public.der is value of variable PublicKeyStr and signature.der is value of variable SignatureBase64Please help me.

推荐答案

[已解决注释]您的Java代码中有几个错误

[Solved in comments] You have several errors in your Java code

1)在Java代码中,您使用SHA256两次消化了该消息并签署了一个十六进制值,不是二进制消息。

1) In the Java code, you are digesting the message twice with SHA256 and signing an hex value, not the binary message.

在Java中, SHA256withRSA 执行若干操作,首先对消息应用SHA256摘要算法,然后应用RSA PKCS#1 v1.5算法。在python(或其他语言)中,可以通过编程以两个步骤完成

In java, SHA256withRSA performs several operations, first applies the SHA256 digest algorithm to the message and then applies the RSA PKCS # 1 v1.5 algorithm. In python (or in other languages) it can be done programmatically in two steps

更改

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

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

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

2) Remove .setBlockModes(KeyProperties.BLOCK_MODE_CBC). This is an encryption parameter not appliable to digital signature

3)您应该一次创建密钥对,而不是每次 onCreate 被称为

3) You should create the the keypair once, not each time onCreate is called

这篇关于Android / Python如何使用RSA和PKCS1填充来验证签名SHA256的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-27 21:48