【发布时间】:2017-12-11 08:56:23
【问题描述】:
我是新会员,我已经等了两天才找到解决方案验证从 android 客户端到 python 服务器的签名。 首先,我创建密钥对并从私钥生成签名。谢谢 pedrob 我已经更新了完整的代码。在 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是变量PublicKeyStr的值,signature.der是变量SignatureBase64的值
请帮帮我。
【问题讨论】:
-
数据不相同,Java端是“哈哈哈”,python端是“哈哈”。
-
您有几个错误 1) 您在 Java 代码和签名和十六进制值中进行了两次散列。将
signature.update(sha256(data).getBytes());更改为signature.update(data.getBytes());并将verifySignature.update(sha256(data).getBytes());更改为verifySignature.update(data.getBytes());2)删除.setBlockModes(KeyProperties.BLOCK_MODE_CBC)3)您应该创建密钥对,而不是每次调用onCreate时 -
谢谢,但客户端我验证真实,我创建的 verifySignature 仅检查它是否适用于 android。我在java端和python端都签名的数据是“哈哈”。 python 中的 h.hexdigest() 和 sha256(data).getBytes() 返回相同的值。
-
3) 您应该创建一个密钥对,而不是每次调用 onCreate 时。你是对的,所以我总是在调试模式调用 onCreate 之后将密钥对更新为 public.der 和 signature.der。
-
谢谢佩德罗夫。我已经解决了这个问题,但我有一个问题要问你?我认为我们应该对客户端和服务器都进行哈希处理。但是为什么我们保留'haha'并在客户端签名但服务器必须通过SHA256哈希?
标签: android python python-2.7 rsa digital-signature