p7數字信封


PKCS7的數字信封格式分為兩種:帶簽名的數字信封和不帶簽名的數字信封。由於這個數字信封的生成過程比較復雜,所以這兩種格式比較容易記混,導致都搞不清楚一個數字信封里面到底是存儲的什么內容了。下面我就詳細的解釋一下,這兩種數字信封的生成過程和其詳細的數據結構。

不帶簽名的數字信封:
不帶簽名的數字信封內容類型由任意類型的加密內容和加密的一個/多個接收者的內容加密密鑰組成,其生成過程如下:
1. 發送方隨機產生一個對應於特定加密內容加密密鑰。
2. 發送方將內容加密密鑰用每個接收者的公鑰加密。
3. 對於每一個接收者,把加了密的內容加密密鑰和接收者的其他信息放入RecipientInfo值中。
4. 用內容加密密鑰加密內容。
5. 將所有接收者的RecipientInfo值和加了密的內容放入EnvelopedData值中。

發送給接收方后,解包的過程很簡單:接收者用自己的私鑰解開加密的內容加密密鑰,然后用該密鑰解密密文內容。整個過程參與非對稱運算的只有接收方的密鑰對。

帶簽名的數字信封:
帶簽名的數字信封由任意類型的加密內容、加了密的一個/多個接收者的內容加密密鑰和雙重加密的一個/多個簽名者的消息摘要。“雙重加密”由簽名者私鑰的加密和內容加密密鑰的加密組成。其生成過程如下:

1.發送方隨機產生一個對應於特定加密算法的內容加密密鑰。
2. 發送方將內容加密密鑰用每個接收者的公鑰加密。
3. 對於每一個接收者,把加了密的內容加密密鑰和接收者的其他信息放入RecipientInfo值中,參見數據結構2。
4. 對於每一個簽名者,他用自己的消息摘要算法計算出摘要值 (如果兩個簽名者使用同樣的算法,那么摘要值只需計算一次) 。
5. 對於每一個簽名者,消息摘要和相關的信息用自己的私鑰加密,結果再用內容加密密鑰加密。
6. 對於每一個簽名者,把雙重加密(即第5步中的先非對稱加密,再對稱加密的過程)的消息摘要和其他的簽名者特定信息放入SignerInfo 值中。
7. 用內容加密密鑰加密內容。
8. 把所有簽名者的消息摘要算法、所有簽名者的SignerInfo值、所有接收者的RecipientInfo值和加了密的內容一起放入SignedAndEnvelopedData 值中。

接收方接到數字信封后,解封操作會復雜些:
1.收方B接受到數字信封DE后,首先用自己的私鑰PVB解密數字信封,取出對稱密鑰SK;2.收方B用對稱密鑰SK通過DES算法解密加密信息E,還原出原文信息、數字簽名SD及發方A證書的公鑰PBA;3. 收方B驗證數字簽名,先用發方A的公鑰解密數字簽名得數字摘要MD;4.收方B同時將原文信息用同樣的哈希運算,求得一個新的數字摘要MD’;5.將兩個數字摘要MD和MD’進行比較,驗證原文是否被修改。如果二者相等,說明數據沒有被篡改,是保密傳輸的,簽名是真實的;否則拒絕該簽名。

 

下圖為簡單流程:

代碼示例:

/**
	 * @param publicKey 公鑰對象
	 * @param orgData  原文
	 * @return Result if(code== 200)success else fail   
	 * encryptFileStr 加密后的字符串
	 * encryptKeyStr  加密后的秘鑰字符串
	 * @throws UnsupportedEncodingException 
	 * @throws NoSuchProviderException 
	 * @throws NoSuchAlgorithmException 
	 */
	public static Result strEncrypt(PublicKey publicKey,String orgData) throws UnsupportedEncodingException {
		try {
			//創建對稱秘鑰對
			byte[] key = Sm4Utils.generateKey();
			//對加密
			byte[] fileEncryptBytes = Sm4Utils.encrypt_ECB_Padding(key, orgData.getBytes(charset));
			//對秘鑰對加密
			byte[] encryptKey = SM2Util.encrypt((BCECPublicKey)publicKey, key);
			//將返回值base64加密
			String encryptDataStr = Base64Utils.encode(fileEncryptBytes);
			String encryptKeyStr = Base64Utils.encode(encryptKey);
			return new Result(Result.CODE_SUCCESS,"加密成功", encryptDataStr,encryptKeyStr);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return new Result(Result.CODE_EXCEPTION, "NoSuchAlgorithmException,沒有找到該摘要算法");
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
			return new Result(Result.CODE_EXCEPTION, "NoSuchProviderException,沒有找到該加密機");
		}catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | InvalidCipherTextException e ) {
			e.printStackTrace();
			return new Result(Result.CODE_EXCEPTION, "加密失敗:"+e.getMessage());
		}
	}

  

 參考:

https://blog.csdn.net/weixin_39636696/article/details/115780593

https://gitee.com/saxonkiku/encrypt_and_decrypt_file/blob/master/src/main/java/com/ymwk/StrEncrypt.java


免責聲明!

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



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