diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java index d6ed143411f..6c70f00b240 100644 --- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java +++ b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/EthereumAuthenticator.java @@ -188,14 +188,17 @@ public class EthereumAuthenticator extends LoginAuthenticator implements Dumpabl } /** - * This setting is only meaningful if a non-null {@link LoginService} has been set. + * Configures the behavior for authenticating users not found by a wrapped {@link LoginService}. *

- * If set to true, any users not found by the {@link LoginService} will still - * be authenticated but with no roles, if set to false users will not be - * authenticated unless they are discovered by the wrapped {@link LoginService}. + * This setting is only meaningful if a wrapped {@link LoginService} has been set. *

- * @param authenticateNewUsers whether to authenticate users not found by a wrapping LoginService - */ + *

+ * If set to {@code true}, users not found by a wrapped {@link LoginService} will authenticated with no roles. + * If set to {@code false}, only users found by a wrapped {@link LoginService} will be authenticated. + *

+ * + * @param authenticateNewUsers whether to authenticate users not found by the wrapped {@link LoginService} + **/ public void setAuthenticateNewUsers(boolean authenticateNewUsers) { this._authenticateNewUsers = authenticateNewUsers; @@ -817,4 +820,12 @@ public class EthereumAuthenticator extends LoginAuthenticator implements Dumpabl return super.add(element); } } + + public record SignedMessage(String message, String signature) + { + public String recoverAddress() + { + return EthereumUtil.recoverAddress(this); + } + } } diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/SignedMessage.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/SignedMessage.java deleted file mode 100644 index b54721fb3b3..00000000000 --- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/SignedMessage.java +++ /dev/null @@ -1,24 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty.security.siwe; - -import org.eclipse.jetty.security.siwe.internal.EthereumSignatureVerifier; - -public record SignedMessage(String message, String signature) -{ - public String recoverAddress() - { - return EthereumSignatureVerifier.recoverAddress(this); - } -} diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumSignatureVerifier.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumSignatureVerifier.java deleted file mode 100644 index 5595d359f5d..00000000000 --- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumSignatureVerifier.java +++ /dev/null @@ -1,139 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty.security.siwe.internal; - -import java.math.BigInteger; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -import org.bouncycastle.asn1.x9.X9ECParameters; -import org.bouncycastle.asn1.x9.X9IntegerConverter; -import org.bouncycastle.crypto.ec.CustomNamedCurves; -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.jcajce.provider.digest.Keccak; -import org.bouncycastle.math.ec.ECAlgorithms; -import org.bouncycastle.math.ec.ECPoint; -import org.eclipse.jetty.security.siwe.SignedMessage; -import org.eclipse.jetty.util.StringUtil; - -/** - * Used to recover an Ethereum address from a message and signature. - *

- * This uses algorithms and terminology defined in EIP-191 and - * ECDSA. - *

- */ -public class EthereumSignatureVerifier -{ - public static final String PREFIX = "\u0019Ethereum Signed Message:\n"; - - private static final int ADDRESS_LENGTH_BYTES = 20; - private static final X9ECParameters SEC_P256K1_PARAMS = CustomNamedCurves.getByName("secp256k1"); - private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters( - SEC_P256K1_PARAMS.getCurve(), SEC_P256K1_PARAMS.getG(), SEC_P256K1_PARAMS.getN(), SEC_P256K1_PARAMS.getH()); - private static final BigInteger PRIME = SEC_P256K1_PARAMS.getCurve().getField().getCharacteristic(); - private static final X9IntegerConverter INT_CONVERTER = new X9IntegerConverter(); - private static final Charset CHARSET = StandardCharsets.UTF_8; - - private EthereumSignatureVerifier() - { - } - - /** - * Recover the Ethereum Address from the {@link SignedMessage}. - * @param signedMessage the signed message used to recover the address. - * @return the ethereum address recovered from the signature. - */ - public static String recoverAddress(SignedMessage signedMessage) - { - String siweMessage = signedMessage.message(); - String signatureHex = signedMessage.signature(); - if (StringUtil.asciiStartsWithIgnoreCase(signatureHex, "0x")) - signatureHex = signatureHex.substring(2); - - int messageLength = siweMessage.getBytes(CHARSET).length; - String prefixedMessage = PREFIX + messageLength + siweMessage; - byte[] messageHash = keccak256(prefixedMessage.getBytes(CHARSET)); - byte[] signatureBytes = StringUtil.fromHexString(signatureHex); - - BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureBytes, 0, 32)); - BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureBytes, 32, 64)); - byte v = (byte)(signatureBytes[64] < 27 ? signatureBytes[64] : signatureBytes[64] - 27); - - ECPoint qPoint = ecRecover(messageHash, v, r, s); - if (qPoint == null) - return null; - return toAddress(qPoint); - } - - public static ECPoint ecRecover(byte[] hash, int v, BigInteger r, BigInteger s) - { - if (v < 0 || v >= 4) - throw new IllegalArgumentException("Invalid v value: " + v); - - // Verify that r and s are integers in [1, n-1]. If not, the signature is invalid. - BigInteger n = DOMAIN_PARAMS.getN(); - if (r.compareTo(BigInteger.ONE) < 0 || r.compareTo(n.subtract(BigInteger.ONE)) > 0) - return null; - if (s.compareTo(BigInteger.ONE) < 0 || s.compareTo(n.subtract(BigInteger.ONE)) > 0) - return null; - - // Calculate the curve point R. - BigInteger x = r.add(BigInteger.valueOf(v / 2).multiply(n)); - if (x.compareTo(PRIME) >= 0) - return null; - ECPoint rPoint = decodePoint(x, v); - if (!rPoint.multiply(n).isInfinity()) - return null; - - // Calculate the curve point Q = u1 * G + u2 * R, where u1=-zr^(-1)%n and u2=sr^(-1)%n. - // Note: for secp256k1 z=e as the hash is 256 bits and z is defined as the Ln leftmost bits of e. - BigInteger e = new BigInteger(1, hash); - BigInteger rInv = r.modInverse(n); - BigInteger u1 = e.negate().multiply(rInv).mod(n); - BigInteger u2 = s.multiply(rInv).mod(n); - return ECAlgorithms.sumOfTwoMultiplies(DOMAIN_PARAMS.getG(), u1, rPoint, u2); - } - - public static String toAddress(ECPoint point) - { - // Remove the 1-byte prefix and return the public key as an ethereum address. - byte[] qBytes = point.getEncoded(false); - byte[] qHash = keccak256(qBytes, 1, qBytes.length - 1); - byte[] address = new byte[ADDRESS_LENGTH_BYTES]; - System.arraycopy(qHash, qHash.length - ADDRESS_LENGTH_BYTES, address, 0, ADDRESS_LENGTH_BYTES); - return "0x" + StringUtil.toHexString(address); - } - - public static ECPoint decodePoint(BigInteger p, int v) - { - byte[] encodedPoint = INT_CONVERTER.integerToBytes(p, 1 + INT_CONVERTER.getByteLength(DOMAIN_PARAMS.getCurve())); - encodedPoint[0] = (byte)((v % 2) == 0 ? 0x02 : 0x03); - return DOMAIN_PARAMS.getCurve().decodePoint(encodedPoint); - } - - public static byte[] keccak256(byte[] bytes) - { - Keccak.Digest256 digest256 = new Keccak.Digest256(); - return digest256.digest(bytes); - } - - public static byte[] keccak256(byte[] buf, int offset, int len) - { - Keccak.Digest256 digest256 = new Keccak.Digest256(); - digest256.update(buf, offset, len); - return digest256.digest(); - } -} diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumUtil.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumUtil.java index e75b0370167..9e915f107fe 100644 --- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumUtil.java +++ b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/EthereumUtil.java @@ -13,17 +13,129 @@ package org.eclipse.jetty.security.siwe.internal; +import java.math.BigInteger; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.security.SecureRandom; +import java.util.Arrays; + +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.asn1.x9.X9IntegerConverter; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.jcajce.provider.digest.Keccak; +import org.bouncycastle.math.ec.ECAlgorithms; +import org.bouncycastle.math.ec.ECPoint; +import org.eclipse.jetty.security.siwe.EthereumAuthenticator; +import org.eclipse.jetty.util.StringUtil; public class EthereumUtil { + public static final String PREFIX = "\u0019Ethereum Signed Message:\n"; private static final String NONCE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static final SecureRandom RANDOM = new SecureRandom(); + private static final int ADDRESS_LENGTH_BYTES = 20; + private static final X9ECParameters SEC_P256K1_PARAMS = CustomNamedCurves.getByName("secp256k1"); + private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters( + SEC_P256K1_PARAMS.getCurve(), SEC_P256K1_PARAMS.getG(), SEC_P256K1_PARAMS.getN(), SEC_P256K1_PARAMS.getH()); + private static final BigInteger PRIME = SEC_P256K1_PARAMS.getCurve().getField().getCharacteristic(); + private static final X9IntegerConverter INT_CONVERTER = new X9IntegerConverter(); + private static final Charset CHARSET = StandardCharsets.UTF_8; private EthereumUtil() { } + /** + * Recover the Ethereum Address from the {@link EthereumAuthenticator.SignedMessage}. + *

+ * This uses algorithms and terminology defined in EIP-191 and + * ECDSA. + *

+ * @param signedMessage the signed message used to recover the address. + * @return the ethereum address recovered from the signature. + */ + public static String recoverAddress(EthereumAuthenticator.SignedMessage signedMessage) + { + String siweMessage = signedMessage.message(); + String signatureHex = signedMessage.signature(); + if (StringUtil.asciiStartsWithIgnoreCase(signatureHex, "0x")) + signatureHex = signatureHex.substring(2); + + int messageLength = siweMessage.getBytes(CHARSET).length; + String prefixedMessage = PREFIX + messageLength + siweMessage; + byte[] messageHash = keccak256(prefixedMessage.getBytes(CHARSET)); + byte[] signatureBytes = StringUtil.fromHexString(signatureHex); + + BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureBytes, 0, 32)); + BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureBytes, 32, 64)); + byte v = (byte)(signatureBytes[64] < 27 ? signatureBytes[64] : signatureBytes[64] - 27); + + ECPoint qPoint = ecRecover(messageHash, v, r, s); + if (qPoint == null) + return null; + return toAddress(qPoint); + } + + public static ECPoint ecRecover(byte[] hash, int v, BigInteger r, BigInteger s) + { + if (v < 0 || v >= 4) + throw new IllegalArgumentException("Invalid v value: " + v); + + // Verify that r and s are integers in [1, n-1]. If not, the signature is invalid. + BigInteger n = DOMAIN_PARAMS.getN(); + if (r.compareTo(BigInteger.ONE) < 0 || r.compareTo(n.subtract(BigInteger.ONE)) > 0) + return null; + if (s.compareTo(BigInteger.ONE) < 0 || s.compareTo(n.subtract(BigInteger.ONE)) > 0) + return null; + + // Calculate the curve point R. + BigInteger x = r.add(BigInteger.valueOf(v / 2).multiply(n)); + if (x.compareTo(PRIME) >= 0) + return null; + ECPoint rPoint = decodePoint(x, v); + if (!rPoint.multiply(n).isInfinity()) + return null; + + // Calculate the curve point Q = u1 * G + u2 * R, where u1=-zr^(-1)%n and u2=sr^(-1)%n. + // Note: for secp256k1 z=e as the hash is 256 bits and z is defined as the Ln leftmost bits of e. + BigInteger e = new BigInteger(1, hash); + BigInteger rInv = r.modInverse(n); + BigInteger u1 = e.negate().multiply(rInv).mod(n); + BigInteger u2 = s.multiply(rInv).mod(n); + return ECAlgorithms.sumOfTwoMultiplies(DOMAIN_PARAMS.getG(), u1, rPoint, u2); + } + + public static String toAddress(ECPoint point) + { + // Remove the 1-byte prefix and return the public key as an ethereum address. + byte[] qBytes = point.getEncoded(false); + byte[] qHash = keccak256(qBytes, 1, qBytes.length - 1); + byte[] address = new byte[ADDRESS_LENGTH_BYTES]; + System.arraycopy(qHash, qHash.length - ADDRESS_LENGTH_BYTES, address, 0, ADDRESS_LENGTH_BYTES); + return "0x" + StringUtil.toHexString(address); + } + + public static ECPoint decodePoint(BigInteger p, int v) + { + byte[] encodedPoint = INT_CONVERTER.integerToBytes(p, 1 + INT_CONVERTER.getByteLength(DOMAIN_PARAMS.getCurve())); + encodedPoint[0] = (byte)((v % 2) == 0 ? 0x02 : 0x03); + return DOMAIN_PARAMS.getCurve().decodePoint(encodedPoint); + } + + public static byte[] keccak256(byte[] bytes) + { + Keccak.Digest256 digest256 = new Keccak.Digest256(); + return digest256.digest(bytes); + } + + public static byte[] keccak256(byte[] buf, int offset, int len) + { + Keccak.Digest256 digest256 = new Keccak.Digest256(); + digest256.update(buf, offset, len); + return digest256.digest(); + } + public static String createNonce() { StringBuilder builder = new StringBuilder(8); diff --git a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java index b351a05b4a3..ea8ecdfe6e5 100644 --- a/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java +++ b/jetty-core/jetty-siwe/src/main/java/org/eclipse/jetty/security/siwe/internal/SignInWithEthereumToken.java @@ -18,7 +18,7 @@ import java.time.format.DateTimeFormatter; import java.util.function.Predicate; import org.eclipse.jetty.security.ServerAuthException; -import org.eclipse.jetty.security.siwe.SignedMessage; +import org.eclipse.jetty.security.siwe.EthereumAuthenticator; import org.eclipse.jetty.util.IncludeExcludeSet; import org.eclipse.jetty.util.StringUtil; @@ -54,13 +54,13 @@ public record SignInWithEthereumToken(String scheme, { /** - * @param signedMessage the {@link SignedMessage}. + * @param signedMessage the {@link EthereumAuthenticator.SignedMessage}. * @param validateNonce a {@link Predicate} used to validate the nonce. * @param domains the {@link IncludeExcludeSet} used to validate the domain. * @param chainIds the {@link IncludeExcludeSet} used to validate the chainId. - * @throws ServerAuthException if the {@link SignedMessage} fails validation. + * @throws ServerAuthException if the {@link EthereumAuthenticator.SignedMessage} fails validation. */ - public void validate(SignedMessage signedMessage, Predicate validateNonce, + public void validate(EthereumAuthenticator.SignedMessage signedMessage, Predicate validateNonce, IncludeExcludeSet domains, IncludeExcludeSet chainIds) throws ServerAuthException { diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTest.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTest.java index f577acb36c3..9707c51d0e3 100644 --- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTest.java +++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTest.java @@ -142,7 +142,7 @@ public class SignInWithEthereumTest // Create ethereum credentials to login, and sign a login message. String siweMessage = SignInWithEthereumGenerator.generateMessage(_connector.getLocalPort(), _credentials.getAddress(), nonce); - SignedMessage signedMessage = _credentials.signMessage(siweMessage); + EthereumAuthenticator.SignedMessage signedMessage = _credentials.signMessage(siweMessage); // Send an Authentication request with the signed SIWE message, this should redirect back to initial request. response = sendAuthRequest(signedMessage); @@ -190,7 +190,7 @@ public class SignInWithEthereumTest // Create ethereum credentials to login, and sign a login message. String siweMessage = SignInWithEthereumGenerator.generateMessage(_connector.getLocalPort(), _credentials.getAddress(), nonce); - SignedMessage signedMessage = _credentials.signMessage(siweMessage); + EthereumAuthenticator.SignedMessage signedMessage = _credentials.signMessage(siweMessage); // Initial authentication should succeed because it has a valid nonce. response = sendAuthRequest(signedMessage); @@ -249,7 +249,7 @@ public class SignInWithEthereumTest assertThat(response.getContentAsString(), containsString("UserPrincipal: " + _credentials.getAddress())); } - private ContentResponse sendAuthRequest(SignedMessage signedMessage) throws ExecutionException, InterruptedException, TimeoutException + private ContentResponse sendAuthRequest(EthereumAuthenticator.SignedMessage signedMessage) throws ExecutionException, InterruptedException, TimeoutException { MultiPartRequestContent content = new MultiPartRequestContent(); content.addPart(new MultiPart.ByteBufferPart("signature", null, null, BufferUtil.toBuffer(signedMessage.signature()))); diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java index de6f2d72944..e7b7511466d 100644 --- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java +++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignInWithEthereumTokenTest.java @@ -50,7 +50,7 @@ public class SignInWithEthereumTokenTest null, null, null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); @@ -79,7 +79,7 @@ public class SignInWithEthereumTokenTest null, null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); @@ -109,7 +109,7 @@ public class SignInWithEthereumTokenTest null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); @@ -136,7 +136,7 @@ public class SignInWithEthereumTokenTest null, null, null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); @@ -166,7 +166,7 @@ public class SignInWithEthereumTokenTest null, null, null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); @@ -196,7 +196,7 @@ public class SignInWithEthereumTokenTest null, null, null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); @@ -224,7 +224,7 @@ public class SignInWithEthereumTokenTest null, null, null, null ); - SignedMessage signedMessage = credentials.signMessage(message); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(message); SignInWithEthereumToken siwe = SignInWithEthereumParser.parse(message); assertNotNull(siwe); diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignatureVerificationTest.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignatureVerificationTest.java index 197ac6374bd..6a2d3811915 100644 --- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignatureVerificationTest.java +++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/SignatureVerificationTest.java @@ -27,7 +27,7 @@ public class SignatureVerificationTest public void testSignatureVerification() throws Exception { String siweMessage = "hello world"; - SignedMessage signedMessage = credentials.signMessage(siweMessage); + EthereumAuthenticator.SignedMessage signedMessage = credentials.signMessage(siweMessage); String address = credentials.getAddress(); String recoveredAddress = signedMessage.recoverAddress(); assertThat(recoveredAddress, equalToIgnoringCase(address)); diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/EthereumCredentials.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/EthereumCredentials.java index 19533dbf748..f19d31b9687 100644 --- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/EthereumCredentials.java +++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/EthereumCredentials.java @@ -28,10 +28,10 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.encoders.Hex; -import org.eclipse.jetty.security.siwe.SignedMessage; -import org.eclipse.jetty.security.siwe.internal.EthereumSignatureVerifier; +import org.eclipse.jetty.security.siwe.EthereumAuthenticator; +import org.eclipse.jetty.security.siwe.internal.EthereumUtil; -import static org.eclipse.jetty.security.siwe.internal.EthereumSignatureVerifier.keccak256; +import static org.eclipse.jetty.security.siwe.internal.EthereumUtil.keccak256; public class EthereumCredentials { @@ -50,7 +50,7 @@ public class EthereumCredentials KeyPair keyPair = keyPairGenerator.generateKeyPair(); this.privateKey = keyPair.getPrivate(); this.publicKey = keyPair.getPublic(); - this.address = EthereumSignatureVerifier.toAddress(((BCECPublicKey)publicKey).getQ()); + this.address = EthereumUtil.toAddress(((BCECPublicKey)publicKey).getQ()); } catch (Exception e) { @@ -63,7 +63,7 @@ public class EthereumCredentials return address; } - public SignedMessage signMessage(String message) throws Exception + public EthereumAuthenticator.SignedMessage signMessage(String message) throws Exception { byte[] messageBytes = message.getBytes(StandardCharsets.ISO_8859_1); String prefix = "\u0019Ethereum Signed Message:\n" + messageBytes.length + message; @@ -80,7 +80,7 @@ public class EthereumCredentials System.arraycopy(r, 0, signature, 0, 32); System.arraycopy(s, 0, signature, 32, 32); signature[64] = (byte)(calculateV(messageHash, r, s) + 27); - return new SignedMessage(message, Hex.toHexString(signature)); + return new EthereumAuthenticator.SignedMessage(message, Hex.toHexString(signature)); } private byte[] getR(byte[] encodedSignature) @@ -117,7 +117,7 @@ public class EthereumCredentials ECPoint publicKeyPoint = ((BCECPublicKey)publicKey).getQ(); for (int v = 0; v < 4; v++) { - ECPoint qPoint = EthereumSignatureVerifier.ecRecover(hash, v, new BigInteger(1, r), new BigInteger(1, s)); + ECPoint qPoint = EthereumUtil.ecRecover(hash, v, new BigInteger(1, r), new BigInteger(1, s)); if (qPoint != null && qPoint.equals(publicKeyPoint)) return (byte)v; } diff --git a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/SignInWithEthereumGenerator.java b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/SignInWithEthereumGenerator.java index 0d91b34c8f8..fed54412897 100644 --- a/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/SignInWithEthereumGenerator.java +++ b/jetty-core/jetty-siwe/src/test/java/org/eclipse/jetty/security/siwe/util/SignInWithEthereumGenerator.java @@ -16,7 +16,7 @@ package org.eclipse.jetty.security.siwe.util; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -public class SignInWithEthereumGenerator +public class SignInWithEthereumGenerator { private SignInWithEthereumGenerator() { diff --git a/pom.xml b/pom.xml index 533efde7859..29b4ceaeefa 100644 --- a/pom.xml +++ b/pom.xml @@ -169,8 +169,8 @@ 3.0.0-alpha.2 9.7 4.2.1 - 1.78.1 7.0.0 + 1.78.1 3.6.0 1.5 3.2.0 @@ -619,6 +619,22 @@ awaitility ${awaitility.version} + + + org.bouncycastle + bcpkix-jdk15to18 + ${bouncycastle.version} + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + + org.bouncycastle + bcutil-jdk15to18 + ${bouncycastle.version} + org.codehaus.plexus plexus-classworlds @@ -1304,22 +1320,6 @@ wildfly-elytron-sasl-scram ${wildfly.elytron.version} - - - org.bouncycastle - bcpkix-jdk15to18 - ${bouncycastle.version} - - - org.bouncycastle - bcprov-jdk15to18 - ${bouncycastle.version} - - - org.bouncycastle - bcutil-jdk15to18 - ${bouncycastle.version} - diff --git a/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/SiweTests.java b/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/SiweTests.java index e7936f868fd..8bf9984ae90 100644 --- a/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/SiweTests.java +++ b/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/SiweTests.java @@ -25,7 +25,7 @@ import org.eclipse.jetty.ee10.tests.distribution.siwe.EthereumCredentials; import org.eclipse.jetty.ee10.tests.distribution.siwe.SignInWithEthereumGenerator; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.security.siwe.SignedMessage; +import org.eclipse.jetty.security.siwe.EthereumAuthenticator; import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest; import org.eclipse.jetty.tests.testers.JettyHomeTester; import org.eclipse.jetty.tests.testers.Tester; @@ -137,7 +137,7 @@ public class SiweTests extends AbstractJettyHomeTest private FormRequestContent getAuthRequestContent(int port, String nonce) throws Exception { - SignedMessage signedMessage = _credentials.signMessage( + EthereumAuthenticator.SignedMessage signedMessage = _credentials.signMessage( SignInWithEthereumGenerator.generateMessage(port, _credentials.getAddress(), nonce)); Fields fields = new Fields(); fields.add("signature", signedMessage.signature()); diff --git a/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/siwe/EthereumCredentials.java b/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/siwe/EthereumCredentials.java index 80a5d6957bf..1b79bb299a1 100644 --- a/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/siwe/EthereumCredentials.java +++ b/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/siwe/EthereumCredentials.java @@ -28,10 +28,10 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.encoders.Hex; -import org.eclipse.jetty.security.siwe.SignedMessage; -import org.eclipse.jetty.security.siwe.internal.EthereumSignatureVerifier; +import org.eclipse.jetty.security.siwe.EthereumAuthenticator; +import org.eclipse.jetty.security.siwe.internal.EthereumUtil; -import static org.eclipse.jetty.security.siwe.internal.EthereumSignatureVerifier.keccak256; +import static org.eclipse.jetty.security.siwe.internal.EthereumUtil.keccak256; public class EthereumCredentials { @@ -50,7 +50,7 @@ public class EthereumCredentials KeyPair keyPair = keyPairGenerator.generateKeyPair(); this.privateKey = keyPair.getPrivate(); this.publicKey = keyPair.getPublic(); - this.address = EthereumSignatureVerifier.toAddress(((BCECPublicKey)publicKey).getQ()); + this.address = EthereumUtil.toAddress(((BCECPublicKey)publicKey).getQ()); } catch (Exception e) { @@ -63,7 +63,7 @@ public class EthereumCredentials return address; } - public SignedMessage signMessage(String message) throws Exception + public EthereumAuthenticator.SignedMessage signMessage(String message) throws Exception { byte[] messageBytes = message.getBytes(StandardCharsets.ISO_8859_1); String prefix = "\u0019Ethereum Signed Message:\n" + messageBytes.length + message; @@ -80,7 +80,7 @@ public class EthereumCredentials System.arraycopy(r, 0, signature, 0, 32); System.arraycopy(s, 0, signature, 32, 32); signature[64] = (byte)(calculateV(messageHash, r, s) + 27); - return new SignedMessage(message, Hex.toHexString(signature)); + return new EthereumAuthenticator.SignedMessage(message, Hex.toHexString(signature)); } private byte[] getR(byte[] encodedSignature) @@ -117,7 +117,7 @@ public class EthereumCredentials ECPoint publicKeyPoint = ((BCECPublicKey)publicKey).getQ(); for (int v = 0; v < 4; v++) { - ECPoint qPoint = EthereumSignatureVerifier.ecRecover(hash, v, new BigInteger(1, r), new BigInteger(1, s)); + ECPoint qPoint = EthereumUtil.ecRecover(hash, v, new BigInteger(1, r), new BigInteger(1, s)); if (qPoint != null && qPoint.equals(publicKeyPoint)) return (byte)v; }