RSA簽名與驗簽


RSA簽名與驗簽

之前看過RSA加密算法的一些介紹,對RSA加密的原理有一些了解。其實剛剛挺熟非對稱加密時是覺得很神奇的。通常對稱加密很好理解,比如原理是ANA,我們將每個字母后移一位,那么就是BOB了,這就是很簡單的加密過程(上帝ana就變成了凡人bob了,只有dota玩家才知道的梗)。解密就將每個字母前移一位。如果把移動的位數看成密鑰,那么密鑰就是1。加密和解密密鑰是一樣的。

剛好最近項目中使了RSA簽名,在此記錄下。

項目使用

目前項目中是使用RSA的簽名與驗簽功能。第三方發送文件給我們,同時會發送該文件的摘要(SHA256)信息,而摘要信息是使用私鑰簽名過的。我們將收到的文件做摘要(SHA256),然后使用公鑰進行驗簽。如果簽名驗證通過才能認為文件是可信的。

問題

項目組的同事在開發好后想測試一下,但是發現第三方只提供了一個樣例文件,而且文件內容還是不符合業務要求的。沒辦法驗證整個流程。

其實解決方式很簡單:替換公鑰

生成密鑰對

第三方提供的公鑰是一個沒有后綴名的文件,使用文本編輯器打開是亂碼的,可以猜測是二進制文件。看了第三方提供的代碼,是直接從文件中讀取byte數據,然后構建一個PublicKey。

然后我嘗試生成自己的密鑰對,一開始我使用的是Xshell。因為SSH是支持RSA加密的,一般的SSH工具都支持生成RSA密鑰。

Xshell

  1. 打開Xshell

  2. 點擊“工具”菜單

  3. 點擊“新建用戶密鑰生成向導”

  4. 密鑰類型選“RSA”,密鑰長度選1024(第三方給的密鑰是1024位)

  5. 然后一路下一步,其中,會讓輸入“用戶密鑰加密的密碼”,我因為是代碼中使用,直接沒輸入。如果是作為SSH登陸的話還是需要輸入一下,不然私鑰被別人盜用,沒有密碼,別人就可以為所欲為了。

  6. 然后密鑰就生成好了,提供和三種格式的公鑰:“SSH1”、“SSH2-IETF SECSH”、“SSH2-OpenSSH”,除了SSH1,SSH2的都是一樣的形式只是備注不一樣

生成后發現沒法使用,因為Xshell生成的密鑰是字符串(Base64編碼),類似下面的。

AAAAB3NzaC1yc2EAAAABIwAAAIEAnfJxPq3OLqfZVt+YNH6tkO7d5qx8etFU8g7adwFzTwuXOaDtm0qoQXMkiRLTt3p5S6ExWM9+NLQePhbSur0d8d6Y4sf3SNB/oIpAYIezkihFczuxHBi1RVNUdVwLdWyFW69eWBGkyaRyt7q0kzIPXMpRz/Gj+JTP45MaNOapW5U=

我通過代碼將這個字符串Base64解碼成byte數組。然后構建一個公鑰,拋出異常。

Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
	at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
	at io.github.loanon.rsa.RSAStudy.main(RSAStudy.java:17)
Caused by: java.security.InvalidKeyException: invalid key format
	at sun.security.x509.X509Key.decode(X509Key.java:387)
	at sun.security.x509.X509Key.decode(X509Key.java:403)
	at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:84)
	at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
	at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
	... 2 more

關鍵詞“invalid key format”讓我覺得是密鑰格式不對。

我從網上找了其他RSA的教程,看到別人的密鑰(Base64)字符串都是這樣的:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqPvovSfXcwBbW8cKMCgwqNpsYuzF8RPAPFb7LGsnVo44JhM/xxzDyzoYtdfNmtbIuKVi9PzIsyp6rg+09gbuI6UGwBZ5DWBDBMqv5MPdOF5dCQkB2Bbr5yPfURPENypUz+pBFBg41d+BC+rwRiXELwKy7Y9caD/MtJyHydj8OUwIDAQAB

首先從長度上就和我用Xshell生成的不一樣。為了驗證我的猜想。我將第三方提供的密鑰二進制文件讀出來,通過Base64編碼后,打印出來,和網上別人教程里面的格式、長度一樣(這里就不貼出來了)。那么就說明不能用Xshell來生成密鑰對。個人認為是密鑰格式不通,至於如何轉換,還沒弄明白。有知道的大神,還請指教一二。

Java

既然Xshell工具生成的密鑰對不用用,那就自己用Java代碼生成,網上也有教程。總結一下:

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();

這樣就可以拿到密鑰對的二進制數據了。

將公鑰數據保存成二進制文件,放到項目中。現在就可以自己簽名進行驗證了。

密鑰格式

找到一篇文章好像解釋了為什么Xshell生成的密鑰對無法使用。

因為Xshell生成的是OpenSSH格式的密鑰,但是Java代碼中使用的是OpenSSL格式的密鑰。其實通過代碼或者工具也是可以將兩種格式的密鑰進行轉換的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM