AWS开发工具包KMS - 在Nodejs中加密并在Java中解密

时间:2018-03-26 14:41:08

标签: java node.js

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

当它们解密各自的加密消息(带有NodeJ的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 app的例外:

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中的加密不需要主密钥(我不确定这是否是问题)。

1 个答案:

答案 0 :(得分:0)

我相信我找到了解决方案。该问题与编码/解码字符串有关,而不是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中找到了我的解决方案。