From a60b61ca5c675490361ee745e7cb571eb5728be3 Mon Sep 17 00:00:00 2001 From: gtebrean <99179176+gtebrean@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:28:32 +0300 Subject: [PATCH 1/2] add kms implementation Signed-off-by: gtebrean <99179176+gtebrean@users.noreply.github.com> --- build.gradle | 1 + core/build.gradle | 1 + .../service/HSMAwsKMSRequestProcessor.java | 104 ++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 core/src/main/java/org/web3j/service/HSMAwsKMSRequestProcessor.java diff --git a/build.gradle b/build.gradle index 2a3cee087..3a8593914 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,7 @@ ext { picocliVersion = '4.7.6' ensAdraffyVersion = '0.2.0' kzg4844Version = '2.0.0' + awsSdkVersion = '2.27.24' tuweniVersion = '2.4.2' // test dependencies equalsverifierVersion = '3.16.1' diff --git a/core/build.gradle b/core/build.gradle index 72799e6bc..789bdf662 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -21,6 +21,7 @@ dependencies { "io.github.adraffy:ens-normalize:$ensAdraffyVersion", "io.tmio:tuweni-bytes:$tuweniVersion", "io.tmio:tuweni-units:$tuweniVersion" + implementation "software.amazon.awssdk:kms:$awsSdkVersion" testImplementation project(path: ':crypto', configuration: 'testArtifacts'), "nl.jqno.equalsverifier:equalsverifier:$equalsverifierVersion", "ch.qos.logback:logback-classic:$logbackVersion" diff --git a/core/src/main/java/org/web3j/service/HSMAwsKMSRequestProcessor.java b/core/src/main/java/org/web3j/service/HSMAwsKMSRequestProcessor.java new file mode 100644 index 000000000..f90a5df88 --- /dev/null +++ b/core/src/main/java/org/web3j/service/HSMAwsKMSRequestProcessor.java @@ -0,0 +1,104 @@ +/* + * Copyright 2024 Web3 Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.web3j.service; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.services.kms.KmsClient; +import software.amazon.awssdk.services.kms.model.MessageType; +import software.amazon.awssdk.services.kms.model.SignRequest; +import software.amazon.awssdk.services.kms.model.SigningAlgorithmSpec; +import software.amazon.awssdk.services.kms.model.VerifyRequest; + +import org.web3j.crypto.CryptoUtils; +import org.web3j.crypto.HSMPass; +import org.web3j.crypto.Sign; + +/** + * HSM request processor for AWS KMS. Notice the KMS key must be ECC_SECG_P256K1, this key is + * supported in crypto space. + */ +public class HSMAwsKMSRequestProcessor implements HSMRequestProcessor { + + private KmsClient kmsClient; + private String keyID; + + public HSMAwsKMSRequestProcessor(KmsClient kmsClient, String keyID) { + this.kmsClient = kmsClient; + this.keyID = keyID; + } + + /** + * Entry point method which creates the KMS sign request + * + * @param dataToSign - data to be signed + * @param pass - public key of the asymmetric KMS key pair used for signing The @{@link + * org.web3j.crypto.HSMPass} should be instantiated before this method call. Use the + * following code for getting and setting the public key: + *
byte[] rawPublicKey = KmsClient.create() .getPublicKey((var builder) -> { + * builder.keyId(kmsKeyId); }) .publicKey() .asByteArray(); + *
byte[] publicKey = SubjectPublicKeyInfo .getInstance(rawPublicKey) .getPublicKeyData() + * .getBytes(); + *
BigInteger publicKey = new BigInteger(1, Arrays.copyOfRange(publicKey, 1, + * publicKey.length)); + *
HSMPass pass = new HSMPass(null, publicKey); + * @return SignatureData v | r | s + */ + @Override + public Sign.SignatureData callHSM(byte[] dataToSign, HSMPass pass) { + byte[] dataHash = new byte[0]; + try { + dataHash = MessageDigest.getInstance("SHA-256").digest(dataToSign); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException( + "Algorithm SHA-256 is not available for the given data!"); + } + + // Create the SignRequest for AWS KMS + var signRequest = + SignRequest.builder() + .keyId(keyID) + .message(SdkBytes.fromByteArray(dataHash)) + .messageType(MessageType.DIGEST) + .signingAlgorithm(SigningAlgorithmSpec.ECDSA_SHA_256) + .build(); + + // Sign the data using AWS KMS + var signResult = kmsClient.sign(signRequest); + var signatureBuffer = signResult.signature().asByteBuffer(); + + // Convert the signature to byte array + var signBytes = new byte[signatureBuffer.remaining()]; + signatureBuffer.get(signBytes); + + // Verify signature on KMS + var verifyRequest = + VerifyRequest.builder() + .keyId(keyID) + .message(SdkBytes.fromByteArray(dataHash)) + .messageType(MessageType.DIGEST) + .signingAlgorithm(SigningAlgorithmSpec.ECDSA_SHA_256) + .signature(SdkBytes.fromByteArray(signBytes)) + .build(); + + var verifyRequestResult = kmsClient.verify(verifyRequest); + if (!verifyRequestResult.signatureValid()) { + throw new RuntimeException("KMS signature is not valid!"); + } + + var signature = CryptoUtils.fromDerFormat(signBytes); + return Sign.createSignatureData(signature, pass.getPublicKey(), dataHash); + } +} From cca45d145d98ebc2b807e616a69120133a4704b8 Mon Sep 17 00:00:00 2001 From: gtebrean <99179176+gtebrean@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:19:45 +0300 Subject: [PATCH 2/2] update changelog Signed-off-by: gtebrean <99179176+gtebrean@users.noreply.github.com> --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef524c732..657fe2ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Features * bump snapshot version to 4.12.3 [#2101](https://github.com/hyperledger/web3j/pull/2101) +* Add HSM kms implementation [#2105](https://github.com/hyperledger/web3j/pull/2105) ### BREAKING CHANGES