Python與Java之間的簽名和驗籤問題
阿新 • • 發佈:2018-12-17
// 最新碰到一個需求, 需要同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、老掉牙的字元編碼格式問題, 還是不熟練 # python3 bytes object mybyte = b"test" # str object mystr = "test" # str to bytes bytes(mystr, encoding="utf8") # bytes to str str(mybyte, encoding="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. '''