溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

在JAVA中如何使用可信時(shí)間戳

發(fā)布時(shí)間:2022-02-24 14:25:59 來(lái)源:億速云 閱讀:155 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了在JAVA中如何使用可信時(shí)間戳,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

可信時(shí)間戳是讓可信第三方(“時(shí)間戳機(jī)構(gòu)”,TSA)以電子形式證明給定事件的時(shí)間的過(guò)程。歐盟法規(guī) eIDAS 賦予這些時(shí)間戳法律效力——即,如果事件帶有時(shí)間戳,則沒(méi)有人可以對(duì)時(shí)間或事件內(nèi)容提出異議。適用于多種場(chǎng)景,包括時(shí)間戳審計(jì)日志。(注意:時(shí)間戳對(duì)于良好的審計(jì)跟蹤是不夠的,因?yàn)樗荒茏柚箰阂庑袨檎咄耆珓h除事件)

可信時(shí)間戳有許多標(biāo)準(zhǔn),核心之一是RFC 3161。與大多數(shù) RFC 一樣,它很難閱讀。對(duì)于 Java 用戶(hù)來(lái)說(shuō)幸運(yùn)的是,BouncyCastle 實(shí)現(xiàn)了該標(biāo)準(zhǔn)。不幸的是,與大多數(shù)安全 API 一樣,使用它很困難,甚至很糟糕。我必須實(shí)現(xiàn)它,所以我將分享時(shí)間戳數(shù)據(jù)所需的代碼。

我將嘗試解釋主要流程。顯然,有很多代碼可以簡(jiǎn)單地遵循標(biāo)準(zhǔn)。BouncyCastle 類(lèi)是一個(gè)難以導(dǎo)航的迷宮。

主要方法顯然是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);
    }
}

它通過(guò)創(chuàng)建消息印記來(lái)準(zhǔn)備請(qǐng)求。請(qǐng)注意,您傳遞的是散列本身,還有用于生成散列的散列算法。為什么 API 不對(duì)你隱藏它,我不知道。在我的情況下,哈希以更復(fù)雜的方式獲得,因此它很有用,而且仍然很實(shí)用。然后我們獲取請(qǐng)求的原始形式并將其發(fā)送給 TSA(時(shí)間戳機(jī)構(gòu))。這是一個(gè) HTTP 請(qǐng)求,有點(diǎn)簡(jiǎn)單,但您必須處理一些在 TSA 中不一定一致的請(qǐng)求和響應(yīng)標(biāo)頭。用戶(hù)名和密碼是可選的,一些 TSA 提供無(wú)需身份驗(yàn)證的服務(wù)(限速)。另請(qǐng)注意 tsaPolicyOid – 大多數(shù) TSA 都有其特定政策記錄在其頁(yè)面上,您應(yīng)該從那里獲取 OID。

當(dāng)您返回原始響應(yīng)時(shí),您將其解析為 TimeStampResponse。同樣,您必須經(jīng)過(guò) 2 個(gè)中間對(duì)象(ASN1StreamParserTimeStampResp),這可能是一個(gè)適當(dāng)?shù)某橄?,但不是可用?API。

然后您檢查響應(yīng)是否成功,您還必須對(duì)其進(jìn)行驗(yàn)證——TSA 可能返回了錯(cuò)誤的響應(yīng)。理想情況下,所有這些都可以對(duì)您隱藏。驗(yàn)證會(huì)引發(fā)異常,在這種情況下,我只是通過(guò)包裝在 IOException 中進(jìn)行傳播。

最后,您獲得令牌并返回響應(yīng)。最重要的是令牌的內(nèi)容,在我的情況下需要 Base64,所以我對(duì)其進(jìn)行了編碼。它也可能只是原始字節(jié)。如果你想從令牌中獲取任何額外的數(shù)據(jù)(例如簽名時(shí)間),并不是那么簡(jiǎn)單;您必須解析低級(jí)屬性(見(jiàn)要點(diǎn))。

好的,您現(xiàn)在擁有令牌,可以將其存儲(chǔ)在數(shù)據(jù)庫(kù)中。有時(shí)您可能想要驗(yàn)證時(shí)間戳是否未被篡改。代碼在這里,我甚至不會(huì)試圖解釋它——這是一大堆樣板,也說(shuō)明了 TSA 響應(yīng)方式的變化(我已經(jīng)嘗試了一些)。需要 DummyCertificate 類(lèi)的事實(shí)要么意味著我做錯(cuò)了什么,要么證實(shí)了我對(duì) BouncyCastle API 的批評(píng)。某些 TSA 可能不需要 DummyCertificate,但其他 TSA 需要 DummyCertificate,而且您實(shí)際上無(wú)法那么容易地實(shí)例化它。您需要一個(gè)真實(shí)的證書(shū)來(lái)構(gòu)建它(它不包含在要點(diǎn)中;使用下一個(gè)要點(diǎn)中的 init() 方法,您可以使用dummyCertificate = new DummyCertificate(certificateHolder.toASN1Structure());)。在我的代碼中,這些都是一個(gè)類(lèi),但是為了呈現(xiàn)它們,我決定將其拆分,因此有一點(diǎn)重復(fù)。

好的,現(xiàn)在我們可以添加時(shí)間戳并驗(yàn)證時(shí)間戳。這應(yīng)該足夠了;但出于測(cè)試目的(或有限的內(nèi)部使用),您可能希望在本地進(jìn)行時(shí)間戳記,而不是詢(xún)問(wèn) TSA。代碼可以在這里找到。它使用 spring,但您可以將密鑰庫(kù)詳細(xì)信息作為參數(shù)傳遞給 init 方法。您需要一個(gè)帶有密鑰對(duì)和證書(shū)的 JKS 存儲(chǔ),我使用 KeyStore Explorer 創(chuàng)建它們。如果您在 AWS 中運(yùn)行您的應(yīng)用程序,您可能希望使用 KMS(密鑰管理服務(wù))加密您的密鑰庫(kù),然后在應(yīng)用程序加載時(shí)對(duì)其進(jìn)行解密,但這超出了本文的范圍。對(duì)于本地時(shí)間戳驗(yàn)證按預(yù)期工作,對(duì)于時(shí)間戳 – 無(wú)需調(diào)用外部服務(wù),只需調(diào)用localTSA.timestamp(req);

我是如何知道要實(shí)例化哪些類(lèi)以及要傳遞哪些參數(shù)的——我不記得了。查看測(cè)試、示例、答案、來(lái)源?;艘欢螘r(shí)間,所以我分享它,以潛在地避免其他人的一些麻煩。

您可以測(cè)試的TSA列表:SafeCreative、FreeTSA、time.centum.pl。

我意識(shí)到這似乎不適用于許多場(chǎng)景,但我建議為應(yīng)用程序數(shù)據(jù)的一些關(guān)鍵部分添加時(shí)間戳。將它放在你的“工具箱”中,隨時(shí)可用,而不是試圖閱讀標(biāo)準(zhǔn)并與 BouncyCastle 類(lèi)斗爭(zhēng)數(shù)天以完成這個(gè)所謂的簡(jiǎn)單任務(wù),這通常很有用。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“在JAVA中如何使用可信時(shí)間戳”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI