diff --git a/core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java b/core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java index 8f214b0147a..a1e266cd972 100644 --- a/core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java +++ b/core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java @@ -18,11 +18,11 @@ import java.security.SecureRandom; import java.util.Base64; +import java.util.HexFormat; import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -71,6 +71,7 @@ *

* * @author Ben Alex + * @author Andrey Litvitski * */ public class KeyBasedPersistenceTokenService implements TokenService, InitializingBean { @@ -142,7 +143,7 @@ private String computeKey(String serverSecret, String content) { private String generatePseudoRandomNumber() { byte[] randomBytes = new byte[this.pseudoRandomNumberBytes]; this.secureRandom.nextBytes(randomBytes); - return new String(Hex.encode(randomBytes)); + return new String(HexFormat.of().formatHex(randomBytes)); } private String computeServerSecretApplicableAt(long time) { diff --git a/core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java b/core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java index 5093afe6935..b517424a8b8 100644 --- a/core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java +++ b/core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java @@ -18,8 +18,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; - -import org.springframework.security.crypto.codec.Hex; +import java.util.HexFormat; /** * Provides SHA512 digest methods. @@ -73,7 +72,7 @@ public static byte[] sha(String data) { * @return SHA digest as a hex string */ public static String shaHex(byte[] data) { - return new String(Hex.encode(sha(data))); + return HexFormat.of().formatHex(sha(data)); } /** @@ -82,7 +81,7 @@ public static String shaHex(byte[] data) { * @return SHA digest as a hex string */ public static String shaHex(String data) { - return new String(Hex.encode(sha(data))); + return HexFormat.of().formatHex(sha(data)); } } diff --git a/crypto/src/main/java/org/springframework/security/crypto/codec/Hex.java b/crypto/src/main/java/org/springframework/security/crypto/codec/Hex.java deleted file mode 100644 index 8ca0b2ad7d0..00000000000 --- a/crypto/src/main/java/org/springframework/security/crypto/codec/Hex.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2004-present the original author or authors. - * - * 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 - * - * https://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.springframework.security.crypto.codec; - -/** - * Hex data encoder. Converts byte arrays (such as those obtained from message digests) - * into hexadecimal string representation. - *

- * For internal use only. - * - * @author Luke Taylor - * @since 3.0 - */ -public final class Hex { - - private static final char[] HEX = "0123456789abcdef".toCharArray(); - - private Hex() { - } - - public static char[] encode(byte[] bytes) { - final int nBytes = bytes.length; - char[] result = new char[2 * nBytes]; - int j = 0; - for (byte aByte : bytes) { - // Char for top 4 bits - result[j++] = HEX[(0xF0 & aByte) >>> 4]; - // Bottom 4 - result[j++] = HEX[(0x0F & aByte)]; - } - return result; - } - - public static byte[] decode(CharSequence s) { - int nChars = s.length(); - if (nChars % 2 != 0) { - throw new IllegalArgumentException("Hex-encoded string must have an even number of characters"); - } - byte[] result = new byte[nChars / 2]; - for (int i = 0; i < nChars; i += 2) { - int msb = Character.digit(s.charAt(i), 16); - int lsb = Character.digit(s.charAt(i + 1), 16); - if (msb < 0 || lsb < 0) { - throw new IllegalArgumentException( - "Detected a Non-hex character at " + (i + 1) + " or " + (i + 2) + " position"); - } - result[i / 2] = (byte) ((msb << 4) | lsb); - } - return result; - } - -} diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java index 5ba1ab5c77a..24a74ea95da 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java @@ -17,6 +17,7 @@ package org.springframework.security.crypto.encrypt; import java.security.spec.AlgorithmParameterSpec; +import java.util.HexFormat; import javax.crypto.Cipher; import javax.crypto.SecretKey; @@ -27,7 +28,6 @@ import org.jspecify.annotations.Nullable; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.util.EncodingUtils; @@ -102,7 +102,7 @@ public AesBytesEncryptor(String password, CharSequence salt, @Nullable BytesKeyG public AesBytesEncryptor(String password, CharSequence salt, @Nullable BytesKeyGenerator ivGenerator, CipherAlgorithm alg) { this(CipherUtils.newSecretKey("PBKDF2WithHmacSHA1", - new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256)), ivGenerator, alg); + new PBEKeySpec(password.toCharArray(), HexFormat.of().parseHex(salt), 1024, 256)), ivGenerator, alg); } /** diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptor.java index 7cae0f3de78..c40ca51a7bd 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptor.java @@ -16,6 +16,7 @@ package org.springframework.security.crypto.encrypt; +import java.util.HexFormat; import java.util.Objects; import javax.crypto.Cipher; @@ -24,7 +25,6 @@ import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.util.EncodingUtils; @@ -119,7 +119,7 @@ public byte[] decrypt(byte[] encryptedBytes) { private static SecretKey deriveKey(String password, CharSequence salt) { return CipherUtils.newSecretKey("PBKDF2WithHmacSHA256", - new PBEKeySpec(password.toCharArray(), Hex.decode(salt), DEFAULT_PBKDF2_ITERATIONS, 256)); + new PBEKeySpec(password.toCharArray(), HexFormat.of().parseHex(salt), DEFAULT_PBKDF2_ITERATIONS, 256)); } /** diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptor.java index 980221cb33c..9ab802eb640 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptor.java @@ -16,6 +16,7 @@ package org.springframework.security.crypto.encrypt; +import java.util.HexFormat; import java.util.Objects; import javax.crypto.Cipher; @@ -24,7 +25,6 @@ import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.util.EncodingUtils; @@ -126,7 +126,7 @@ public byte[] decrypt(byte[] encryptedBytes) { private static SecretKey deriveKey(String password, CharSequence salt) { return CipherUtils.newSecretKey("PBKDF2WithHmacSHA256", - new PBEKeySpec(password.toCharArray(), Hex.decode(salt), DEFAULT_PBKDF2_ITERATIONS, 256)); + new PBEKeySpec(password.toCharArray(), HexFormat.of().parseHex(salt), DEFAULT_PBKDF2_ITERATIONS, 256)); } /** diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptor.java index 282a71689b2..85608a2322b 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptor.java @@ -16,11 +16,12 @@ package org.springframework.security.crypto.encrypt; +import java.util.HexFormat; + import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.bouncycastle.crypto.params.KeyParameter; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; @@ -47,7 +48,7 @@ abstract class BouncyCastleAesBytesEncryptor implements BytesEncryptor { this.ivGenerator = ivGenerator; PBEParametersGenerator keyGenerator = new PKCS5S2ParametersGenerator(); byte[] pkcs12PasswordBytes = PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password.toCharArray()); - keyGenerator.init(pkcs12PasswordBytes, Hex.decode(salt), 1024); + keyGenerator.init(pkcs12PasswordBytes, HexFormat.of().parseHex(salt), 1024); this.secretKey = (KeyParameter) keyGenerator.generateDerivedParameters(256); } diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java index 1a3ead10347..2a0e92726c7 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/HexEncodingTextEncryptor.java @@ -16,7 +16,8 @@ package org.springframework.security.crypto.encrypt; -import org.springframework.security.crypto.codec.Hex; +import java.util.HexFormat; + import org.springframework.security.crypto.codec.Utf8; /** @@ -36,12 +37,12 @@ final class HexEncodingTextEncryptor implements TextEncryptor { @Override public String encrypt(String text) { - return new String(Hex.encode(this.encryptor.encrypt(Utf8.encode(text)))); + return HexFormat.of().formatHex(this.encryptor.encrypt(Utf8.encode(text))); } @Override public String decrypt(String encryptedText) { - return Utf8.decode(this.encryptor.decrypt(Hex.decode(encryptedText))); + return Utf8.decode(this.encryptor.decrypt(HexFormat.of().parseHex(encryptedText))); } } diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaSecretEncryptor.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaSecretEncryptor.java index c6ecab9ac3d..16e8325324e 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaSecretEncryptor.java +++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaSecretEncryptor.java @@ -25,12 +25,12 @@ import java.security.PublicKey; import java.security.interfaces.RSAPublicKey; import java.util.Base64; +import java.util.HexFormat; import javax.crypto.Cipher; import org.jspecify.annotations.Nullable; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.KeyGenerators; /** @@ -138,7 +138,7 @@ public RsaSecretEncryptor(String encoding, PublicKey publicKey, @Nullable Privat this.privateKey = privateKey; this.defaultCharset = Charset.forName(DEFAULT_ENCODING); this.algorithm = algorithm; - this.salt = isHex(salt) ? salt : new String(Hex.encode(salt.getBytes(this.defaultCharset))); + this.salt = isHex(salt) ? salt : HexFormat.of().formatHex(salt.getBytes(this.defaultCharset)); this.gcm = gcm; } @@ -176,8 +176,8 @@ public byte[] decrypt(byte[] encryptedByteArray) { private static byte[] encrypt(byte[] text, PublicKey key, RsaAlgorithm alg, String salt, boolean gcm) { byte[] random = KeyGenerators.secureRandom(16).generateKey(); - BytesEncryptor aes = gcm ? Encryptors.stronger(new String(Hex.encode(random)), salt) - : Encryptors.standard(new String(Hex.encode(random)), salt); + BytesEncryptor aes = gcm ? Encryptors.stronger(HexFormat.of().formatHex(random), salt) + : Encryptors.standard(HexFormat.of().formatHex(random), salt); try { final Cipher cipher = Cipher.getInstance(alg.getJceName()); cipher.init(Cipher.ENCRYPT_MODE, key); @@ -218,7 +218,7 @@ private static byte[] decrypt(byte[] text, @Nullable PrivateKey key, RsaAlgorith input.read(random); final Cipher cipher = Cipher.getInstance(alg.getJceName()); cipher.init(Cipher.DECRYPT_MODE, key); - String secret = new String(Hex.encode(cipher.doFinal(random))); + String secret = HexFormat.of().formatHex(cipher.doFinal(random)); byte[] buffer = new byte[text.length - random.length - 2]; input.read(buffer); BytesEncryptor aes = gcm ? Encryptors.stronger(secret, salt) : Encryptors.standard(secret, salt); @@ -235,7 +235,7 @@ private static byte[] decrypt(byte[] text, @Nullable PrivateKey key, RsaAlgorith private static boolean isHex(String input) { try { - Hex.decode(input); + HexFormat.of().parseHex(input); return true; } catch (Exception ex) { diff --git a/crypto/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java b/crypto/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java index f6f9a22f939..00a70181331 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java +++ b/crypto/src/main/java/org/springframework/security/crypto/keygen/HexEncodingStringKeyGenerator.java @@ -16,7 +16,7 @@ package org.springframework.security.crypto.keygen; -import org.springframework.security.crypto.codec.Hex; +import java.util.HexFormat; /** * A StringKeyGenerator that generates hex-encoded String keys. Delegates to a @@ -34,7 +34,7 @@ final class HexEncodingStringKeyGenerator implements StringKeyGenerator { @Override public String generateKey() { - return new String(Hex.encode(this.keyGenerator.generateKey())); + return HexFormat.of().formatHex(this.keyGenerator.generateKey()); } } diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/AbstractPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/AbstractPasswordEncoder.java index 973a11dd550..97186fc7e21 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/password/AbstractPasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/password/AbstractPasswordEncoder.java @@ -17,8 +17,8 @@ package org.springframework.security.crypto.password; import java.security.MessageDigest; +import java.util.HexFormat; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.util.EncodingUtils; @@ -40,12 +40,12 @@ protected AbstractPasswordEncoder() { protected String encodeNonNullPassword(String rawPassword) { byte[] salt = this.saltGenerator.generateKey(); byte[] encoded = encodeAndConcatenate(rawPassword, salt); - return String.valueOf(Hex.encode(encoded)); + return String.valueOf(HexFormat.of().formatHex(encoded)); } @Override protected boolean matchesNonNull(String rawPassword, String encodedPassword) { - byte[] digested = Hex.decode(encodedPassword); + byte[] digested = HexFormat.of().parseHex(encodedPassword); byte[] salt = EncodingUtils.subArray(digested, 0, this.saltGenerator.getKeyLength()); return matchesNonNull(digested, encodeAndConcatenate(rawPassword, salt)); } diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java index 0ab6b9001ad..6556940f0e6 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java @@ -17,8 +17,8 @@ package org.springframework.security.crypto.password; import java.util.Base64; +import java.util.HexFormat; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import org.springframework.security.crypto.keygen.Base64StringKeyGenerator; import org.springframework.security.crypto.keygen.StringKeyGenerator; @@ -122,7 +122,7 @@ private String encodedNonNullPassword(byte[] digest) { if (this.encodeHashAsBase64) { return Utf8.decode(Base64.getEncoder().encode(digest)); } - return new String(Hex.encode(digest)); + return HexFormat.of().formatHex(digest); } /** diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/MessageDigestPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/MessageDigestPasswordEncoder.java index d899593007a..a8f9fce3e19 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/password/MessageDigestPasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/password/MessageDigestPasswordEncoder.java @@ -18,8 +18,8 @@ import java.security.MessageDigest; import java.util.Base64; +import java.util.HexFormat; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import org.springframework.security.crypto.keygen.Base64StringKeyGenerator; import org.springframework.security.crypto.keygen.StringKeyGenerator; @@ -132,7 +132,7 @@ private String encodedNonNullPassword(byte[] digest) { if (this.encodeHashAsBase64) { return Utf8.decode(Base64.getEncoder().encode(digest)); } - return new String(Hex.encode(digest)); + return HexFormat.of().formatHex(digest); } /** diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.java index d456c962674..1f1eb772886 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoder.java @@ -20,11 +20,11 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; +import java.util.HexFormat; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; @@ -204,7 +204,7 @@ private String encodedNonNullPassword(byte[] bytes) { if (this.encodeHashAsBase64) { return Base64.getEncoder().encodeToString(bytes); } - return String.valueOf(Hex.encode(bytes)); + return String.valueOf(HexFormat.of().formatHex(bytes)); } @Override @@ -218,7 +218,7 @@ private byte[] decode(String encodedBytes) { if (this.encodeHashAsBase64) { return Base64.getDecoder().decode(encodedBytes); } - return Hex.decode(encodedBytes); + return HexFormat.of().parseHex(encodedBytes); } private byte[] encodedNonNullPassword(CharSequence rawPassword, byte[] salt) { diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java index a89641be6c2..6b5b8e37abf 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/password/StandardPasswordEncoder.java @@ -17,8 +17,8 @@ package org.springframework.security.crypto.password; import java.security.MessageDigest; +import java.util.HexFormat; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; @@ -94,7 +94,7 @@ private StandardPasswordEncoder(String algorithm, CharSequence secret) { private String encodedNonNullPassword(CharSequence rawPassword, byte[] salt) { byte[] digest = digest(rawPassword, salt); - return new String(Hex.encode(digest)); + return HexFormat.of().formatHex(digest); } private byte[] digest(CharSequence rawPassword, byte[] salt) { @@ -103,7 +103,7 @@ private byte[] digest(CharSequence rawPassword, byte[] salt) { } private byte[] decode(CharSequence encodedPassword) { - return Hex.decode(encodedPassword); + return HexFormat.of().parseHex(encodedPassword); } } diff --git a/crypto/src/test/java/org/springframework/security/crypto/codec/HexTests.java b/crypto/src/test/java/org/springframework/security/crypto/codec/HexTests.java deleted file mode 100644 index 322d315e27e..00000000000 --- a/crypto/src/test/java/org/springframework/security/crypto/codec/HexTests.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2004-present the original author or authors. - * - * 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 - * - * https://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.springframework.security.crypto.codec; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -/** - * Test cases for {@link Hex}. - * - * @author Kazuki Shimizu - */ -public class HexTests { - - @Test - public void encode() { - assertThat(Hex.encode(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D' })) - .isEqualTo(new char[] { '4', '1', '4', '2', '4', '3', '4', '4' }); - } - - @Test - public void encodeEmptyByteArray() { - assertThat(Hex.encode(new byte[] {})).isEmpty(); - } - - @Test - public void decode() { - assertThat(Hex.decode("41424344")).isEqualTo(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D' }); - } - - @Test - public void decodeEmptyString() { - assertThat(Hex.decode("")).isEmpty(); - } - - @Test - public void decodeNotEven() { - assertThatIllegalArgumentException().isThrownBy(() -> Hex.decode("414243444")) - .withMessage("Hex-encoded string must have an even number of characters"); - } - - @Test - public void decodeExistNonHexCharAtFirst() { - assertThatIllegalArgumentException().isThrownBy(() -> Hex.decode("G0")) - .withMessage("Detected a Non-hex character at 1 or 2 position"); - } - - @Test - public void decodeExistNonHexCharAtSecond() { - assertThatIllegalArgumentException().isThrownBy(() -> Hex.decode("410G")) - .withMessage("Detected a Non-hex character at 3 or 4 position"); - } - - @Test - public void decodeExistNonHexCharAtBoth() { - assertThatIllegalArgumentException().isThrownBy(() -> Hex.decode("4142GG")) - .withMessage("Detected a Non-hex character at 5 or 6 position"); - } - -} diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesBytesEncryptorTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesBytesEncryptorTests.java index f52264acd07..d4cae59d98c 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesBytesEncryptorTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesBytesEncryptorTests.java @@ -16,13 +16,14 @@ package org.springframework.security.crypto.encrypt; +import java.util.HexFormat; + import javax.crypto.SecretKey; import javax.crypto.spec.PBEKeySpec; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.encrypt.AesBytesEncryptor.CipherAlgorithm; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder.SecretKeyFactoryAlgorithm; @@ -47,7 +48,7 @@ public class AesBytesEncryptorTests { @BeforeEach public void setUp() { this.generator = mock(BytesKeyGenerator.class); - given(this.generator.generateKey()).willReturn(Hex.decode("4b0febebd439db7ca77153cb254520c3")); + given(this.generator.generateKey()).willReturn(HexFormat.of().parseHex("4b0febebd439db7ca77153cb254520c3")); given(this.generator.getKeyLength()).willReturn(16); } @@ -65,7 +66,7 @@ public void roundtripWhenUsingDefaultCipherThenEncryptsAndDecrypts() { CryptoAssumptions.assumeCBCJCE(); AesBytesEncryptor encryptor = new AesBytesEncryptor(this.password, this.hexSalt, this.generator); byte[] encryption = encryptor.encrypt(this.secret.getBytes()); - assertThat(new String(Hex.encode(encryption))) + assertThat(new String(HexFormat.of().formatHex(encryption))) .isEqualTo("4b0febebd439db7ca77153cb254520c3b7232ac29355d07869433f1ecf55fe94"); byte[] decryption = encryptor.decrypt(encryption); assertThat(new String(decryption)).isEqualTo(this.secret); @@ -77,7 +78,7 @@ public void roundtripWhenUsingGcmThenEncryptsAndDecrypts() { AesBytesEncryptor encryptor = new AesBytesEncryptor(this.password, this.hexSalt, this.generator, CipherAlgorithm.GCM); byte[] encryption = encryptor.encrypt(this.secret.getBytes()); - assertThat(new String(Hex.encode(encryption))) + assertThat(new String(HexFormat.of().formatHex(encryption))) .isEqualTo("4b0febebd439db7ca77153cb254520c3e4d61ae38207b4e42b820d311dc3d4e0e2f37ed5ee"); byte[] decryption = encryptor.decrypt(encryption); assertThat(new String(decryption)).isEqualTo(this.secret); @@ -86,11 +87,12 @@ public void roundtripWhenUsingGcmThenEncryptsAndDecrypts() { @Test public void roundtripWhenUsingSecretKeyThenEncryptsAndDecrypts() { CryptoAssumptions.assumeGCMJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey secretKey = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesBytesEncryptor encryptor = new AesBytesEncryptor(secretKey, this.generator, CipherAlgorithm.GCM); byte[] encryption = encryptor.encrypt(this.secret.getBytes()); - assertThat(new String(Hex.encode(encryption))) + assertThat(new String(HexFormat.of().formatHex(encryption))) .isEqualTo("4b0febebd439db7ca77153cb254520c3e4d61ae38207b4e42b820d311dc3d4e0e2f37ed5ee"); byte[] decryption = encryptor.decrypt(encryption); assertThat(new String(decryption)).isEqualTo(this.secret); diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptorTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptorTests.java index dfa187783d2..b35ec426f0d 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptorTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesCbcBytesEncryptorTests.java @@ -17,13 +17,13 @@ package org.springframework.security.crypto.encrypt; import java.nio.charset.StandardCharsets; +import java.util.HexFormat; import javax.crypto.SecretKey; import javax.crypto.spec.PBEKeySpec; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder.SecretKeyFactoryAlgorithm; @@ -56,7 +56,8 @@ void roundtripWhenUsingPasswordAndSaltThenEncryptsAndDecrypts() { @Test void roundtripWhenUsingSecretKeyThenEncryptsAndDecrypts() { CryptoAssumptions.assumeCBCJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey secretKey = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesCbcBytesEncryptor encryptor = AesCbcBytesEncryptor.withSecretKey(secretKey).build(); byte[] encrypted = encryptor.encrypt(this.secret.getBytes()); @@ -67,13 +68,14 @@ void roundtripWhenUsingSecretKeyThenEncryptsAndDecrypts() { void encryptWhenUsingMockIvThenProducesKnownCiphertext() { CryptoAssumptions.assumeCBCJCE(); BytesKeyGenerator mockGenerator = mock(BytesKeyGenerator.class); - given(mockGenerator.generateKey()).willReturn(Hex.decode("4b0febebd439db7ca77153cb254520c3")); + given(mockGenerator.generateKey()).willReturn(HexFormat.of().parseHex("4b0febebd439db7ca77153cb254520c3")); given(mockGenerator.getKeyLength()).willReturn(16); AesCbcBytesEncryptor encryptor = AesCbcBytesEncryptor.withPassword(this.password, this.hexSalt) .ivGenerator(mockGenerator) .build(); byte[] encrypted = encryptor.encrypt(this.secret.getBytes()); - assertThat(Hex.encode(encrypted)).isEqualTo("4b0febebd439db7ca77153cb254520c3b7232ac29355d07869433f1ecf55fe94"); + assertThat(HexFormat.of().formatHex(encrypted)) + .isEqualTo("4b0febebd439db7ca77153cb254520c3b7232ac29355d07869433f1ecf55fe94"); assertThat(new String(encryptor.decrypt(encrypted))).isEqualTo(this.secret); } @@ -112,7 +114,8 @@ void migratesFromDeprecatedNullIvCbcToAesCbcBytesEncryptor() { @SuppressWarnings("deprecation") void withSecretWhenAesBytesEncryptorEncryptsThenDecrypts() { CryptoAssumptions.assumeCBCJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey key = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesBytesEncryptor deprecated = new AesBytesEncryptor(key, KeyGenerators.secureRandom(16), AesBytesEncryptor.CipherAlgorithm.CBC); @@ -125,7 +128,8 @@ void withSecretWhenAesBytesEncryptorEncryptsThenDecrypts() { @SuppressWarnings("deprecation") void aesBytesEncryptorWhenEncryptsThenAesCbcBytesEncryptorDecrypts() { CryptoAssumptions.assumeCBCJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey key = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesCbcBytesEncryptor encryptor = AesCbcBytesEncryptor.withSecretKey(key).build(); AesBytesEncryptor deprecated = new AesBytesEncryptor(key, KeyGenerators.secureRandom(16), @@ -138,7 +142,7 @@ void aesBytesEncryptorWhenEncryptsThenAesCbcBytesEncryptorDecrypts() { void roundtripWhenUsingCustomIvGeneratorThenEncryptsAndDecrypts() { CryptoAssumptions.assumeCBCJCE(); BytesKeyGenerator customIvGenerator = mock(BytesKeyGenerator.class); - given(customIvGenerator.generateKey()).willReturn(Hex.decode("4b0febebd439db7ca77153cb254520c3")); + given(customIvGenerator.generateKey()).willReturn(HexFormat.of().parseHex("4b0febebd439db7ca77153cb254520c3")); given(customIvGenerator.getKeyLength()).willReturn(16); AesCbcBytesEncryptor encryptor = AesCbcBytesEncryptor.withPassword(this.password, this.hexSalt) .ivGenerator(customIvGenerator) diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptorTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptorTests.java index 62f52bdcf1c..0813f1ef758 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptorTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/AesGcmBytesEncryptorTests.java @@ -16,12 +16,13 @@ package org.springframework.security.crypto.encrypt; +import java.util.HexFormat; + import javax.crypto.SecretKey; import javax.crypto.spec.PBEKeySpec; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder.SecretKeyFactoryAlgorithm; @@ -53,7 +54,8 @@ void roundtripWhenUsingPasswordAndSaltThenEncryptsAndDecrypts() { @Test void roundtripWhenUsingSecretKeyThenEncryptsAndDecrypts() { CryptoAssumptions.assumeGCMJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey secretKey = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesGcmBytesEncryptor encryptor = AesGcmBytesEncryptor.withSecretKey(secretKey).build(); byte[] encrypted = encryptor.encrypt(this.secret.getBytes()); @@ -64,13 +66,13 @@ void roundtripWhenUsingSecretKeyThenEncryptsAndDecrypts() { void encryptWhenUsingMockIvThenProducesKnownCiphertext() { CryptoAssumptions.assumeGCMJCE(); BytesKeyGenerator mockGenerator = mock(BytesKeyGenerator.class); - given(mockGenerator.generateKey()).willReturn(Hex.decode("4b0febebd439db7ca77153cb254520c3")); + given(mockGenerator.generateKey()).willReturn(HexFormat.of().parseHex("4b0febebd439db7ca77153cb254520c3")); given(mockGenerator.getKeyLength()).willReturn(16); AesGcmBytesEncryptor encryptor = AesGcmBytesEncryptor.withPassword(this.password, this.hexSalt) .ivGenerator(mockGenerator) .build(); byte[] encrypted = encryptor.encrypt(this.secret.getBytes()); - assertThat(Hex.encode(encrypted)) + assertThat(HexFormat.of().formatHex(encrypted)) .isEqualTo("4b0febebd439db7ca77153cb254520c3e4d61ae38207b4e42b820d311dc3d4e0e2f37ed5ee"); assertThat(new String(encryptor.decrypt(encrypted))).isEqualTo(this.secret); } @@ -89,7 +91,8 @@ void encryptProducesUniqueOutputAndIvIsPrepended() { @SuppressWarnings("deprecation") void withSecretWhenAesBytesEncryptorEncryptsThenDecrypts() { CryptoAssumptions.assumeGCMJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey key = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesBytesEncryptor deprecated = new AesBytesEncryptor(key, KeyGenerators.secureRandom(16), AesBytesEncryptor.CipherAlgorithm.GCM); @@ -102,7 +105,8 @@ void withSecretWhenAesBytesEncryptorEncryptsThenDecrypts() { @SuppressWarnings("deprecation") void aesBytesEncryptorWhenEncryptsThenAesGcmBytesEncryptorDecrypts() { CryptoAssumptions.assumeGCMJCE(); - PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), Hex.decode(this.hexSalt), 1024, 256); + PBEKeySpec keySpec = new PBEKeySpec(this.password.toCharArray(), HexFormat.of().parseHex(this.hexSalt), 1024, + 256); SecretKey key = CipherUtils.newSecretKey(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA1.name(), keySpec); AesGcmBytesEncryptor encryptor = AesGcmBytesEncryptor.withSecretKey(key) .ivGenerator(KeyGenerators.secureRandom(12)) diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java index b2698e97f22..5d0a4cb716c 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorEquivalencyTests.java @@ -19,13 +19,13 @@ import java.security.SecureRandom; import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.util.HexFormat; import java.util.Random; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.encrypt.AesBytesEncryptor.CipherAlgorithm; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; @@ -49,7 +49,7 @@ public void setup() { /** insecure salt byte, recommend 64 or larger than 64 */ byte[] saltBytes = new byte[16]; this.secureRandom.nextBytes(saltBytes); - this.salt = new String(Hex.encode(saltBytes)); + this.salt = HexFormat.of().formatHex(saltBytes); } @Test diff --git a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorTests.java b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorTests.java index ee423ff5985..fa8af5a59a6 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptorTests.java @@ -17,13 +17,13 @@ package org.springframework.security.crypto.encrypt; import java.security.SecureRandom; +import java.util.HexFormat; import java.util.UUID; import org.bouncycastle.util.Arrays; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.KeyGenerators; import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +44,7 @@ public void setup() { this.password = UUID.randomUUID().toString(); byte[] saltBytes = new byte[16]; secureRandom.nextBytes(saltBytes); - this.salt = new String(Hex.encode(saltBytes)); + this.salt = HexFormat.of().formatHex(saltBytes); this.testData = new byte[1024 * 1024]; secureRandom.nextBytes(this.testData); } diff --git a/crypto/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java b/crypto/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java index 8413bf1b9c9..4b9c4cbfbf3 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/keygen/KeyGeneratorsTests.java @@ -17,11 +17,10 @@ package org.springframework.security.crypto.keygen; import java.util.Arrays; +import java.util.HexFormat; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; - import static org.assertj.core.api.Assertions.assertThat; public class KeyGeneratorsTests { @@ -61,7 +60,7 @@ public void string() { StringKeyGenerator keyGenerator = KeyGenerators.string(); String hexStringKey = keyGenerator.generateKey(); assertThat(hexStringKey).hasSize(16); - assertThat(Hex.decode(hexStringKey)).hasSize(8); + assertThat(HexFormat.of().parseHex(hexStringKey)).hasSize(8); String hexStringKey2 = keyGenerator.generateKey(); assertThat(hexStringKey.equals(hexStringKey2)).isFalse(); } diff --git a/crypto/src/test/java/org/springframework/security/crypto/password/DigesterTests.java b/crypto/src/test/java/org/springframework/security/crypto/password/DigesterTests.java index d70ce8cb94a..e48de9d8ea6 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/password/DigesterTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/password/DigesterTests.java @@ -16,9 +16,10 @@ package org.springframework.security.crypto.password; +import java.util.HexFormat; + import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import static org.assertj.core.api.Assertions.assertThat; @@ -30,7 +31,7 @@ public void digestIsCorrectFor3Iterations() { Digester digester = new Digester("SHA-1", 3); byte[] result = digester.digest(Utf8.encode("text")); // echo -n text | openssl sha1 -binary | openssl sha1 -binary | openssl sha1 - assertThat(new String(Hex.encode(result))).isEqualTo("3cfa28da425eca5b894f0af2b158adf7001e000f"); + assertThat(HexFormat.of().formatHex(result)).isEqualTo("3cfa28da425eca5b894f0af2b158adf7001e000f"); } } diff --git a/crypto/src/test/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoderTests.java b/crypto/src/test/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoderTests.java index 2331f257092..570caa5b302 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoderTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/password/Pbkdf2PasswordEncoderTests.java @@ -17,10 +17,10 @@ package org.springframework.security.crypto.password; import java.util.Arrays; +import java.util.HexFormat; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.keygen.KeyGenerators; import static org.assertj.core.api.Assertions.assertThat; @@ -116,9 +116,9 @@ public void migrate() { final int saltLength = KeyGenerators.secureRandom().getKeyLength(); String encodedPassword = "ab1146a8458d4ce4e65789e5a3f60e423373cfa10b01abd23739e5ae2fdc37f8e9ede4ae6da65264"; String originalEncodedPassword = "ab1146a8458d4ce4ab1146a8458d4ce4e65789e5a3f60e423373cfa10b01abd23739e5ae2fdc37f8e9ede4ae6da65264"; - byte[] originalBytes = Hex.decode(originalEncodedPassword); + byte[] originalBytes = HexFormat.of().parseHex(originalEncodedPassword); byte[] fixedBytes = Arrays.copyOfRange(originalBytes, saltLength, originalBytes.length); - String fixedHex = String.valueOf(Hex.encode(fixedBytes)); + String fixedHex = String.valueOf(HexFormat.of().formatHex(fixedBytes)); assertThat(fixedHex).isEqualTo(encodedPassword); } diff --git a/crypto/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java b/crypto/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java index 2cae0df7896..f08e648a0bc 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/util/EncodingUtilsTests.java @@ -17,11 +17,10 @@ package org.springframework.security.crypto.util; import java.util.Arrays; +import java.util.HexFormat; import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.codec.Hex; - import static org.assertj.core.api.Assertions.assertThat; public class EncodingUtilsTests { @@ -30,7 +29,7 @@ public class EncodingUtilsTests { public void hexEncode() { byte[] bytes = new byte[] { (byte) 0x01, (byte) 0xFF, (byte) 65, (byte) 66, (byte) 67, (byte) 0xC0, (byte) 0xC1, (byte) 0xC2 }; - String result = new String(Hex.encode(bytes)); + String result = HexFormat.of().formatHex(bytes); assertThat(result).isEqualTo("01ff414243c0c1c2"); } @@ -38,7 +37,7 @@ public void hexEncode() { public void hexDecode() { byte[] bytes = new byte[] { (byte) 0x01, (byte) 0xFF, (byte) 65, (byte) 66, (byte) 67, (byte) 0xC0, (byte) 0xC1, (byte) 0xC2 }; - byte[] result = Hex.decode("01ff414243c0c1c2"); + byte[] result = HexFormat.of().parseHex("01ff414243c0c1c2"); assertThat(Arrays.equals(bytes, result)).isTrue(); } diff --git a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java index 9e9eaf0047b..947c9a36f9b 100644 --- a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java +++ b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2ClientAuthenticationFilterTests.java @@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.authorization.web; import java.nio.charset.StandardCharsets; +import java.util.HexFormat; import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; @@ -36,7 +37,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; @@ -180,19 +180,19 @@ public void doFilterWhenRequestMatchesAndInvalidCredentialsThenInvalidRequestErr public void doFilterWhenRequestMatchesAndClientIdContainsNonPrintableASCIIThenInvalidRequestError() throws Exception { // Hex 00 -> null - String clientId = new String(Hex.decode("00"), StandardCharsets.UTF_8); + String clientId = new String(HexFormat.of().parseHex("00"), StandardCharsets.UTF_8); assertWhenInvalidClientIdThenInvalidRequestError(clientId); // Hex 0a61 -> line feed + a - clientId = new String(Hex.decode("0a61"), StandardCharsets.UTF_8); + clientId = new String(HexFormat.of().parseHex("0a61"), StandardCharsets.UTF_8); assertWhenInvalidClientIdThenInvalidRequestError(clientId); // Hex 1b -> escape - clientId = new String(Hex.decode("1b"), StandardCharsets.UTF_8); + clientId = new String(HexFormat.of().parseHex("1b"), StandardCharsets.UTF_8); assertWhenInvalidClientIdThenInvalidRequestError(clientId); // Hex 1b61 -> escape + a - clientId = new String(Hex.decode("1b61"), StandardCharsets.UTF_8); + clientId = new String(HexFormat.of().parseHex("1b61"), StandardCharsets.UTF_8); assertWhenInvalidClientIdThenInvalidRequestError(clientId); } diff --git a/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiPasswordChecker.java b/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiPasswordChecker.java index cd892c8d968..6b31b53f1de 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiPasswordChecker.java +++ b/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiPasswordChecker.java @@ -20,6 +20,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Collections; +import java.util.HexFormat; import java.util.List; import java.util.Locale; @@ -29,7 +30,6 @@ import org.springframework.security.authentication.password.CompromisedPasswordChecker; import org.springframework.security.authentication.password.CompromisedPasswordDecision; -import org.springframework.security.crypto.codec.Hex; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.client.RestClient; @@ -60,7 +60,7 @@ public CompromisedPasswordDecision check(@Nullable String password) { return new CompromisedPasswordDecision(false); } byte[] hash = getSha1Digest().digest(password.getBytes(StandardCharsets.UTF_8)); - String encoded = new String(Hex.encode(hash)).toUpperCase(Locale.ROOT); + String encoded = HexFormat.of().formatHex(hash).toUpperCase(Locale.ROOT); String prefix = encoded.substring(0, PREFIX_LENGTH); String suffix = encoded.substring(PREFIX_LENGTH); diff --git a/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiReactivePasswordChecker.java b/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiReactivePasswordChecker.java index d3e7b1d53db..8a0991cd489 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiReactivePasswordChecker.java +++ b/web/src/main/java/org/springframework/security/web/authentication/password/HaveIBeenPwnedRestApiReactivePasswordChecker.java @@ -19,6 +19,7 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.HexFormat; import java.util.Locale; import org.apache.commons.logging.Log; @@ -30,7 +31,6 @@ import org.springframework.security.authentication.password.CompromisedPasswordDecision; import org.springframework.security.authentication.password.ReactiveCompromisedPasswordChecker; -import org.springframework.security.crypto.codec.Hex; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.reactive.function.client.WebClient; @@ -57,7 +57,7 @@ public class HaveIBeenPwnedRestApiReactivePasswordChecker implements ReactiveCom @Override public Mono check(@Nullable String password) { - return getHash(password).map((hash) -> new String(Hex.encode(hash))) + return getHash(password).map((hash) -> HexFormat.of().formatHex(hash)) .flatMap(this::findLeakedPassword) .defaultIfEmpty(Boolean.FALSE) .map(CompromisedPasswordDecision::new); diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java index e970e9326e1..f1d64a0cc84 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java @@ -20,6 +20,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Date; +import java.util.HexFormat; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -28,7 +29,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.codec.Hex; import org.springframework.security.crypto.codec.Utf8; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -184,7 +184,7 @@ protected String makeTokenSignature(long tokenExpiryTime, String username, Strin String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey(); try { MessageDigest digest = MessageDigest.getInstance(this.encodingAlgorithm.getDigestAlgorithm()); - return new String(Hex.encode(digest.digest(data.getBytes()))); + return HexFormat.of().formatHex(digest.digest(data.getBytes())); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("No " + this.encodingAlgorithm.name() + " algorithm available!"); @@ -200,7 +200,7 @@ protected String makeTokenSignature(long tokenExpiryTime, String username, @Null String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey(); try { MessageDigest digest = MessageDigest.getInstance(algorithm.getDigestAlgorithm()); - return new String(Hex.encode(digest.digest(data.getBytes()))); + return HexFormat.of().formatHex(digest.digest(data.getBytes())); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("No " + algorithm.name() + " algorithm available!"); diff --git a/web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java b/web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java index d29a98d8ed8..9ddd8ad9a17 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java +++ b/web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java @@ -20,12 +20,12 @@ import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HexFormat; import java.util.List; import java.util.Map; import org.jspecify.annotations.Nullable; -import org.springframework.security.crypto.codec.Hex; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -181,7 +181,7 @@ static String generateDigest(boolean passwordAlreadyEncoded, @Nullable String us static String md5Hex(String data) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); - return new String(Hex.encode(digest.digest(data.getBytes()))); + return HexFormat.of().formatHex(digest.digest(data.getBytes())); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("No MD5 algorithm available!"); diff --git a/web/src/test/java/org/springframework/security/test/web/CodecTestUtils.java b/web/src/test/java/org/springframework/security/test/web/CodecTestUtils.java index 1f032d72323..58d4482ec77 100644 --- a/web/src/test/java/org/springframework/security/test/web/CodecTestUtils.java +++ b/web/src/test/java/org/springframework/security/test/web/CodecTestUtils.java @@ -19,8 +19,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; +import java.util.HexFormat; -import org.springframework.security.crypto.codec.Hex; import org.springframework.util.DigestUtils; public final class CodecTestUtils { @@ -58,7 +58,7 @@ public static String md5Hex(String data) { public static String algorithmHex(String algorithmName, String data) { try { MessageDigest digest = MessageDigest.getInstance(algorithmName); - return new String(Hex.encode(digest.digest(data.getBytes()))); + return HexFormat.of().formatHex(digest.digest(data.getBytes())); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("No " + algorithmName + " algorithm available!");