Android/Python 如何验证签名 SHA256withRSA 和 PKCS1 填充
Android/Python How to verify Signature SHA256withRSA and PKCS1 Padding
我是新成员,我已经等了两天才找到从 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);
}
和服务器,我使用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 return 错误,public.der
是变量 PublicKeyStr
和 [=16= 的值] 是变量 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) 您应该创建密钥对一次,而不是每次 onCreate
被调用时
我是新成员,我已经等了两天才找到从 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);
}
和服务器,我使用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 return 错误,public.der
是变量 PublicKeyStr
和 [=16= 的值] 是变量 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) 您应该创建密钥对一次,而不是每次 onCreate
被调用时