您好,登錄后才能下訂單哦!
這篇文章主要介紹了在JAVA中如何使用可信時間戳,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
可信時間戳是讓可信第三方(“時間戳機構”,TSA)以電子形式證明給定事件的時間的過程。歐盟法規 eIDAS 賦予這些時間戳法律效力——即,如果事件帶有時間戳,則沒有人可以對時間或事件內容提出異議。適用于多種場景,包括時間戳審計日志。(注意:時間戳對于良好的審計跟蹤是不夠的,因為它不能阻止惡意行為者完全刪除事件)
可信時間戳有許多標準,核心之一是RFC 3161
。與大多數 RFC 一樣,它很難閱讀。對于 Java 用戶來說幸運的是,BouncyCastle 實現了該標準。不幸的是,與大多數安全 API 一樣,使用它很困難,甚至很糟糕。我必須實現它,所以我將分享時間戳數據所需的代碼。
我將嘗試解釋主要流程。顯然,有很多代碼可以簡單地遵循標準。BouncyCastle 類是一個難以導航的迷宮。
主要方法顯然是timestamp(hash, tsaURL, username, password, tsaPolicyOid)
:
public TimestampResponseDto timestamp(byte[] hash, String tsaUrl, String tsaUsername, String tsaPassword, String tsaPolicyOid)throws IOException {
MessageImprint imprint =new MessageImprint(sha512oid, hash);
ASN1ObjectIdentifier tsaPolicyId = StringUtils.isNotBlank(tsaPolicyOid) ?new ASN1ObjectIdentifier(tsaPolicyOid) : baseTsaPolicyId;
TimeStampReq request =new TimeStampReq(imprint, tsaPolicyOid,new ASN1Integer(random.nextLong()),
ASN1Boolean.TRUE,null);
byte[] body = request.getEncoded();
try {
byte[] responseBytes = getTSAResponse(body, tsaUrl, tsaUsername, tsaPassword);
ASN1StreamParser asn1Sp =new ASN1StreamParser(responseBytes);
TimeStampResp tspResp = TimeStampResp.getInstance(asn1Sp.readObject());
TimeStampResponse tsr =new TimeStampResponse(tspResp);
checkForErrors(tsaUrl, tsr);
// validate communication level attributes (RFC 3161 PKIStatus)
tsr.validate(new TimeStampRequest(request));
TimeStampToken token = tsr.getTimeStampToken();
TimestampResponseDto response =new TimestampResponseDto();
response.setTime(getSigningTime(token.getSignedAttributes()));
response.setEncodedToken(Base64.getEncoder().encodeToString(token.getEncoded()));
return response;
}catch (RestClientException | TSPException | CMSException | OperatorCreationException | GeneralSecurityException e) {
throw new IOException(e);
}
}
它通過創建消息印記來準備請求。請注意,您傳遞的是散列本身,還有用于生成散列的散列算法。為什么 API 不對你隱藏它,我不知道。在我的情況下,哈希以更復雜的方式獲得,因此它很有用,而且仍然很實用。然后我們獲取請求的原始形式并將其發送給 TSA(時間戳機構)。這是一個 HTTP 請求,有點簡單,但您必須處理一些在 TSA 中不一定一致的請求和響應標頭。用戶名和密碼是可選的,一些 TSA 提供無需身份驗證的服務(限速)。另請注意 tsaPolicyOid
– 大多數 TSA 都有其特定政策記錄在其頁面上,您應該從那里獲取 OID。
當您返回原始響應時,您將其解析為 TimeStampResponse
。同樣,您必須經過 2 個中間對象(ASN1StreamParser
和 TimeStampResp
),這可能是一個適當的抽象,但不是可用的 API。
然后您檢查響應是否成功,您還必須對其進行驗證——TSA 可能返回了錯誤的響應。理想情況下,所有這些都可以對您隱藏。驗證會引發異常,在這種情況下,我只是通過包裝在 IOException 中進行傳播。
最后,您獲得令牌并返回響應。最重要的是令牌的內容,在我的情況下需要 Base64,所以我對其進行了編碼。它也可能只是原始字節。如果你想從令牌中獲取任何額外的數據(例如簽名時間),并不是那么簡單;您必須解析低級屬性(見要點)。
好的,您現在擁有令牌,可以將其存儲在數據庫中。有時您可能想要驗證時間戳是否未被篡改。代碼在這里,我甚至不會試圖解釋它——這是一大堆樣板,也說明了 TSA 響應方式的變化(我已經嘗試了一些)。需要 DummyCertificate 類的事實要么意味著我做錯了什么,要么證實了我對 BouncyCastle API 的批評。某些 TSA 可能不需要 DummyCertificate,但其他 TSA 需要 DummyCertificate,而且您實際上無法那么容易地實例化它。您需要一個真實的證書來構建它(它不包含在要點中;使用下一個要點中的 init() 方法,您可以使用dummyCertificate = new DummyCertificate(certificateHolder.toASN1Structure());
)。在我的代碼中,這些都是一個類,但是為了呈現它們,我決定將其拆分,因此有一點重復。
好的,現在我們可以添加時間戳并驗證時間戳。這應該足夠了;但出于測試目的(或有限的內部使用),您可能希望在本地進行時間戳記,而不是詢問 TSA。代碼可以在這里找到。它使用 spring,但您可以將密鑰庫詳細信息作為參數傳遞給 init 方法。您需要一個帶有密鑰對和證書的 JKS 存儲,我使用 KeyStore Explorer
創建它們。如果您在 AWS 中運行您的應用程序,您可能希望使用 KMS(密鑰管理服務)加密您的密鑰庫,然后在應用程序加載時對其進行解密,但這超出了本文的范圍。對于本地時間戳驗證按預期工作,對于時間戳 – 無需調用外部服務,只需調用localTSA.timestamp(req);
我是如何知道要實例化哪些類以及要傳遞哪些參數的——我不記得了。查看測試、示例、答案、來源。花了一段時間,所以我分享它,以潛在地避免其他人的一些麻煩。
您可以測試的TSA列表:SafeCreative
、FreeTSA
、time.centum.pl
。
我意識到這似乎不適用于許多場景,但我建議為應用程序數據的一些關鍵部分添加時間戳。將它放在你的“工具箱”中,隨時可用,而不是試圖閱讀標準并與 BouncyCastle 類斗爭數天以完成這個所謂的簡單任務,這通常很有用。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“在JAVA中如何使用可信時間戳”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。