0
import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.regions.Regions; import com.amazonaws.services.kms.AWSKMS; import com.amazonaws.services.kms.AWSKMSClientBuilder; import com.amazonaws.services.kms.model.GetPublicKeyRequest; import com.amazonaws.services.kms.model.SignRequest; import com.amazonaws.util.BinaryUtils; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import org.junit.Test; import org.web3j.crypto.ECDSASignature; import org.web3j.crypto.Hash; import org.web3j.crypto.Keys; import org.web3j.crypto.Sign; import java.io.IOException; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.\*; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; @Slf4j public class AwsKmsTest { private static final String keyId = "****"; AWSKMS kmsClient = AWSKMSClientBuilder.standard() .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("****", "*****"))) .withRegion(Regions.AP_NORTHEAST_1) .build(); static { if (Security.getProvider("BC") == null) { Security.addProvider(new BouncyCastleProvider()); } } @Test public void publicKey() throws Exception { BCECPublicKey publicKey = (BCECPublicKey) getPublicKey(); System.out.println(Keys.getAddress(pubKeyToBigInter(publicKey))); } @Test public void sign() throws Exception { String msg = "hi"; byte[] Bytes = msg.getBytes(StandardCharsets.UTF_8); byte[] digestBytes = MessageDigest.getInstance("SHA-256").digest(Bytes); SignRequest signRequest = new SignRequest(); signRequest.setKeyId(keyId); signRequest.setMessage(ByteBuffer.wrap(digestBytes)); signRequest.setMessageType("DIGEST"); signRequest.setSigningAlgorithm("ECDSA_SHA_256"); ByteBuffer signatureB = kmsClient.sign(signRequest).getSignature(); BCECPublicKey publicKey = (BCECPublicKey) getPublicKey(); Signature signature = Signature.getInstance("SHA256withECDSA"); signature.initVerify(publicKey); signature.update(Bytes); if (signature.verify(signatureB.array())) { ECDSASignature ecdsaSignature = parseDERSequence(signatureB.array()); //throw exception:Could not construct a recoverable key. Are your credentials valid? Sign.SignatureData signMessage = Sign.createSignatureData(ecdsaSignature, pubKeyToBigInter(publicKey), Hash.sha3(Bytes)); System.out.println("0x" + Hex.toHexString(signMessage.getR()) + Hex.toHexString(signMessage.getS()) + Hex.toHexString(signMessage.getV())); } } public static BigInteger pubKeyToBigInter(BCECPublicKey publicKey) { byte[] publicKeyBytes = publicKey.getQ().getEncoded(false); return new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.length)); } public PublicKey getPublicKey() throws Exception { GetPublicKeyRequest publicKeyRequest = new GetPublicKeyRequest(); publicKeyRequest.setKeyId(keyId); ByteBuffer publicKeyByteBuffer = kmsClient.getPublicKey(publicKeyRequest).getPublicKey(); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(BinaryUtils.copyBytesFrom(publicKeyByteBuffer)); KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC"); return keyFactory.generatePublic(keySpec); } private ECDSASignature parseDERSequence(byte[] derEncoded) throws IOException { ASN1InputStream asn1InputStream = new ASN1InputStream(derEncoded); ASN1Sequence asn1Sequence = (ASN1Sequence) asn1InputStream.readObject(); ASN1Integer r = (ASN1Integer) asn1Sequence.getObjectAt(0); ASN1Integer s = (ASN1Integer) asn1Sequence.getObjectAt(1); BigInteger rValue = r.getPositiveValue(); BigInteger sValue = s.getPositiveValue(); return new ECDSASignature(rValue, sValue); } } 

Sign.createSignatureData(ecdsaSignature,pubKeyToBigInter(publicKey),Hash.sha3(Bytes)); throw a exception:Could not construct a recoverable key. Are your credentials valid?

It can be roughly confirmed that the method parseDERSequence returns incorrect f and s values, resulting in failure. Does anyone know how to solve it

1 Answer 1

0

Make sure to specify MessageType: 'DIGEST' in the KMS.SignRequest, otherwise, AWS will try to hash your payload again which will generate an invalid signature. The payload needs to be a keccak256 hash of your transaction object.

byte[] Bytes = msg.getBytes(StandardCharsets.UTF_8); byte[] digestBytes = MessageDigest.getInstance("SHA-256").digest(Bytes);

Replace with

byte[] Bytes = Hash.sha3(msg.getBytes(StandardCharsets.UTF_8)); 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.