【问题标题】:AWS S3 Java SDK - Downloading an encrypted GetObject by Stream of a Selling Partner (SP) API urlAWS S3 Java SDK - 通过销售伙伴 (SP) API url 的流下载加密的 GetObject
【发布时间】:2021-05-21 14:07:31
【问题描述】:

我最近开始使用 SellingPartner (SP),我很困惑他们如何为我们提供 S3 报告以供下载。

当我从 SP API 获取报告文档时,我得到这个返回(省略):

GetReportDocumentResponse class:
{
  "payload": {
    "reportDocumentId": "amzn1.tortuga.3.OMITTED.OMITTED",
    "url": "https://tortuga-prod-na.s3-external-1.amazonaws.com/%2FOMITED/amzn1.tortuga.3.OMITTED.OMITTED?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20201025T163212Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=OMITED%2F20201025%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=OMITED",
    "encryptionDetails": {
      "standard": "AES",
      "initializationVector": "OMITED==",
      "key": "+OMITED="
    },
    "compressionAlgorithm": null
  },
  "errors": null
}

如果我直接在浏览器中复制/粘贴payload.url,它会下载一个看起来不错的加密文档(虽然我无法解密它,最后是sn-p)。

我正在尝试使用 AWS S3 Java SDK 下载,但我不断收到software.amazon.awssdk.services.s3.model.S3Exception: Access Denied

我有这个sn-p:

public String getReportFile(String reportDocumentId) throws IOException {
    GetReportDocumentResponse response = getReport(reportDocumentId);
    ReportDocumentEncryptionDetails encryptionDetails = response.getPayload().getEncryptionDetails();
    
    GetObjectRequest request =
        GetObjectRequest.builder()
            .key(reportDocumentId)
            .bucket("tortuga-prod-na") //hardcoding here, thats the bucket on the URL, right?
            .sseCustomerAlgorithm(encryptionDetails.getStandard())
            .sseCustomerKey(encryptionDetails.getKey())
            // .sseCustomerKeyMD5() should I apply it? Is that the Initialization Vector field?
            .build();
    
//I tried both without Credentials, and using accessKey and secretKey from my personal account, not sure if should be another one related to the URL, what should I use for credentials if the URL works fine in my browser?
    StaticCredentialsProvider credentialsProvider =
        StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, secretKey));
    BufferedReader br =
        new BufferedReader(
            new InputStreamReader(
                S3Client.builder()
                    .credentialsProvider(credentialsProvider)
                    .region(Region.US_EAST_1)
                    .build()
                    .getObject(request)));
    

我的最终目标是分块下载这个文件(因为它可能超过 500mb)并一次处理几百行。如果它是加密的,这可能吗?我想下载它已经解密并能够分块处理。

我想知道如何使用 S3Client 发出相同的请求,例如来自 JSON 的 URL。我们有办法在 S3Client 上粘贴 URL,包括加密设置并拨打电话吗?

关于从浏览器下载的文件,我尝试解密它:

byte[] bytes = FileUtils.readFileToByteArray(new File("encrypted_file"));

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(<payload.encryptionDetails.key String value>), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
System.out.println(new String(cipher.doFinal(bytes)));

抛出异常: Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

提前致谢。

【问题讨论】:

    标签: java amazon-web-services amazon-s3 encryption


    【解决方案1】:

    如果我直接在浏览器中复制/粘贴payload.url,它会下载一个加密的文档,看起来很好(虽然我无法解密,最后是sn-p)。

    这意味着该对象没有使用 SSE-C,否则您将无法下载它。似乎内容在客户端(在 s3 api 之外)被加密,并且加密的内容作为普通对象上传。因此,请在您上传内容的代码中检查加密参数。

    如果您能够直接从浏览器下载对象,则只需将内容作为普通对象下载即可。

    注意:正确使用AWS S3 Client Side Encryption

    关于从浏览器下载的文件,我尝试这样做解密它

    无论您在何处获得此代码,请不要使用它。只使用AES/ECB/PKCS5PADDING 模式并不安全。

    使用 IV(initializationVector)意味着使用不同的encryption mode of operation。您必须从加密内容的代码或服务中找出是哪个。

    private static final String SYMMETRIC_KEY_ALG = "AES";
    // find out the correct value, could be AES/CBC/PKCS5Padding
    private static final String SYMMETRIC_CIPHER_NAME = "???";
    
    IvParameterSpec ivParamSpec = new IvParameterSpec(encryptionParams.getIv());
    SecretKey symmetricKey = new SecretKeySpec(encryptionParams.getKey(), SYMMETRIC_KEY_ALG);
    
    Cipher cipher = Cipher.getInstance(SYMMETRIC_CIPHER_NAME);
    cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivParamSpec);
    
    byte[] decrypted = cipher.doFinal(encryptionParams.getCiphertext());
    
    

    但是 - 您确实需要了解内容是如何加密的。可能使用 aes-gcm 模式,然后密文的一部分可以是身份验证哈希。所以在这里你不应该做假设并找到真实的数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      • 2021-08-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多