Как развернуть встроенный ключ данных S3 в Node.js?

У меня есть объект, который я успешно зашифровал с помощью ключа Amazon Web Services (KMS), а затем сохранил его в корзине S3. Все это отлично работает с Java, включая чтение и расшифровку, но Node.js не знает, как обрабатывать встроенный ключ данных, который AWS создает с объектом S3.

Это работает (Java):

 public class Cryptotest {
    final AwsCrypto crypto = new AwsCrypto();
    private final Logger logger = Logger.getLogger(getClass().getName());
    final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(System.getenv("AesKey"));

    public void doWrite() {
        AmazonS3 s3Client = AmazonS3ClientBuilder.standard().build();
        String contents = "Hello world from KMS-encrypted file!";
        final Map<String, String> context = Collections.singletonMap(System.getenv("KeyContext"),
                System.getenv("KeyValue"));

        final byte[] ciphertext = crypto.encryptData(prov, contents.getBytes(), context).getResult();

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
        metadata.setContentLength(ciphertext.length);

        if (!s3Client.doesObjectExist(System.getenv("Bucket"), System.getenv("Path"))) {
            PutObjectRequest writeMe = new PutObjectRequest(System.getenv("Bucket"), System.getenv("Path"),
                    new ByteArrayInputStream(ciphertext), metadata);
            s3Client.putObject(writeMe);
        } else {
            logger.debug("Object already exists, will not overwrite!");
        }

    }

    public void doWork() throws IOException {
        AmazonS3 s3Client = AmazonS3ClientBuilder.standard().build();
        S3Object xFile = s3Client.getObject(System.getenv("Bucket"), System.getenv("Path"));

        logger.debug("Got S3 object");
        InputStream fileContents = xFile.getObjectContent();
        byte[] read_buf = new byte[1024];
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        int read_len = 0;
        while ((read_len = fileContents.read(read_buf)) > 0) {
            os.write(read_buf, 0, read_len);
        }
        fileContents.close();
        logger.debug("Read object contents");
        logger.debug(os.toString(StandardCharsets.UTF_8.name()));

        CryptoResult<byte[], KmsMasterKey> decryptResult = crypto.decryptData(prov, os.toByteArray());
        logger.debug("Decrypted object");
        if (!decryptResult.getMasterKeyIds().get(0).equals(System.getenv("AesKey"))) {
            throw new IllegalStateException("Wrong key ID!");
        }
        logger.debug("Verified object contents");
        final Map<String, String> context = Collections.singletonMap(System.getenv("KeyContext"),
                System.getenv("KeyValue"));
        logger.debug("Created encryption context map");

        // Also, verify that the encryption context in the result contains the
        // encryption context supplied to the encryptString method. Because the
        // SDK can add values to the encryption context, don't require that
        // the entire context matches.
        for (final Map.Entry<String, String> e : context.entrySet()) {
            if (!e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey()))) {
                throw new IllegalStateException("Wrong Encryption Context!");
            }
        }

        logger.debug("Finished decrypting object");

        logger.debug(new String(decryptResult.getResult()));

    }
}

Это вызывает InvalidCiphertextException (Node.js) из-за (я думаю) встроенного ключа данных. Я пробовал разные перестановки toString, Buffer и тип декодирования (двоичный, ascii и т. д.) с той же ошибкой:

return s3.getObject(keyParams).promise()
    .then(encryptedAesKey => {
      var cipherParams = {
        CiphertextBlob: new Buffer(encryptedAesKey.Body, 'base64'),
        EncryptionContext: {
          "KeyContext": "KeyValue"
        }
      };
      return kms.decrypt(cipherParams).promise();
    })

Я почти уверен, что проблема связана со встроенным ключом данных, потому что, когда я отправляю содержимое объекта S3 на консоль, я вижу в открытом тексте имя ключа данных (среди множества представлений Unicode двоичных данных), как это:

arn:aws:kms:us-east-1:XXXXXXXXX:key/YYYYY-YYYYYY-YYYYYYYY

Я не вижу этого в файлах S3, зашифрованных из Node.js. Java документация относится к распаковке ключа данных:

AwsCrypto.decryptData(MasterKeyProvider<K> provider, byte[] ciphertext)

Расшифровывает предоставленный зашифрованный текст, запрашивая у провайдера распаковку любого пригодного для использования DataKey в зашифрованном тексте, а затем расшифровывает зашифрованный текст с помощью этого DataKey.

Как извлечь ключ данных из объекта S3 с помощью Node.js?


person MattW    schedule 16.02.2018    source источник


Ответы (1)


AWS получает признание за ответ на этот вопрос:

Этот Java-код использует SDK AWS Encryption[1], а не напрямую KMS.

К сожалению, в настоящее время у нас нет реализации NodeJS для AWS Encryption SDK.

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

person MattW    schedule 16.02.2018