java - AWS SDK KMS - 在 Nodejs 中加密并在 Java 中解密

标签 java node.js

我正在尝试实现 2 个库(一个在 NodeJS 中,一个在 Java 中),它们使用 AWS (KMS) SDK 来加密/解密消息。

这些库在解密各自的加密消息(NodeJS 与 NodeJs,Java 与 Java)时工作正常,但它们似乎无法跨工作(Java 不会解密来自 NodeJS 加密的消息)。

NodeJS 加密:

const AWS = require('aws-sdk');
AWS.config.update({ accessKeyId: "accessKeyId", secretAccessKey: 
"secretAccessKey", region: "region" });
const kms = new AWS.KMS();

kms.encrypt({ KeyId: "keyId", Plaintext: new Buffer("test") }, function(e, r) {
  var ciphertext = r.CiphertextBlob.toString('base64');
  console.log(ciphertext); // Encrypted text that I pass to the Java app
});

Java解密

String ciphertext = "AQICAHgNtyEjB2bL8hp2NFe7fpccIFlXKOSWuRIz5BUh/benwAFK9A0/tAYzltvC9ZaxXzuAAAAAYjBgBgkqhkiG9w0BBwagUzBRAgEAMEwGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMv/wGmK/7D5XaNHvJAgEQgB/+lCCHK2TBIeECV+8B7Msvrrw5ntxCvARWerzccsMB"; // From NodeJs encryption

BasicAWSCredentials bas = new BasicAWSCredentials("accessKeyId", "secretAccessKey");
AWSCredentialsProvider provider = new AWSStaticCredentialsProvider(bas);
AWSKMS client = AWSKMSClientBuilder.standard().withCredentials(provider).withRegion("region").build();

ByteBuffer encodedBytes = java.util.Base64.getEncoder().encode(ByteBuffer.wrap(ciphertext.getBytes()));
DecryptRequest request = new DecryptRequest().withCiphertextBlob(encodedBytes);

// Tried this alternative way, still fails
//DecryptRequest request = new DecryptRequest().withCiphertextBlob(ByteBuffer.wrap(ciphertext.getBytes()));

DecryptResult response = client.decrypt(request); // This throws the exception

Java 应用程序的异常:

Caused by: com.amazonaws.services.kms.model.InvalidCiphertextException: null (Service: AWSKMS; Status Code: 400; Error Code: InvalidCiphertextException; Request ID: 9a727296-3101-11e8-907e-d5bf28c7a5b5)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1630) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1302) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1056) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:743) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:717) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513) ~[aws-java-sdk-core-1.11.301.jar:na]
at com.amazonaws.services.kms.AWSKMSClient.doInvoke(AWSKMSClient.java:2741) ~[aws-java-sdk-kms-1.11.18.jar:na]
at com.amazonaws.services.kms.AWSKMSClient.invoke(AWSKMSClient.java:2711) ~[aws-java-sdk-kms-1.11.18.jar:na]
at com.amazonaws.services.kms.AWSKMSClient.decrypt(AWSKMSClient.java:886) ~[aws-java-sdk-kms-1.11.18.jar:na]
at com.amway.na.utility.general.AwsEncryption.decrypt(AwsEncryption.java:92) ~[Utility-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at com.amway.na.utility.general.AwsEncryption.decrypt(AwsEncryption.java:72) ~[Utility-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at com.amway.na.kafka.consumer.configuration.KafkaMessageListener.receive(KafkaMessageListener.java:45) ~[kafka-event-consumer-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at com.amway.na.kafka.consumer.configuration.KafkaMessageListener$$FastClassBySpringCGLIB$$7611f8fa.invoke(<generated>) ~[kafka-event-consumer-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at com.amway.na.kafka.consumer.configuration.KafkaConsumerListenerExecutionTimeLoggingAspect.logTime(KafkaConsumerListenerExecutionTimeLoggingAspect.java:29) ~[kafka-event-consumer-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at com.amway.na.kafka.consumer.configuration.KafkaMessageListener$$EnhancerBySpringCGLIB$$174059f9.receive(<generated>) ~[kafka-event-consumer-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:180) ~[spring-messaging-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:112) ~[spring-messaging-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48) ~[spring-kafka-1.1.7.RELEASE.jar:na]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:174) ~[spring-kafka-1.1.7.RELEASE.jar:na]
... 8 common frames omitted

在使用AWSKMS客户端之前,我使用AwsCryptoKmsMasterKeyProvider,但后来我在网上看到它们的加密不兼容。

这可能是 Base64 编码问题:我尝试了 2 个解决方案(请参阅上面的评论),但没有成功。

我不明白的一件事是为什么 Java 中的加密不需要主 key (我不确定这是否是问题所在)。

最佳答案

我相信我找到了解决方案。该问题与字符串的编码/解码有关,而不是 SDK 之间的兼容性。

为了使 Java 应用程序正常工作,您必须确保正确编码/解码明文(和密文)。

以下是我在 Java 中修复解密的方法:

//.... omitted
    ByteBuffer buffer = getByteBuffer(ciphertext);
    DecryptRequest decryptRequest = new DecryptRequest().withCiphertextBlob(buffer);
    DecryptResult decryptResult = client.decrypt(decryptRequest);
    String plaintext = getString(decryptResult.getPlaintext());
//.... omitted

这里是加密,如果您想了解它是如何在 Java 中完成的(请注意 Base64 编码部分):

//.... omitted
    ByteBuffer byteBuffer = getByteBuffer(plaintext);
    EncryptRequest encryptRequest = new EncryptRequest().withKeyId(keyId"").withPlaintext(byteBuffer);
    EncryptResult encryptResult = client.encrypt(encryptRequest);
    String ciphertext = getString(java.util.Base64.getEncoder().encode(encryptResult.getCiphertextBlob()));
//.... omitted

这些辅助函数是从 String 转换为 ByteBuffer 的关键,反之亦然(我问题的根本原因):

private String getString(ByteBuffer byteBuffer) {
    byte[] bytes = new byte[byteBuffer.remaining()];
    byteBuffer.get(bytes);
    return new String(bytes);
}

private ByteBuffer getByteBuffer(String string) {
    byte[] bytes = java.util.Base64.getDecoder().decode(string);
    ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
    byteBuffer.put(bytes);
    byteBuffer.flip();

    return byteBuffer;
}

我在这些示例中找到了我的解决方案 DecryptEncrypt .

关于java - AWS SDK KMS - 在 Nodejs 中加密并在 Java 中解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49494164/

相关文章:

javascript - 在 pg-promise 中使用助手时如何设置列

node.js - 如何用密码保护 Node/Express 中的静态 Assets ?

Java 8 : Reading a file into a String

java - 日期时间字段 validator

java - 从 1.8 迁移到 openJDK11 时如何解决 "sun.security.x509"不可见问题?

node.js - 如何将新元素推送到子文档中“发布”>“评论”>“回复”>“喜欢”作为数组

Node.js Express + Busboy 文件类型检查

sql - Node.JS 与 NoSQL 还是 SQL?

java - JPQL Eclipselink - 如何连接两个表并显示另一个表中没有项目的项目

java - 格式化没有年份的日期