带数据密钥的 AWS 加密 SDK Encrypt/Decrypt

AWS Encryption SDK Encrypt/Decrypt with Data Key

我正在尝试使用 KMS 和 AWS 加密 SDK 加密数据。查看 AWS documentation 中提供的示例,似乎没有地方可以显式设置数据键。

我找到了 API EncryptionMaterialsRequest class 的文档,它允许您使用关联的构建器 class、EncryptionMaterialsRequest.Builder 设置明文密钥,而这个 class 有一个方法 returns EncryptionMaterials 的一个实例。在执行加密操作时,我找不到任何地方可以使用 EncryptionMaterials 实例。

这是我目前的代码。请注意,请求中未使用 EncryptionMaterials 实例。

public static void encryptData(String dataToEncrypt, String keyID) {
    final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyID);
    DefaultCryptoMaterialsManager manager = new DefaultCryptoMaterialsManager(prov);

    byte[] plaintextKey = generateDataKey(keyID);
    EncryptionMaterialsRequest request = EncryptionMaterialsRequest
        .newBuilder()
        .setPlaintext(plaintextKey)
        .build();

    EncryptionMaterials materials = manager.getMaterialsForEncrypt(request);
    AwsCrypto crypto = new AwsCrypto();
    String encryptedString = crypto.encryptString(manager, dataToEncrypt).getResult();
}

public byte[] generateDataKey(String keyID) {
    GenerateDataKeyRequest dataKeyRequest = new GenerateDataKeyRequest();
    dataKeyRequest.setKeyId(keyID);
    dataKeyRequest.setKeySpec(DataKeySpec.AES_256);
    GenerateDataKeyResult dataKeyResult = kmsClient.generateDataKey(dataKeyRequest);
    ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();
    byte[] arr = new byte[encryptedKey.remaining()];
    encryptedKey.get(arr);
    return arr;
}

使用 AWS 加密 SDK 和 KMS 生成的数据密钥来加密数据的推荐方法是什么?

我的问题是:为什么不使用 DefaultCryptoMaterialsManager,它应该为每个加密操作从主密钥生成一个新的数据密钥?你为什么要重用数据密钥?从安全角度来看,这听起来不像是一种合理的方法。

但是如果你想这样做,你需要提供 CryptoMaterialsManager 接口的实现。

不使用 DefaultCryptoMaterialsManager,而是创建一个新的 class,比方说 MyCryptoMaterialsManager,它实现了上面的接口。

像这样就可以了:

public static void encryptData(String dataToEncrypt, String keyID) {
    // not sure whether you need this or where you're getting the data key from.
    final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyID);
    MyCryptoMaterialsManager manager = new MyCryptoMaterialsManager(prov);

    byte[] plaintextKey = generateDataKey(keyID);
    EncryptionMaterialsRequest request = EncryptionMaterialsRequest
        .newBuilder()
        .setPlaintext(plaintextKey)
        .build();

    // this, you told you know how to do:
    EncryptionMaterials materials = manager.getMaterialsForEncrypt(request);
    AwsCrypto crypto = new AwsCrypto();
    String encryptedString = crypto.encryptString(manager, dataToEncrypt).getResult();
}

public byte[] generateDataKey(String keyID) {
    GenerateDataKeyRequest dataKeyRequest = new GenerateDataKeyRequest();
    dataKeyRequest.setKeyId(keyID);
    dataKeyRequest.setKeySpec(DataKeySpec.AES_256);
    GenerateDataKeyResult dataKeyResult = kmsClient.generateDataKey(dataKeyRequest);
    ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();
    byte[] arr = new byte[encryptedKey.remaining()];
    encryptedKey.get(arr);
    return arr;
}

如果对 KMS 的调用成本或次数有顾虑,您也可以改用 CachingCryptoMaterialsManager。它提供保证,例如确保数据密钥不会被无限次使用。

@Viccari 是正确的,但听起来围绕这些结构的预期用途的一些上下文有助于解释原因。

除非您正在构建自定义加密材料管理器,否则您不应该创建 EncryptionMaterials;客户端和管理组件会为您处理。

客户端在每次加密调用时都向加密材料管理器询问加密材料。根据加密材料管理器的不同,接下来发生的事情可能会有所不同。

DefaulCryptoMaterialsManager 的情况下,它会向提供的主密钥提供者询问所有要使用的主密钥,然后使用这些主密钥生成和加密数据密钥(一个用于生成并加密,任何额外的都用于加密)。

CachingCryptoMaterialsManager 的情况下,它在客户端和另一个加密材料管理器之间添加了一个缓存层。

如果您想将 AWS 加密 SDK 与 AWS KMS 一起使用,推荐的方法是简单地提供 KmsMasterKeyKmsMasterKeyProvider 的实例,或者最终使用以下之一的加密材料管理器那些,在加密调用中。所有的细节都由客户负责。

如果您对这些概念如何结合在一起的更多细节感兴趣,我们的概念文档[1] 将是一个很好的起点。

[1] https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html