我是新成员,我已经等了两天才找到从android客户端到python服务器的解决方案验证签名。 首先,我创建密钥对并从私钥生成签名。谢谢你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);
}
和Server,我使用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
是变量PublicKeyStr
的值,signature.der
是变量值{{1 }}
请帮帮我。
答案 0 :(得分:1)
[在评论中解决]您的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)你应该创建一次密钥对,而不是每次调用onCreate