// 最新碰到一个需求, 需要同java下的签名做验签, 感觉有必要总结下:
// 整个过程碰到以下几个问题:
/*
1、如何生成指定的公私钥?
# 使用linux指令openssl, openssl这个东西是真的强, (证书问题, 加解密问题, 公私钥问题等)都能帮你处理的妥妥滴; 有兴趣和时间的童鞋建议好好玩玩这东西. (yum install openssl* -y)
私钥: openssl genrsa -out rsa_private_key.pem 1024 // 不指定, 默认为2048位字符
公钥: openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
2、如何验证公私钥是匹配的?(私钥签的名,公钥可以验签通过,那么就是匹配的)
# 同样使用openssl, 姿势如下:
签名: openssl dgst -sign rsa_private.key -sha1 -out sha1_rsa_file.sign file.txt
验签: openssl dgst -verify rsa_public.key -sha1 -signature sha1_rsa_file.sign file.txt
原文链接: https://blog.csdn.net/scuyxi/article/details/55002130
# http://tool.chacuo.net/cryptrsakeyvalid // 这个网址也可以, 效果不是很好
3、pkcs1与pkcs8格式转换的问题?
# 本处摘自 https://blog.csdn.net/six66hao/article/details/81814576
常用的rsa密钥有两种格式,一种为pkcs1,首尾分别为:
# 公钥
-----BEGIN RSA PUBLIC KEY-----
-----END RSA PUBLIC KEY-----
# 私钥
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
另一种为pkcs8,首位分别为:
# 公钥
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
# 私钥
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
使用python rsa模块生成的公/私钥均为pkcs1格式,生成密钥对代码如下:
(public_key, private_key) = rsa.newkeys(lens)
with open('public.pem', 'wb') as f:
f.write(public_key.save_pkcs1())
with open('private.pem', 'wb') as f:
f.write(private_key.save_pkcs1())
4、不同语言之间做签名与验签时的对应问题?
# 找出对应的库/包
# 采用相同的编码格式, 加解密算法
# 公私钥必须是配对的
5、老掉牙的字符编码格式问题, 还是不熟练
# py3 bytes object
mybyte = b"test"
# str object
mystr = "test"
# str to bytes
bytes(mystr, encoding="utf8")
# bytes to str
str(mybyte, encoding="utf-8")
# py2 str 转 utf8
str.encode(mystr, 'utf-8')
*/
// 说了碰到的问题, 自然要玩玩签名与验签
package myJava;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.security.Signature;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
public class verifySignature {
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";
public static String sign(byte[] data, String privateKey) throws Exception {
// 解密由 base64 编码的私钥
final Base64.Encoder encoder = Base64.getEncoder();
final Base64.Decoder decoder = Base64.getDecoder();
byte[] keyBytes = decoder.decode(privateKey);
// 构造 PKCS8EncodedKeySpec 对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取私钥对象
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(priKey);
signature.update(data);
return encoder.encodeToString(signature.sign());
}
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
// 解码由 base64 编码的公钥
final Base64.Decoder decoder = Base64.getDecoder();
final byte[] keyBytes = publicKey.getBytes("UTF-8");
// 构造 X509EncodedKeySpec 对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoder.decode(keyBytes));
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取公钥匙对象
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(decoder.decode(sign));
}
public static void main(String[] args) throws Exception {
String s = "hello world";
String pubKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyJy3rlD9EtWqVBzSIYxRRuFWRVn3juht2nupDCBSsWi7uKaRu3W0gn5y6aCacArtCkrf0EehwYRm0A4iHf8rkCAwEAAQ==";
// PKCS8格式私钥(可由PKCS1格式转换)
String priKey = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvInLeuUP0S1apUHNIhjFFG4VZFWfeO6G3ae6kMIFKxaLu4ppG7dbSCfnLpoJpwCu0KSt/QR6HBhGbQDiId/yuQIDAQABAkEAqm/y15UtOE7Ey/HxLCqyNqbRhdN1h5AxsT0IhgYvP+PhWGc3hRElMwNCdiNaJBh04R1iK6wmKoi3DSjkdU6IAQIhAPRL9khAdPMxjy5tpswNWeaDjNJrlUKEnItQUkoHqve5AiEAxZIDz235HcUgLg9ApYK4spOpzLDGCCgfO3FxmrUEUwECIEaLjQIOQvdbT1p75Ze1H0nWoRq+YGrF+qKsPicMkc1ZAiARlNTR+K9afthGQQU3tVJKUemiVXjJ8QgWehnp8oHYAQIhANsC2fEVjWv94Oy2c8I9qhuX+yfNtvZ2m+Kmf2o4JFrR";
String sign = "cPz4BuUiKXDDBXjTx5VcMFgDFdCKVfn50Idv7pYhmiivrmx94zk0Fpk6IbKjReiqaNfRhEqGCIVpdFNiKLVKfA==";
String m = "hello world";
String after_sign = sign(s.getBytes(), priKey);
System.out.println(after_sign);
boolean ok = verify(m.getBytes(), pubKey, sign);
System.out.println(ok);
}
}
/* 输出结果:
cPz4BuUiKXDDBXjTx5VcMFgDFdCKVfn50Idv7pYhmiivrmx94zk0Fpk6IbKjReiqaNfRhEqGCIVpdFNiKLVKfA==
true
*/
# -*- coding: utf-8 -*-
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
from base64 import b64decode, b64encode
origin_data = 'hello world'
public_key = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALyJy3rlD9EtWqVBzSIYxRRuFWRVn3juht2nupDCBSsWi7uKaRu3W0gn5y6aCacArtCkrf0EehwYRm0A4iHf8rkCAwEAAQ=='
signature = 'cPz4BuUiKXDDBXjTx5VcMFgDFdCKVfn50Idv7pYhmiivrmx94zk0Fpk6IbKjReiqaNfRhEqGCIVpdFNiKLVKfA=='
private_key = 'MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvInLeuUP0S1apUHNIhjFFG4VZFWfeO6G3ae6kMIFKxaLu4ppG7dbSCfnLpoJpwCu0KSt/QR6HBhGbQDiId/yuQIDAQABAkEAqm/y15UtOE7Ey/HxLCqyNqbRhdN1h5AxsT0IhgYvP+PhWGc3hRElMwNCdiNaJBh04R1iK6wmKoi3DSjkdU6IAQIhAPRL9khAdPMxjy5tpswNWeaDjNJrlUKEnItQUkoHqve5AiEAxZIDz235HcUgLg9ApYK4spOpzLDGCCgfO3FxmrUEUwECIEaLjQIOQvdbT1p75Ze1H0nWoRq+YGrF+qKsPicMkc1ZAiARlNTR+K9afthGQQU3tVJKUemiVXjJ8QgWehnp8oHYAQIhANsC2fEVjWv94Oy2c8I9qhuX+yfNtvZ2m+Kmf2o4JFrR'
def sign():
key_bytes = bytes(private_key, encoding="utf-8")
key_bytes = b64decode(key_bytes)
key = RSA.importKey(key_bytes)
hash_value = SHA256.new(bytes(origin_data, encoding="utf-8"))
signer = PKCS1_v1_5.new(key)
signature = signer.sign(hash_value)
return b64encode(signature)
def verify():
key_bytes = bytes(public_key, encoding="utf-8")
key_bytes = b64decode(key_bytes)
key = RSA.importKey(key_bytes)
hash_value = SHA256.new(bytes(origin_data, encoding="utf-8"))
verifier = PKCS1_v1_5.new(key)
if verifier.verify(hash_value, b64decode(signature)):
print("The signature is authentic.")
else:
print("The signature is not authentic.")
if __name__ == '__main__':
print(sign())
verify()
''' 输出结果:
b'cPz4BuUiKXDDBXjTx5VcMFgDFdCKVfn50Idv7pYhmiivrmx94zk0Fpk6IbKjReiqaNfRhEqGCIVpdFNiKLVKfA=='
The signature is authentic.
'''