

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 驗證 CloudTrail Lake 儲存的查詢結果
<a name="cloudtrail-query-results-validation"></a>

若要判斷在 CloudTrail 傳送查詢結果之後，查詢結果是否經過修改、遭到刪除或保持不變，您可以使用 CloudTrail 查詢結果完整性驗證。此功能以產業標準演算法建置：SHA-256 適用於進行雜湊，而含 RSA 的 SHA-256 適用於進行數位簽署。這可透過運算方式防止修改、刪除或偽造 CloudTrail 查詢結果檔案，而無需偵測。您可以使用命令列來驗證查詢結果檔案。

## 為什麼使用它？
<a name="cloudtrail-query-results-validation-use-cases"></a>

驗證過的查詢結果檔案對於安全和鑑識調查十分重要。例如，驗證過的查詢結果檔案可讓您肯定地宣告查詢結果檔案本身並未變更。CloudTrail 查詢結果檔案完整性驗證程序也可讓您知道查詢結果檔案是否已遭刪除或變更。

**Topics**
+ [為什麼使用它？](#cloudtrail-query-results-validation-use-cases)
+ [使用 驗證已儲存的查詢結果 AWS CLI](#cloudtrail-query-results-validation-cli)
+ [CloudTrail 簽署檔案結構](#cloudtrail-results-file-validation-sign-file-structure)
+ [CloudTrail 查詢結果檔案完整性驗證的自訂實作](#cloudtrail-results-file-custom-validation)

## 使用 驗證已儲存的查詢結果 AWS CLI
<a name="cloudtrail-query-results-validation-cli"></a>

您可以使用 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/verify-query-results.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/verify-query-results.html) 命令驗證查詢結果檔案和簽署檔案的完整性。

### 先決條件
<a name="cloudtrail-query-results-validation-cli-prerequisites"></a>

若要使用命令列驗證查詢結果完整性，必須符合下列條件：
+ 您必須擁有 的線上連線 AWS。
+ 您必須使用第 2 AWS CLI 版。
+ 若要在本機驗證查詢結果檔案和簽署檔案，請套用下列條件：
  + 您必須將查詢結果檔案和簽署檔案放置在指定的檔案路徑。指定檔案路徑作為 **--local-export-path** 參數的值。
  + 您不得重新命名查詢結果檔案和簽署檔案。
+ 若要在 S3 儲存貯體中驗證查詢結果檔案和簽署檔案，請套用下列條件：
  + 您不得重新命名查詢結果檔案和簽署檔案。
  + 您必須具有包含查詢結果檔案和簽署檔案之 Amazon S3 儲存貯體的讀取權限。
  + 指定的 S3 字首必須包含查詢結果檔案和簽署檔案。指定 S3 字首作為 **--s3-prefix** 參數的值。

### verify-query-results
<a name="cloudtrail-query-results-validation-cli-command"></a>

 **verify-query-results** 命令透過比較每個查詢結果檔案的雜湊值和簽署檔案中的 `fileHashValue` 確認該雜湊值，然後驗證簽署檔案中的 `hashSignature`。

當確認查詢結果時，您可以使用 **--s3-bucket** 和 **--s3-prefix** 命令列選項來驗證儲存在 S3 儲存貯體中的查詢結果檔案和簽署檔案，或者您可以使用 **--local-export-path** 命令列選項對已下載查詢結果檔案和簽署檔案執行本機驗證。

**注意**  
**verify-query-results** 命令限特定區域使用。您必須指定**--region**全域選項，以驗證特定 的查詢結果 AWS 區域。

下列是 **verify-query-results** 命令選項。

**--s3-bucket** {{<string>}}  
指定儲存查詢結果檔案和簽署檔案的 S3 儲存貯體名稱。您不能將此參數與 **--local-export-path** 搭配使用。

**--s3-prefix** {{<string>}}  
指定包含查詢結果檔案和簽署檔案的 S3 資料夾的 S3 路徑 (例如，`s3/path/`)。您不能將此參數與 **--local-export-path** 搭配使用。如果檔案位於 S3 儲存貯體的根目錄中，則不需要提供此參數。

**--local-export-path** {{<string>}}  
指定包含查詢結果檔案和簽署檔案的本機目錄 (例如，`/local/path/to/export/file/`)。您不能將此參數與 **--s3-bucket** 或 **--s3-prefix** 搭配使用。

#### 範例
<a name="cloudtrail-query-results-validation-cli-examples"></a>

下列範例使用 **--s3-bucket** 和 **--s3-prefix** 命令列選項驗證查詢結果，以指定包含查詢結果檔案和簽署檔案的 S3 儲存貯體名稱和字首。

```
aws cloudtrail verify-query-results --s3-bucket {{amzn-s3-demo-bucket}} --s3-prefix {{prefix}} --region {{region}}
```

下列範例使用 **--local-export-path** 命令列選項驗證已下載查詢結果，以指定查詢結果檔案和簽署檔案的本機路徑。如需有關下載查詢結果檔案的詳細資訊，請參閱 [下載您的 CloudTrail Lake 已儲存查詢結果](view-download-cloudtrail-lake-query-results.md#cloudtrail-download-lake-query-results)。

```
aws cloudtrail verify-query-results --local-export-path {{local_file_path}} --region {{region}}
```

#### 驗證結果
<a name="cloudtrail-query-results-validation-cli-command-messages"></a>

下表說明查詢結果檔案和簽署檔案的可能驗證訊息。


****  

| 檔案類型 | 驗證訊息 | Description | 
| --- | --- | --- | 
| Sign file | Successfully validated sign and query result files | 簽署檔案簽章有效。可以檢查其參考的查詢結果檔案。 | 
| Query result file | `ValidationError: "File {{file_name}} has inconsistent hash value with hash value recorded in sign file, hash value in sign file is {{expected_hash}}, but get {{computed_hash}}` | 驗證失敗，因為查詢結果檔案的雜湊值與簽署檔案中的 fileHashValue 不相符。 | 
| Sign file | `ValidationError: Invalid signature in sign file` | 簽署檔案驗證失敗，因為簽章無效。 | 

## CloudTrail 簽署檔案結構
<a name="cloudtrail-results-file-validation-sign-file-structure"></a>

簽署檔案包含您儲存查詢結果時傳送至您 Amazon S3 儲存貯體的每個查詢結果檔案名稱、每個查詢結果檔案的雜湊值，以及檔案的數位簽章。數位簽章和雜湊是用於驗證查詢結果檔案和簽署檔案本身的完整性。

### 簽署檔案位置
<a name="cloudtrail-results-file-validation-sign-file-location"></a>

簽署檔案會傳送到遵循此語法的 Amazon S3 儲存貯體位置。

```
s3://{{amzn-s3-demo-bucket}}/{{optional-prefix/}}AWSLogs/{{aws-account-ID}}/CloudTrail-Lake/Query/{{year}}/{{month}}/{{date}}/{{query-ID}}/result_sign.json
```

### 範例簽署檔案內容
<a name="cloudtrail-results-file-validation-sign-file-contents"></a>

以下範例簽署檔案包含 CloudTrail Lake 查詢結果的資訊。

```
{
  "version": "1.0",
  "region": "us-east-1",
  "files": [
    {
      "fileHashValue" : "de85a48b8a363033c891abd723181243620a3af3b6505f0a44db77e147e9c188",
      "fileName" : "result_1.csv.gz"
    }
  ],
  "hashAlgorithm" : "SHA-256",
  "signatureAlgorithm" : "SHA256withRSA",
  "queryCompleteTime": "2022-05-10T22:06:30Z",
  "hashSignature" : "7664652aaf1d5a17a12ba50abe6aca77c0ec76264bdf7dce71ac6d1c7781117c2a412e5820bccf473b1361306dff648feae20083ad3a27c6118172a81635829bdc7f7b795ebfabeb5259423b2fb2daa7d1d02f55791efa403dac553171e7ce5f9307d13e92eeec505da41685b4102c71ec5f1089168dacde702c8d39fed2f25e9216be5c49769b9db51037cb70a84b5712e1dffb005a74580c7fdcbb89a16b9b7674e327de4f5414701a772773a4c98eb008cca34228e294169901c735221e34cc643ead34628aabf1ba2c32e0cdf28ef403e8fe3772499ac61e21b70802dfddded9bea0ddfc3a021bf2a0b209f312ccee5a43f2b06aa35cac34638f7611e5d7",
  "publicKeyFingerprint" : "67b9fa73676d86966b449dd677850753"
}
```

### 簽署檔案欄位說明
<a name="cloudtrail-results-file-validation-sign-file-descriptions"></a>

以下是簽署檔案中每個欄位的說明：

`version`  
簽署檔案的版本。

`region`  
用於儲存查詢結果 AWS 的帳戶區域。

`files.fileHashValue`  
壓縮查詢結果檔案內容的十六進位編碼雜湊值。

`files.fileName`  
查詢結果檔案的名稱。

`hashAlgorithm`  
用於對查詢結果檔案進行雜湊的雜湊演算法。

`signatureAlgorithm`  
用於簽署檔案的演算法。

`queryCompleteTime`  
指出 CloudTrail 將查詢結果傳送至 S3 儲存貯體的時間。您可以使用此值來尋找公有金鑰。

`hashSignature`  
檔案的雜湊簽章。

`publicKeyFingerprint`  
用於簽署檔案之公有金鑰的十六進位編碼指紋。

## CloudTrail 查詢結果檔案完整性驗證的自訂實作
<a name="cloudtrail-results-file-custom-validation"></a>

由於 CloudTrail 使用業界標準、公開使用的密碼編譯演算法和雜湊函數，因此您可以建立自己的工具來驗證 CloudTrail 查詢結果檔案的完整性。當您將查詢結果儲存到 Amazon S3 儲存貯體時，CloudTrail 會將簽署檔案傳送到您的 S3 儲存貯體。您可以實作自己的驗證解決方案，以驗證簽章和查詢結果檔案。如需簽署檔案的詳細資訊，請參閱 [CloudTrail 簽署檔案結構](#cloudtrail-results-file-validation-sign-file-structure)。

本主題說明簽署檔案的簽署方式，並接著詳細說明您必須執行的步驟，以實作解決方案來驗證簽署檔案及其所參考的查詢結果檔案。

### 了解如何簽署 CloudTrail 簽署檔案
<a name="cloudtrail-results-file-custom-validation-how-cloudtrail-sign-files-are-signed"></a>

CloudTrail 簽署檔案使用 RSA 數位簽章進行簽署。針對每個簽署檔案，CloudTrail 會執行下列操作：

1. 建立雜湊清單，內含每個查詢結果檔案的雜湊值。

1. 取得區域唯一的私有金鑰。

1. 將字串和私有金鑰的 SHA-256 雜湊傳遞到 RSA 簽署演算法，以產生數位簽章。

1. 將簽章的位元組碼編碼為十六進位格式。

1. 將數位簽章放入簽署檔案中。

#### 資料簽署字串內容
<a name="cloudtrail-results-file-custom-validation-data-signing-string-summary"></a>

資料簽署字串是由每個查詢結果檔案的雜湊值 (以空格分隔) 所組成。簽署檔案會列出每個查詢結果檔案的 `fileHashValue`。

### 自訂驗證實作步驟
<a name="cloudtrail-results-file-custom-validation-steps"></a>

實作自訂驗證解決方案時，您需要先驗證簽署檔案，再驗證其所參考的查詢結果檔案。

#### 驗證簽署檔案
<a name="cloudtrail-results-file-custom-validation-steps-sign"></a>

若要驗證簽署檔案，您需要其簽章、其私有金鑰已用來簽署的公有金鑰，以及用來運算的資料簽署字串。

1. 取得簽署檔案。

1. 確認已從其原始位置擷取簽署檔案。

1. 取得簽署檔案的十六進位編碼簽章。

1. 取得其私有金鑰已用來簽署簽署檔案之公有金鑰的十六進位編碼指紋。

1. 擷取簽署檔案中 `queryCompleteTime` 對應時間範圍的公有金鑰。針對時間範圍，請選擇早於 `queryCompleteTime` 的 `StartTime` 和晚於 `queryCompleteTime` 的 `EndTime`。

1. 從所擷取的公有金鑰，選擇其指紋符合簽署檔案中 `publicKeyFingerprint` 值的公有金鑰。

1. 使用包含每個查詢結果檔案雜湊值 (以空格分隔) 的雜湊清單，重新建立用於驗證簽署檔案簽章的資料簽署字串。簽署檔案會列出每個查詢結果檔案的 `fileHashValue`。

   例如，如果簽署文件的 `files` 陣列包含以下三個查詢結果檔案，則雜湊清單為「aaa bbb ccc」。

   ```
   “files": [ 
      { 
           "fileHashValue" : “aaa”, 
           "fileName" : "result_1.csv.gz" 
      },
      {       
           "fileHashValue" : “bbb”,       
           "fileName" : "result_2.csv.gz"      
      },
      { 
           "fileHashValue" : “ccc”,       
           "fileName" : "result_3.csv.gz" 
      }
   ],
   ```

1. 傳遞字串、公有金鑰和簽章的 SHA-256 雜湊做為 RSA 簽章驗證演算法的參數，來驗證簽章。如果結果為 true，則簽署檔案有效。

#### 驗證查詢結果檔案
<a name="cloudtrail-results-file-custom-validation-steps-logs"></a>

如果簽署檔案有效，請驗證簽署檔案所參考的查詢結果檔案。若要驗證查詢結果檔案的完整性，請在其壓縮內容上運算 SHA-256 雜湊值，並將結果與簽署檔案中所記錄查詢結果檔案的 `fileHashValue` 進行比較。如果雜湊相符，則查詢結果檔案有效。

下列各節將詳細說明驗證程序。

#### A. 取得簽署檔案
<a name="cloudtrail-results-file-custom-validation-steps-get-the-sign-file"></a>

第一步是取得簽署檔案和公有金鑰的指紋。

1. 針對您要驗證的查詢結果從 Amazon S3 儲存貯體取得簽署檔案。

1. 接下來，從簽署檔案中取得 `hashSignature` 值。

1. 在簽署檔案中，從 `publicKeyFingerprint` 欄位取得其私有金鑰已用來簽署檔案之公有金鑰的指紋。

#### B. 擷取用於驗證簽署檔案的公有金鑰
<a name="cloudtrail-results-file-custom-validation-steps-retrieve-public-key"></a>

若要取得公有金鑰來驗證簽署檔案，您可以使用 AWS CLI 或 CloudTrail API。在這兩種情況下，您會為要驗證的簽署檔案指定時間範圍 (即開始時間和結束時間)。使用符號檔案中 `queryCompleteTime` 對應的時間範圍。您指定的時間範圍內可能會傳回一或多個公有金鑰。傳回的金鑰可能會有重疊的有效時間範圍。

**注意**  
由於 CloudTrail 針對每個區域使用不同的私有/公有金鑰對，因此每個簽署檔案都使用其區域唯一的私有金鑰進行簽署。因此，當您驗證來自特定區域的簽署檔案時，您必須從同一個區域擷取其公有金鑰。

##### 使用 AWS CLI 擷取公有金鑰
<a name="cloudtrail-results-file-custom-validation-steps-retrieve-public-key-cli"></a>

若要使用 擷取簽署檔案的公有金鑰 AWS CLI，請使用 `cloudtrail list-public-keys`命令。此命令的格式如下：

 `aws cloudtrail list-public-keys [--start-time <start-time>] [--end-time <end-time>]` 

開始時間和結束時間參數是 UTC 時間戳記，而且是選用的。如果未指定，則會使用目前的時間，並傳回一或多個目前作用中的公有金鑰。

 **回應範例** 

回應會是代表所傳回之一或多個金鑰的 JSON 物件清單：

##### 使用 CloudTrail API 擷取公有金鑰
<a name="cloudtrail-results-file-custom-validation-steps-retrieve-public-key-api"></a>

若要使用 CloudTrail API 擷取簽署檔案的公有金鑰，請將開始時間和結束時間值傳遞到 `ListPublicKeys` API。`ListPublicKeys` API 會傳回其私有金鑰已在指定時間範圍內用來簽署檔案的公有金鑰。針對每個公有金鑰，API 也會傳回對應的指紋。

##### `ListPublicKeys`
<a name="cloudtrail-results-file-custom-validation-steps-list-public-keys"></a>

本節說明 `ListPublicKeys` API 的請求參數和回應元素。

**注意**  
`ListPublicKeys` 的二進位欄位編碼可能會有所變更。

 **請求參數** 


****  

| 名稱 | 描述 | 
| --- | --- | 
|  StartTime  | 選擇地指定要查詢 CloudTrail 簽署檔案公有金鑰之時間範圍的開始時間 (UTC)。如果未指定 StartTime，則會使用目前的時間，並傳回目前的公有金鑰。<br />類型：DateTime  | 
|  EndTime  | 選擇地指定要查詢 CloudTrail 簽署檔案公有金鑰之時間範圍的結束時間 (UTC)。如果未指定 EndTime，則會使用目前的時間。<br />類型：DateTime  | 

 **回應元素** 

`PublicKeyList` 是 `PublicKey` 物件陣列，其中包含：


****  

|  |  | 
| --- |--- |
|  名稱  |  描述  | 
|  Value  | PKCS \#1 格式的 DER 編碼公有金鑰值。<br />類型：Blob  | 
|  ValidityStartTime  | 公有金鑰的有效開始時間。<br />類型：DateTime  | 
|  ValidityEndTime  | 公有金鑰的有效結束時間。<br />類型：DateTime  | 
|  Fingerprint  | 公有金鑰的指紋。該指紋可用來識別驗證簽署檔案所需使用的公有金鑰。<br />類型：字串  | 

#### C. 選擇要用於驗證的公有金鑰
<a name="cloudtrail-results-file-custom-validation-steps-choose-public-key"></a>

從 `list-public-keys` 或 `ListPublicKeys` 所擷取的公有金鑰，選擇其指紋符合簽署檔案 `publicKeyFingerprint` 欄位中所記錄之指紋的公有金鑰。這是您將用來驗證簽署檔案的公有金鑰。

#### D. 重新建立資料簽署字串
<a name="cloudtrail-results-file-custom-validation-steps-recreate-data-signing-string"></a>

現在您已擁有簽署檔案的簽章及相關聯的公有金鑰，您需要計算資料簽署字串。計算資料簽署字串之後，您將擁有驗證簽章所需的輸入。

資料簽署字串是由每個查詢結果檔案的雜湊值 (以空格分隔) 所組成。重新建立此字串之後，您可以驗證簽署檔案。

#### E. 驗證簽署檔案
<a name="cloudtrail-results-file-custom-validation-steps-validate-sign-file"></a>

將重新建立後的資料簽署字串、數位簽章和公有金鑰傳遞到 RSA 簽章驗證演算法。如果輸出為 true，則簽署檔案的簽章已經過驗證且簽署檔案有效。

#### F. 驗證查詢結果檔案
<a name="cloudtrail-results-file-custom-validation-steps-validate-log-files"></a>

驗證簽署檔案之後，您可以驗證其所參考的查詢結果檔案。簽署檔案包含查詢結果檔案的 SHA-256 雜湊。如果其中一個查詢結果檔案在 CloudTrail 交付後已修改，SHA-256 雜湊將會變更，因此簽署檔案的簽章將會不符。

使用以下程序來驗證簽署檔案的 `files` 陣列中列出的查詢結果檔案。

1. 從簽署檔案中的 `files.fileHashValue` 欄位擷取檔案的原始雜湊。

1. 使用 `hashAlgorithm` 中指定的雜湊演算法，將查詢結果檔案的壓縮內容進行雜湊。

1. 將您為每個查詢結果檔案產生的雜湊值與簽署檔案中的 `files.fileHashValue` 進行比較。如果雜湊相符，則查詢結果檔案有效。

### 離線驗證簽章和查詢結果檔案
<a name="cloudtrail-results-file-custom-validation-offline"></a>

離線驗證簽署和查詢結果檔案時，您通常可以遵循先前章節中所述的程序。不過，您必須考慮以下有關公有金鑰的資訊。

#### 公有金鑰
<a name="cloudtrail-results-file-custom-validation-offline-public-keys"></a>

若要離線驗證，您必須先在線上取得在指定時間範圍內驗證查詢結果檔案所需的公有金鑰 (例如藉由呼叫 `ListPublicKeys`)，然後存放在離線位置。每當您想要在指定的初始時間範圍外驗證其他檔案時，都必須重複此步驟。

### 範例驗證程式碼片段
<a name="cloudtrail-results-file-custom-validation-sample-code"></a>

下列範例程式碼片段提供驗證 CloudTrail 簽署和查詢結果檔案的骨架程式碼。此骨架程式碼線上/離線皆可使用；也就是說，您可以決定是否要線上連線到 AWS來實作它。建議的實作使用 [Java Cryptography Extension (JCE)](https://en.wikipedia.org/wiki/Java_Cryptography_Extension) 和 [Bouncy Castle](https://www.bouncycastle.org/) 做為安全供應商。

此範例程式碼片段說明：
+ 如何建立用來驗證簽署檔案簽章的資料簽署字串。
+ 如何驗證簽署檔案的簽章。
+ 如何計算查詢結果檔案的雜湊值，並將其與簽署檔案中列出的 `fileHashValue` 進行比較，以驗證查詢結果檔案的真實性。

```
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONArray;
import org.json.JSONObject;
 
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
 
public class SignFileValidationSampleCode {
 
    public void validateSignFile(String s3Bucket, String s3PrefixPath) throws Exception {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
 
        // Load the sign file from S3 (using Amazon S3 Client) or from your local copy
        JSONObject signFile = loadSignFileToMemory(s3Bucket, String.format("%s/%s", s3PrefixPath, "result_sign.json"));
 
        // Using the Bouncy Castle provider as a JCE security provider - http://www.bouncycastle.org/
        Security.addProvider(new BouncyCastleProvider());
 
        List<String> hashList = new ArrayList<>();
 
        JSONArray jsonArray = signFile.getJSONArray("files");
 
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject file = jsonArray.getJSONObject(i);
            String fileS3ObjectKey = String.format("%s/%s", s3PrefixPath, file.getString("fileName"));
 
            // Load the export file from S3 (using Amazon S3 Client) or from your local copy
            byte[] exportFileContent = loadCompressedExportFileInMemory(s3Bucket, fileS3ObjectKey);
            messageDigest.update(exportFileContent);
            byte[] exportFileHash = messageDigest.digest();
            messageDigest.reset();
            byte[] expectedHash = Hex.decodeHex(file.getString("fileHashValue"));
 
            boolean signaturesMatch = Arrays.equals(expectedHash, exportFileHash);
            if (!signaturesMatch) {
                System.err.println(String.format("Export file: %s/%s hash doesn't match.\tExpected: %s Actual: %s",
                        s3Bucket, fileS3ObjectKey,
                        Hex.encodeHexString(expectedHash), Hex.encodeHexString(exportFileHash)));
            } else {
                System.out.println(String.format("Export file: %s/%s hash match",
                        s3Bucket, fileS3ObjectKey));
            }
 
            hashList.add(file.getString("fileHashValue"));
        }
        String hashListString = hashList.stream().collect(Collectors.joining(" "));
 
        /*
            NOTE:
            To find the right public key to verify the signature, call CloudTrail ListPublicKey API to get a list
            of public keys, then match by the publicKeyFingerprint in the sign file. Also, the public key bytes
            returned from ListPublicKey API are DER encoded in PKCS#1 format:
 
            PublicKeyInfo ::= SEQUENCE {
                algorithm       AlgorithmIdentifier,
                PublicKey       BIT STRING
            }
 
            AlgorithmIdentifier ::= SEQUENCE {
                algorithm       OBJECT IDENTIFIER,
                parameters      ANY DEFINED BY algorithm OPTIONAL
            }
        */
        byte[] pkcs1PublicKeyBytes = getPublicKey(signFile.getString("queryCompleteTime"),
                signFile.getString("publicKeyFingerprint"));
        byte[] signatureContent = Hex.decodeHex(signFile.getString("hashSignature"));
 
        // Transform the PKCS#1 formatted public key to x.509 format.
        RSAPublicKey rsaPublicKey = RSAPublicKey.getInstance(pkcs1PublicKeyBytes);
        AlgorithmIdentifier rsaEncryption = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null);
        SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(rsaEncryption, rsaPublicKey);
 
        // Create the PublicKey object needed for the signature validation
        PublicKey publicKey = KeyFactory.getInstance("RSA", "BC")
                .generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
 
        // Verify signature
        Signature signature = Signature.getInstance("SHA256withRSA", "BC");
        signature.initVerify(publicKey);
        signature.update(hashListString.getBytes("UTF-8"));
 
        if (signature.verify(signatureContent)) {
            System.out.println("Sign file signature is valid.");
        } else {
            System.err.println("Sign file signature failed validation.");
        }
 
        System.out.println("Sign file validation completed.");
    }
}
```