У меня есть объект, который я успешно зашифровал с помощью ключа 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?