From 0704b7445ed66248985e7c4a08f3825804fac6e6 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 16 Feb 2026 22:12:28 -0800 Subject: [PATCH 1/2] Fix gradle BAT --- gradlew.bat | 186 ++++++++++++++++++++++++++-------------------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/gradlew.bat b/gradlew.bat index e509b2dd..c4bdd3ab 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,93 +1,93 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From ccc6ddcd36b67e261b1ae61055394a98be6af383 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 16 Feb 2026 22:18:44 -0800 Subject: [PATCH 2/2] Accert OID for EdDSA keys --- .../trilead/ssh2/crypto/PublicKeyUtils.java | 20 +++++- .../ssh2/crypto/keys/Ed25519KeyFactory.java | 24 ++++--- .../ssh2/crypto/PublicKeyUtilsTest.java | 71 +++++++++++++++++++ 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/trilead/ssh2/crypto/PublicKeyUtils.java b/src/main/java/com/trilead/ssh2/crypto/PublicKeyUtils.java index 8db5ea76..89509b3f 100644 --- a/src/main/java/com/trilead/ssh2/crypto/PublicKeyUtils.java +++ b/src/main/java/com/trilead/ssh2/crypto/PublicKeyUtils.java @@ -15,6 +15,7 @@ import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; +import java.util.Locale; /** * Utilities for working with SSH public keys. @@ -58,7 +59,7 @@ public static String toAuthorizedKeysFormat(PublicKey publicKey, String comment) keyType = ECDSASHA2Verify.getSshKeyType(ecKey); SSHSignature verifier = ECDSASHA2Verify.getVerifierForKey(ecKey); encoded = verifier.encodePublicKey(ecKey); - } else if ("EdDSA".equals(publicKey.getAlgorithm()) || "Ed25519".equals(publicKey.getAlgorithm())) { + } else if (isEd25519Key(publicKey)) { Ed25519PublicKey ed25519Key = Ed25519Verify.convertPublicKey(publicKey); keyType = Ed25519Verify.ED25519_ID; encoded = Ed25519Verify.get().encodePublicKey(ed25519Key); @@ -88,7 +89,7 @@ public static byte[] extractPublicKeyBlob(PublicKey publicKey) ECPublicKey ecKey = (ECPublicKey) publicKey; SSHSignature verifier = ECDSASHA2Verify.getVerifierForKey(ecKey); return verifier.encodePublicKey(ecKey); - } else if ("EdDSA".equals(publicKey.getAlgorithm()) || "Ed25519".equals(publicKey.getAlgorithm())) { + } else if (isEd25519Key(publicKey)) { Ed25519PublicKey ed25519Key = Ed25519Verify.convertPublicKey(publicKey); return Ed25519Verify.get().encodePublicKey(ed25519Key); } else { @@ -96,6 +97,21 @@ public static byte[] extractPublicKeyBlob(PublicKey publicKey) } } + /** + * Checks whether the given key is an Ed25519 key. This handles keys from different providers + * (e.g., JDK, Conscrypt/Google Play Services) which may use different algorithm names or + * class names for Ed25519 keys. + */ + static boolean isEd25519Key(PublicKey publicKey) { + String algorithm = publicKey.getAlgorithm(); + if ("EdDSA".equals(algorithm) || "Ed25519".equals(algorithm) || "1.3.101.112".equals(algorithm)) { + return true; + } + + String className = publicKey.getClass().getName().toLowerCase(Locale.ROOT); + return className.contains("ed25519") || className.contains("eddsa"); + } + /** * Detect the key type from OpenSSH format private key data without requiring password. * This reads the unencrypted public key section of the OpenSSH format. diff --git a/src/main/java/com/trilead/ssh2/crypto/keys/Ed25519KeyFactory.java b/src/main/java/com/trilead/ssh2/crypto/keys/Ed25519KeyFactory.java index 00f59194..81c0b31a 100644 --- a/src/main/java/com/trilead/ssh2/crypto/keys/Ed25519KeyFactory.java +++ b/src/main/java/com/trilead/ssh2/crypto/keys/Ed25519KeyFactory.java @@ -47,21 +47,25 @@ public Key engineTranslateKey(Key key) throws InvalidKeyException { return key; } - if (key instanceof PublicKey && key.getFormat().equals("X.509")) { + if (key instanceof PublicKey) { byte[] encoded = key.getEncoded(); - try { - return new Ed25519PublicKey(new X509EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); + if (encoded != null) { + try { + return new Ed25519PublicKey(new X509EncodedKeySpec(encoded)); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException(e); + } } } - if (key instanceof PrivateKey && key.getFormat().equals("PKCS#8")) { + if (key instanceof PrivateKey) { byte[] encoded = key.getEncoded(); - try { - return new Ed25519PrivateKey(new PKCS8EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); + if (encoded != null) { + try { + return new Ed25519PrivateKey(new PKCS8EncodedKeySpec(encoded)); + } catch (InvalidKeySpecException e) { + throw new InvalidKeyException(e); + } } } diff --git a/src/test/java/com/trilead/ssh2/crypto/PublicKeyUtilsTest.java b/src/test/java/com/trilead/ssh2/crypto/PublicKeyUtilsTest.java index c3cd1d85..970d9ba8 100644 --- a/src/test/java/com/trilead/ssh2/crypto/PublicKeyUtilsTest.java +++ b/src/test/java/com/trilead/ssh2/crypto/PublicKeyUtilsTest.java @@ -10,6 +10,7 @@ import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -242,6 +243,76 @@ void testToAuthorizedKeysFormatWithNativeJDKEdDSAKey() throws Exception { assertTrue(result.endsWith(" native-eddsa-key")); } + @Test + void testExtractPublicKeyBlobWithOidAlgorithmName() throws Exception { + String keyPath = TEST_RESOURCES + "openssh_ed25519"; + KeyPair keyPair = loadKeyPair(keyPath); + PublicKey originalKey = keyPair.getPublic(); + + PublicKey wrappedKey = new PublicKey() { + @Override + public String getAlgorithm() { + return "1.3.101.112"; + } + + @Override + public String getFormat() { + return originalKey.getFormat(); + } + + @Override + public byte[] getEncoded() { + return originalKey.getEncoded(); + } + }; + + byte[] blob = assertDoesNotThrow(() -> PublicKeyUtils.extractPublicKeyBlob(wrappedKey)); + assertNotNull(blob); + assertTrue(blob.length > 0); + + byte[] expectedBlob = PublicKeyUtils.extractPublicKeyBlob(originalKey); + assertEquals(expectedBlob.length, blob.length); + for (int i = 0; i < expectedBlob.length; i++) { + assertEquals(expectedBlob[i], blob[i]); + } + } + + @Test + void testExtractPublicKeyBlobWithEdDsaClassName() throws Exception { + String keyPath = TEST_RESOURCES + "openssh_ed25519"; + KeyPair keyPair = loadKeyPair(keyPath); + PublicKey originalKey = keyPair.getPublic(); + + PublicKey wrappedKey = new OpenSslEdDsaPublicKeyStub(originalKey); + + byte[] blob = assertDoesNotThrow(() -> PublicKeyUtils.extractPublicKeyBlob(wrappedKey)); + assertNotNull(blob); + assertTrue(blob.length > 0); + } + + private static class OpenSslEdDsaPublicKeyStub implements PublicKey { + private final PublicKey delegate; + + OpenSslEdDsaPublicKeyStub(PublicKey delegate) { + this.delegate = delegate; + } + + @Override + public String getAlgorithm() { + return "UnknownAlgorithm"; + } + + @Override + public String getFormat() { + return delegate.getFormat(); + } + + @Override + public byte[] getEncoded() { + return delegate.getEncoded(); + } + } + private KeyPair loadKeyPair(String path) throws Exception { byte[] keyData = Files.readAllBytes(Paths.get(path)); String keyString = new String(keyData, "UTF-8");