1. 程式人生 > >Python與Java之間的簽名和驗籤問題

Python與Java之間的簽名和驗籤問題

// 最新碰到一個需求, 需要同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.
'''