Merge branch 'switch-to-commons-codec' into 'master'

replace custom digest code with commons-codec v1.15

See merge request fdroid/fdroidclient!1089
This commit is contained in:
Torsten Grote
2022-01-27 11:07:42 +00:00
25 changed files with 3570 additions and 188 deletions

View File

@@ -225,6 +225,7 @@ task pmdMain(type: Pmd) {
ruleSets = [] // otherwise defaults clash with the list in rules.xml
source 'src/main/java'
include '**/*.java'
exclude '**/vendored/**/*.java'
}
task pmdTest(type: Pmd) {
@@ -233,6 +234,7 @@ task pmdTest(type: Pmd) {
ruleSets = [] // otherwise defaults clash with the list in rules.xml
source 'src/test/java', 'src/androidTest/java'
include '**/*.java'
exclude '**/vendored/**/*.java'
}
task pmd(dependsOn: [pmdMain, pmdTest]) {}

View File

@@ -226,18 +226,6 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
Security.addProvider(BOUNCYCASTLE_PROVIDER);
}
public static void enableBouncyCastleOnLollipop() {
if (Build.VERSION.SDK_INT == 21) {
Security.addProvider(BOUNCYCASTLE_PROVIDER);
}
}
public static void disableBouncyCastleOnLollipop() {
if (Build.VERSION.SDK_INT == 21) {
Security.removeProvider(BOUNCYCASTLE_PROVIDER.getName());
}
}
/**
* Initialize the settings needed to run a local swap repo. This should
* only ever be called in {@link WifiStateChangeService.WifiInfoThread},

View File

@@ -28,20 +28,14 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.util.Locale;
public class Hasher {
private MessageDigest digest;
private File file;
private byte[] array;
private final byte[] array;
private String hashCache;
public Hasher(String type, File f) throws NoSuchAlgorithmException {
init(type);
this.file = f;
}
public Hasher(String type, byte[] a) throws NoSuchAlgorithmException {
init(type);
this.array = a;
@@ -84,34 +78,6 @@ public class Hasher {
return hashCache;
}
// Compare the calculated hash to another string, ignoring case,
// returning true if they are equal. The empty string and null are
// considered non-matching.
public boolean match(String otherHash) {
if (otherHash == null) {
return false;
}
if (hashCache == null) {
getHash();
}
return hashCache.equals(otherHash.toLowerCase(Locale.ENGLISH));
}
/**
* Checks the file against the provided hash, returning whether it is a match.
*/
public static boolean isFileMatchingHash(File file, String hash, String hashType) {
if (!file.exists()) {
return false;
}
try {
Hasher hasher = new Hasher(hashType, file);
return hasher.match(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static String hex(Certificate cert) {
byte[] encoded;
try {

View File

@@ -207,11 +207,6 @@ public class IndexUpdater {
throw new UpdateException(repo, downloadedFile + " does not exist!");
}
// Due to a bug in Android 5.0 Lollipop, the inclusion of bouncycastle causes
// breakage when verifying the signature of the downloaded .jar. For more
// details, check out https://gitlab.com/fdroid/fdroidclient/issues/111.
FDroidApp.disableBouncyCastleOnLollipop();
JarFile jarFile = new JarFile(downloadedFile, true);
JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexUpdater.DATA_FILE_NAME);
indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry),
@@ -241,7 +236,6 @@ public class IndexUpdater {
} catch (SAXException | ParserConfigurationException | IOException e) {
throw new UpdateException(repo, "Error parsing index", e);
} finally {
FDroidApp.enableBouncyCastleOnLollipop();
Utils.closeQuietly(indexInputStream);
if (downloadedFile != null) {
if (!downloadedFile.delete()) {

View File

@@ -62,7 +62,6 @@ import org.fdroid.fdroid.data.SanitizedFile;
import org.fdroid.fdroid.data.Schema;
import org.xml.sax.XMLReader;
import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
@@ -104,6 +103,8 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
import vendored.org.apache.commons.codec.binary.Hex;
import vendored.org.apache.commons.codec.digest.DigestUtils;
public final class Utils {
@@ -417,6 +418,15 @@ public final class Utils {
return ret;
}
/**
* Checks the file against the provided hash, returning whether it is a match.
*/
public static boolean isFileMatchingHash(File file, String hash, String hashType) {
if (file == null || !file.exists() || TextUtils.isEmpty(hash)) {
return false;
}
return hash.equals(getFileHexDigest(file, hashType));
}
/**
* Get the fingerprint used to represent an APK signing key in F-Droid.
@@ -427,7 +437,7 @@ public final class Utils {
* @see org.fdroid.fdroid.data.Apk#sig
*/
public static String getsig(byte[] rawCertBytes) {
return Utils.hashBytes(toHexString(rawCertBytes).getBytes(), "md5");
return DigestUtils.md5Hex(Hex.encodeHexString(rawCertBytes).getBytes());
}
/**
@@ -453,36 +463,6 @@ public final class Utils {
return sigHash;
}
/**
* There is a method {@link java.util.Locale#forLanguageTag(String)} which would be useful
* for this, however it doesn't deal with android-specific language tags, which are a little
* different. For example, android language tags may have an "r" before the country code,
* such as "zh-rHK", however {@link java.util.Locale} expects them to be "zr-HK".
*/
public static Locale getLocaleFromAndroidLangTag(String languageTag) {
if (TextUtils.isEmpty(languageTag)) {
return null;
}
final String[] parts = languageTag.split("-");
if (parts.length == 1) {
return new Locale(parts[0]);
}
if (parts.length == 2) {
String country = parts[1];
// Some languages have an "r" before the country as per the values folders, such
// as "zh-rCN". As far as the Locale class is concerned, the "r" is
// not helpful, and this should be "zh-CN". Thus, we will
// strip the "r" when found.
if (country.charAt(0) == 'r' && country.length() == 3) {
country = country.substring(1);
}
return new Locale(parts[0], country);
}
Log.e(TAG, "Locale could not be parsed from language tag: " + languageTag);
return new Locale(languageTag);
}
/**
* Gets the {@link RequestOptions} instance used to configure
* {@link Glide} instances used to display app icons that should always be
@@ -514,24 +494,9 @@ public final class Utils {
Glide.with(context).load(app.getIconUrl(iv.getContext())).apply(iconRequestOptions).into(iv);
}
// this is all new stuff being added
public static String hashBytes(byte[] input, String algo) {
try {
MessageDigest md = MessageDigest.getInstance(algo);
byte[] hashBytes = md.digest(input);
String hash = toHexString(hashBytes);
md.reset();
return hash;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Device does not support " + algo + " MessageDisgest algorithm");
return null;
}
}
/**
* Get the checksum hash of the file {@code apk} using the algorithm in {@code algo}.
* {@code apk} must exist on the filesystem and {@code algo} must be supported
* Get the checksum hash of the file {@code file} using the algorithm in {@code hashAlgo}.
* {@code file} must exist on the filesystem and {@code hashAlgo} must be supported
* by this device, otherwise an {@link IllegalArgumentException} is thrown. This
* method must be very defensive about checking whether the file exists, since APKs
* can be uninstalled/deleted in background at any time, even if this is in the
@@ -542,57 +507,24 @@ public final class Utils {
* exception-message-parsing-and-throwing-a-new-ignorable-exception-hackery is
* probably warranted. See https://www.gitlab.com/fdroid/fdroidclient/issues/855
* for more detail.
*
* @see <a href="https://gitlab.com/fdroid/fdroidclient/-/merge_requests/1089#note_822501322">forced to vendor Apache Commons Codec</a>
*/
@Nullable
public static String getBinaryHash(File apk, String algo) {
FileInputStream fis = null;
public static String getFileHexDigest(File file, String hashAlgo) {
try {
MessageDigest md = MessageDigest.getInstance(algo);
fis = new FileInputStream(apk);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] dataBytes = new byte[8192];
int nread;
while ((nread = bis.read(dataBytes)) != -1) { // NOPMD Avoid assignments in operands
md.update(dataBytes, 0, nread);
}
byte[] mdbytes = md.digest();
return toHexString(mdbytes);
return Hex.encodeHexString(DigestUtils.digest(DigestUtils.getDigest(hashAlgo), file));
} catch (IOException e) {
String message = e.getMessage();
if (message.contains("read failed: EIO (I/O error)")) {
Utils.debugLog(TAG, "potential filesystem corruption while accessing " + apk + ": " + message);
Utils.debugLog(TAG, "potential filesystem corruption while accessing " + file + ": " + message);
} else if (message.contains(" ENOENT ")) {
Utils.debugLog(TAG, apk + " vanished: " + message);
Utils.debugLog(TAG, file + " vanished: " + message);
}
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
} finally {
closeQuietly(fis);
}
return null;
}
/**
* Computes the base 16 representation of the byte array argument.
*
* @param bytes an array of bytes.
* @return the bytes represented as a string of lowercase hexadecimal digits.
* @see <a href="https://stackoverflow.com/a/9855338">source</a>
*/
public static String toHexString(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_LOOKUP_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_LOOKUP_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
private static final char[] HEX_LOOKUP_ARRAY = "0123456789abcdef".toCharArray();
public static int parseInt(String str, int fallback) {
if (str == null || str.length() == 0) {
return fallback;

View File

@@ -24,7 +24,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
@@ -431,7 +430,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
app.installedApk.hash = installedApp.getHash();
} else if (apkFile.canRead()) {
String hashType = "sha256";
String hash = Utils.getBinaryHash(apkFile, hashType);
String hash = Utils.getFileHexDigest(apkFile, hashType);
if (TextUtils.isEmpty(hash)) {
return null;
}
@@ -876,10 +875,10 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
if (Integer.parseInt(segments[1]) <= apk.versionCode) {
if ("main".equals(segments[0])) {
apk.obbMainFile = filename;
apk.obbMainFileSha256 = Utils.getBinaryHash(f, apk.hashType);
apk.obbMainFileSha256 = Utils.getFileHexDigest(f, apk.hashType);
} else if ("patch".equals(segments[0])) {
apk.obbPatchFile = filename;
apk.obbPatchFileSha256 = Utils.getBinaryHash(f, apk.hashType);
apk.obbPatchFileSha256 = Utils.getFileHexDigest(f, apk.hashType);
}
}
}
@@ -934,35 +933,25 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
throw new CertificateEncodingException("null signed entry!");
}
byte[] rawCertBytes;
// Due to a bug in android 5.0 lollipop, the inclusion of BouncyCastle causes
// breakage when verifying the signature of most .jars. For more
// details, check out https://gitlab.com/fdroid/fdroidclient/issues/111.
try {
FDroidApp.disableBouncyCastleOnLollipop();
final InputStream tmpIn = apkJar.getInputStream(aSignedEntry);
byte[] buff = new byte[2048];
//noinspection StatementWithEmptyBody
while (tmpIn.read(buff, 0, buff.length) != -1) {
/*
* NOP - apparently have to READ from the JarEntry before you can
* call getCerficates() and have it return != null. Yay Java.
*/
}
tmpIn.close();
if (aSignedEntry.getCertificates() == null
|| aSignedEntry.getCertificates().length == 0) {
apkJar.close();
throw new CertificateEncodingException("No Certificates found!");
}
final Certificate signer = aSignedEntry.getCertificates()[0];
rawCertBytes = signer.getEncoded();
} finally {
FDroidApp.enableBouncyCastleOnLollipop();
final InputStream tmpIn = apkJar.getInputStream(aSignedEntry);
byte[] buff = new byte[2048];
//noinspection StatementWithEmptyBody
while (tmpIn.read(buff, 0, buff.length) != -1) {
/*
* NOP - apparently have to READ from the JarEntry before you can
* call getCerficates() and have it return != null. Yay Java.
*/
}
tmpIn.close();
if (aSignedEntry.getCertificates() == null
|| aSignedEntry.getCertificates().length == 0) {
apkJar.close();
throw new CertificateEncodingException("No Certificates found!");
}
final Certificate signer = aSignedEntry.getCertificates()[0];
byte[] rawCertBytes = signer.getEncoded();
apkJar.close();
apk.sig = Utils.getsig(rawCertBytes);

View File

@@ -299,7 +299,7 @@ public class InstalledAppProviderService extends JobIntentService {
if (apk.exists() && apk.canRead()) {
try {
String hashType = "sha256";
String hash = Utils.getBinaryHash(apk, hashType);
String hash = Utils.getFileHexDigest(apk, hashType);
insertAppIntoDb(this, packageInfo, hashType, hash);
} catch (IllegalArgumentException e) {
Utils.debugLog(TAG, e.getMessage());

View File

@@ -25,7 +25,7 @@ import android.content.pm.PackageInfo;
import android.net.Uri;
import org.apache.commons.io.FileUtils;
import org.fdroid.fdroid.Hasher;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
@@ -89,7 +89,7 @@ public class ApkCache {
FileUtils.copyFile(apkFile, sanitizedApkFile);
// verify copied file's hash with expected hash from Apk class
if (verifyHash && !Hasher.isFileMatchingHash(sanitizedApkFile, hash, hashType)) {
if (verifyHash && !Utils.isFileMatchingHash(sanitizedApkFile, hash, hashType)) {
FileUtils.deleteQuietly(apkFile);
throw new IOException(apkFile + " failed to verify!");
}
@@ -137,7 +137,7 @@ public class ApkCache {
*/
public static boolean apkIsCached(File apkFile, Apk apkToCheck) {
return apkFile.length() == apkToCheck.size &&
Hasher.isFileMatchingHash(apkFile, apkToCheck.hash, apkToCheck.hashType);
Utils.isFileMatchingHash(apkFile, apkToCheck.hash, apkToCheck.hashType);
}
/**

View File

@@ -33,10 +33,14 @@ import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import vendored.org.apache.commons.codec.binary.Hex;
/**
* NOTE: Silly Android API naming: APK signatures are actually certificates!
* Thus, we are comparing certificates (including the public key) used to sign an APK,
* not the actual APK signature.
*
* @see <a href="https://gitlab.com/fdroid/fdroidclient/-/merge_requests/1089#note_822501322">forced to vendor Apache Commons Codec</a>
*/
class ApkSignatureVerifier {
@@ -69,8 +73,8 @@ class ApkSignatureVerifier {
}
Utils.debugLog(TAG, "Signature mismatch!");
Utils.debugLog(TAG, "APK sig: " + Utils.toHexString(getApkSignature(apkFile)));
Utils.debugLog(TAG, "F-Droid sig: " + Utils.toHexString(getFDroidSignature()));
Utils.debugLog(TAG, "APK sig: " + Hex.encodeHexString(getApkSignature(apkFile)));
Utils.debugLog(TAG, "F-Droid sig: " + Hex.encodeHexString(getFDroidSignature()));
return false;
}

View File

@@ -17,7 +17,6 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Hasher;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.compat.PackageManagerCompat;
import org.fdroid.fdroid.data.Apk;
@@ -33,6 +32,8 @@ import java.io.IOException;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import static vendored.org.apache.commons.codec.digest.MessageDigestAlgorithms.SHA_256;
/**
* Manages the whole process when a background update triggers an install or the user
* requests an APK to be installed. It handles checking whether the APK is cached,
@@ -86,6 +87,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
* has a different name/description/summary, etc).
*
* @see <a href="https://developer.android.com/google/play/expansion-files.html">APK Expansion Files</a>
* @see <a href="https://gitlab.com/fdroid/fdroidclient/-/merge_requests/1089#note_822501322">forced to vendor Apache Commons Codec</a>
*/
@SuppressWarnings("LineLength")
public class InstallManagerService extends Service {
@@ -281,7 +283,7 @@ public class InstallManagerService extends Service {
+ " to " + localApkUri);
try {
if (Hasher.isFileMatchingHash(localFile, hash, "sha256")) {
if (Utils.isFileMatchingHash(localFile, hash, SHA_256)) {
Utils.debugLog(TAG, "Installing OBB " + localFile + " to " + obbDestFile);
FileUtils.forceMkdirParent(obbDestFile);
FileUtils.copyFile(localFile, obbDestFile);

View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Defines common decoding methods for byte array decoders.
*
*/
public interface BinaryDecoder extends Decoder {
/**
* Decodes a byte array and returns the results as a byte array.
*
* @param source
* A byte array which has been encoded with the appropriate encoder
* @return a byte array that contains decoded content
* @throws DecoderException
* A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
*/
byte[] decode(byte[] source) throws DecoderException;
}

View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Defines common encoding methods for byte array encoders.
*
*/
public interface BinaryEncoder extends Encoder {
/**
* Encodes a byte array and return the encoded data as a byte array.
*
* @param source
* Data to be encoded
* @return A byte array containing the encoded data
* @throws EncoderException
* thrown if the Encoder encounters a failure condition during the encoding process.
*/
byte[] encode(byte[] source) throws EncoderException;
}

View File

@@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Character encoding names required of every implementation of the Java platform.
*
* From the Java documentation <a
* href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>:
* <p>
* <cite>Every implementation of the Java platform is required to support the following character encodings. Consult the
* release documentation for your implementation to see if any other encodings are supported. Consult the release
* documentation for your implementation to see if any other encodings are supported.</cite>
* </p>
*
* <ul>
* <li>{@code US-ASCII}<p>
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.</p></li>
* <li>{@code ISO-8859-1}<p>
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.</p></li>
* <li>{@code UTF-8}<p>
* Eight-bit Unicode Transformation Format.</p></li>
* <li>{@code UTF-16BE}<p>
* Sixteen-bit Unicode Transformation Format, big-endian byte order.</p></li>
* <li>{@code UTF-16LE}<p>
* Sixteen-bit Unicode Transformation Format, little-endian byte order.</p></li>
* <li>{@code UTF-16}<p>
* Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
* accepted on input, big-endian used on output.)</p></li>
* </ul>
*
* This perhaps would best belong in the [lang] project. Even if a similar interface is defined in [lang], it is not
* foreseen that [codec] would be made to depend on [lang].
*
* <p>
* This class is immutable and thread-safe.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @since 1.4
*/
public class CharEncoding {
/**
* CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String ISO_8859_1 = "ISO-8859-1";
/**
* Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String US_ASCII = "US-ASCII";
/**
* Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
* (either order accepted on input, big-endian used on output)
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_16 = "UTF-16";
/**
* Sixteen-bit Unicode Transformation Format, big-endian byte order.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_16BE = "UTF-16BE";
/**
* Sixteen-bit Unicode Transformation Format, little-endian byte order.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_16LE = "UTF-16LE";
/**
* Eight-bit Unicode Transformation Format.
* <p>
* Every implementation of the Java platform is required to support this character encoding.
* </p>
*
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
*/
public static final String UTF_8 = "UTF-8";
}

View File

@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Provides the highest level of abstraction for Decoders.
* <p>
* This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface.
* Allows a user to pass a generic Object to any Decoder implementation in the codec package.
* <p>
* One of the two interfaces at the center of the codec package.
*
*/
public interface Decoder {
/**
* Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will
* try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a
* {@link ClassCastException} occurs this decode method will throw a DecoderException.
*
* @param source
* the object to decode
* @return a 'decoded" object
* @throws DecoderException
* a decoder exception can be thrown for any number of reasons. Some good candidates are that the
* parameter passed to this method is null, a param cannot be cast to the appropriate type for a
* specific encoder.
*/
Object decode(Object source) throws DecoderException;
}

View File

@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder}
* encounters a decoding specific exception such as invalid data, or characters outside of the expected range.
*
*/
public class DecoderException extends Exception {
/**
* Declares the Serial Version Uid.
*
* @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
*/
private static final long serialVersionUID = 1L;
/**
* Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may
* subsequently be initialized by a call to {@link #initCause}.
*
* @since 1.4
*/
public DecoderException() {
}
/**
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
* be initialized by a call to {@link #initCause}.
*
* @param message
* The detail message which is saved for later retrieval by the {@link #getMessage()} method.
*/
public DecoderException(final String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and cause.
* <p>
* Note that the detail message associated with {@code cause} is not automatically incorporated into this
* exception's detail message.
*
* @param message
* The detail message which is saved for later retrieval by the {@link #getMessage()} method.
* @param cause
* The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
* value is permitted, and indicates that the cause is nonexistent or unknown.
* @since 1.4
*/
public DecoderException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Constructs a new exception with the specified cause and a detail message of <code>(cause==null ?
* null : cause.toString())</code> (which typically contains the class and detail message of {@code cause}).
* This constructor is useful for exceptions that are little more than wrappers for other throwables.
*
* @param cause
* The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
* value is permitted, and indicates that the cause is nonexistent or unknown.
* @since 1.4
*/
public DecoderException(final Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Provides the highest level of abstraction for Encoders.
* <p>
* This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this
* common generic interface which allows a user to pass a generic Object to any Encoder implementation
* in the codec package.
*
*/
public interface Encoder {
/**
* Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be
* {@code byte[]} or {@code String}s depending on the implementation used.
*
* @param source
* An object to encode
* @return An "encoded" Object
* @throws EncoderException
* An encoder exception is thrown if the encoder experiences a failure condition during the encoding
* process.
*/
Object encode(Object source) throws EncoderException;
}

View File

@@ -0,0 +1,87 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec;
/**
* Thrown when there is a failure condition during the encoding process. This exception is thrown when an
* {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum,
* characters outside of the expected range.
*
*/
public class EncoderException extends Exception {
/**
* Declares the Serial Version Uid.
*
* @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
*/
private static final long serialVersionUID = 1L;
/**
* Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may
* subsequently be initialized by a call to {@link #initCause}.
*
* @since 1.4
*/
public EncoderException() {
}
/**
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
* be initialized by a call to {@link #initCause}.
*
* @param message
* a useful message relating to the encoder specific error.
*/
public EncoderException(final String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* <p>
* Note that the detail message associated with {@code cause} is not automatically incorporated into this
* exception's detail message.
* </p>
*
* @param message
* The detail message which is saved for later retrieval by the {@link #getMessage()} method.
* @param cause
* The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
* value is permitted, and indicates that the cause is nonexistent or unknown.
* @since 1.4
*/
public EncoderException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Constructs a new exception with the specified cause and a detail message of <code>(cause==null ?
* null : cause.toString())</code> (which typically contains the class and detail message of {@code cause}).
* This constructor is useful for exceptions that are little more than wrappers for other throwables.
*
* @param cause
* The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
* value is permitted, and indicates that the cause is nonexistent or unknown.
* @since 1.4
*/
public EncoderException(final Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec.binary;
/**
* <p>
* Operations on {@link CharSequence} that are {@code null} safe.
* </p>
* <p>
* Copied from Apache Commons Lang r1586295 on April 10, 2014 (day of 3.3.2 release).
* </p>
*
* @see CharSequence
* @since 1.10
*/
public class CharSequenceUtils {
/**
* Green implementation of regionMatches.
*
* <p>Note: This function differs from the current implementation in Apache Commons Lang
* where the input indices are not valid. It is only used within this package.
*
* @param cs
* the {@code CharSequence} to be processed
* @param ignoreCase
* whether or not to be case insensitive
* @param thisStart
* the index to start on the {@code cs} CharSequence
* @param substring
* the {@code CharSequence} to be looked for
* @param start
* the index to start on the {@code substring} CharSequence
* @param length
* character length of the region
* @return whether the region matched
*/
static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
final CharSequence substring, final int start, final int length) {
if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
}
int index1 = thisStart;
int index2 = start;
int tmpLen = length;
while (tmpLen-- > 0) {
final char c1 = cs.charAt(index1++);
final char c2 = substring.charAt(index2++);
if (c1 == c2) {
continue;
}
if (!ignoreCase) {
return false;
}
// The same check as in String.regionMatches():
if (Character.toUpperCase(c1) != Character.toUpperCase(c2) &&
Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,567 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec.binary;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import vendored.org.apache.commons.codec.BinaryDecoder;
import vendored.org.apache.commons.codec.BinaryEncoder;
import vendored.org.apache.commons.codec.CharEncoding;
import vendored.org.apache.commons.codec.DecoderException;
import vendored.org.apache.commons.codec.EncoderException;
/**
* Converts hexadecimal Strings. The Charset used for certain operation can be set, the default is set in
* {@link #DEFAULT_CHARSET_NAME}
*
* This class is thread-safe.
*
* @since 1.1
*/
public class Hex implements BinaryEncoder, BinaryDecoder {
/**
* Default charset is {@link StandardCharsets#UTF_8}.
*
* @since 1.7
*/
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
/**
* Default charset name is {@link CharEncoding#UTF_8}.
*
* @since 1.4
*/
public static final String DEFAULT_CHARSET_NAME = CharEncoding.UTF_8;
/**
* Used to build output as hex.
*/
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
'e', 'f' };
/**
* Used to build output as hex.
*/
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F' };
/**
* Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
* returned array will be half the length of the passed array, as it takes two characters to represent any given
* byte. An exception is thrown if the passed char array has an odd number of elements.
*
* @param data An array of characters containing hexadecimal digits
* @return A byte array containing binary data decoded from the supplied char array.
* @throws DecoderException Thrown if an odd number of characters or illegal characters are supplied
*/
public static byte[] decodeHex(final char[] data) throws DecoderException {
final byte[] out = new byte[data.length >> 1];
decodeHex(data, out, 0);
return out;
}
/**
* Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
* returned array will be half the length of the passed array, as it takes two characters to represent any given
* byte. An exception is thrown if the passed char array has an odd number of elements.
*
* @param data An array of characters containing hexadecimal digits
* @param out A byte array to contain the binary data decoded from the supplied char array.
* @param outOffset The position within {@code out} to start writing the decoded bytes.
* @return the number of bytes written to {@code out}.
* @throws DecoderException Thrown if an odd number of characters or illegal characters are supplied
* @since 1.15
*/
public static int decodeHex(final char[] data, final byte[] out, final int outOffset) throws DecoderException {
final int len = data.length;
if ((len & 0x01) != 0) {
throw new DecoderException("Odd number of characters.");
}
final int outLen = len >> 1;
if (out.length - outOffset < outLen) {
throw new DecoderException("Output array is not large enough to accommodate decoded data.");
}
// two characters form the hex value.
for (int i = outOffset, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return outLen;
}
/**
* Converts a String representing hexadecimal values into an array of bytes of those same values. The returned array
* will be half the length of the passed String, as it takes two characters to represent any given byte. An
* exception is thrown if the passed String has an odd number of elements.
*
* @param data A String containing hexadecimal digits
* @return A byte array containing binary data decoded from the supplied char array.
* @throws DecoderException Thrown if an odd number of characters or illegal characters are supplied
* @since 1.11
*/
public static byte[] decodeHex(final String data) throws DecoderException {
return decodeHex(data.toCharArray());
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
* The returned array will be double the length of the passed array, as it takes two characters to represent any
* given byte.
*
* @param data a byte[] to convert to hex characters
* @return A char[] containing lower-case hexadecimal characters
*/
public static char[] encodeHex(final byte[] data) {
return encodeHex(data, true);
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
* The returned array will be double the length of the passed array, as it takes two characters to represent any
* given byte.
*
* @param data a byte[] to convert to Hex characters
* @param toLowerCase {@code true} converts to lowercase, {@code false} to uppercase
* @return A char[] containing hexadecimal characters in the selected case
* @since 1.4
*/
public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
* The returned array will be double the length of the passed array, as it takes two characters to represent any
* given byte.
*
* @param data a byte[] to convert to hex characters
* @param toDigits the output alphabet (must contain at least 16 chars)
* @return A char[] containing the appropriate characters from the alphabet For best results, this should be either
* upper- or lower-case hex.
* @since 1.4
*/
protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
final int dataLength = data.length;
final char[] out = new char[dataLength << 1];
encodeHex(data, 0, dataLength, toDigits, out, 0);
return out;
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
*
* @param data a byte[] to convert to hex characters
* @param dataOffset the position in {@code data} to start encoding from
* @param dataLen the number of bytes from {@code dataOffset} to encode
* @param toLowerCase {@code true} converts to lowercase, {@code false} to uppercase
* @return A char[] containing the appropriate characters from the alphabet For best results, this should be either
* upper- or lower-case hex.
* @since 1.15
*/
public static char[] encodeHex(final byte[] data, final int dataOffset, final int dataLen,
final boolean toLowerCase) {
final char[] out = new char[dataLen << 1];
encodeHex(data, dataOffset, dataLen, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER, out, 0);
return out;
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
*
* @param data a byte[] to convert to hex characters
* @param dataOffset the position in {@code data} to start encoding from
* @param dataLen the number of bytes from {@code dataOffset} to encode
* @param toLowerCase {@code true} converts to lowercase, {@code false} to uppercase
* @param out a char[] which will hold the resultant appropriate characters from the alphabet.
* @param outOffset the position within {@code out} at which to start writing the encoded characters.
* @since 1.15
*/
public static void encodeHex(final byte[] data, final int dataOffset, final int dataLen,
final boolean toLowerCase, final char[] out, final int outOffset) {
encodeHex(data, dataOffset, dataLen, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER, out, outOffset);
}
/**
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
*
* @param data a byte[] to convert to hex characters
* @param dataOffset the position in {@code data} to start encoding from
* @param dataLen the number of bytes from {@code dataOffset} to encode
* @param toDigits the output alphabet (must contain at least 16 chars)
* @param out a char[] which will hold the resultant appropriate characters from the alphabet.
* @param outOffset the position within {@code out} at which to start writing the encoded characters.
*/
private static void encodeHex(final byte[] data, final int dataOffset, final int dataLen, final char[] toDigits,
final char[] out, final int outOffset) {
// two characters form the hex value.
for (int i = dataOffset, j = outOffset; i < dataOffset + dataLen; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
}
/**
* Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The
* returned array will be double the length of the passed array, as it takes two characters to represent any given
* byte.
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param data a byte buffer to convert to hex characters
* @return A char[] containing lower-case hexadecimal characters
* @since 1.11
*/
public static char[] encodeHex(final ByteBuffer data) {
return encodeHex(data, true);
}
/**
* Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The
* returned array will be double the length of the passed array, as it takes two characters to represent any given
* byte.
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param data a byte buffer to convert to hex characters
* @param toLowerCase {@code true} converts to lowercase, {@code false} to uppercase
* @return A char[] containing hexadecimal characters in the selected case
* @since 1.11
*/
public static char[] encodeHex(final ByteBuffer data, final boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The
* returned array will be double the length of the passed array, as it takes two characters to represent any given
* byte.
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param byteBuffer a byte buffer to convert to hex characters
* @param toDigits the output alphabet (must be at least 16 characters)
* @return A char[] containing the appropriate characters from the alphabet For best results, this should be either
* upper- or lower-case hex.
* @since 1.11
*/
protected static char[] encodeHex(final ByteBuffer byteBuffer, final char[] toDigits) {
return encodeHex(toByteArray(byteBuffer), toDigits);
}
/**
* Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
* String will be double the length of the passed array, as it takes two characters to represent any given byte.
*
* @param data a byte[] to convert to hex characters
* @return A String containing lower-case hexadecimal characters
* @since 1.4
*/
public static String encodeHexString(final byte[] data) {
return new String(encodeHex(data));
}
/**
* Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
* String will be double the length of the passed array, as it takes two characters to represent any given byte.
*
* @param data a byte[] to convert to hex characters
* @param toLowerCase {@code true} converts to lowercase, {@code false} to uppercase
* @return A String containing lower-case hexadecimal characters
* @since 1.11
*/
public static String encodeHexString(final byte[] data, final boolean toLowerCase) {
return new String(encodeHex(data, toLowerCase));
}
/**
* Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
* String will be double the length of the passed array, as it takes two characters to represent any given byte.
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param data a byte buffer to convert to hex characters
* @return A String containing lower-case hexadecimal characters
* @since 1.11
*/
public static String encodeHexString(final ByteBuffer data) {
return new String(encodeHex(data));
}
/**
* Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
* String will be double the length of the passed array, as it takes two characters to represent any given byte.
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param data a byte buffer to convert to hex characters
* @param toLowerCase {@code true} converts to lowercase, {@code false} to uppercase
* @return A String containing lower-case hexadecimal characters
* @since 1.11
*/
public static String encodeHexString(final ByteBuffer data, final boolean toLowerCase) {
return new String(encodeHex(data, toLowerCase));
}
/**
* Convert the byte buffer to a byte array. All bytes identified by
* {@link ByteBuffer#remaining()} will be used.
*
* @param byteBuffer the byte buffer
* @return the byte[]
*/
private static byte[] toByteArray(final ByteBuffer byteBuffer) {
final int remaining = byteBuffer.remaining();
// Use the underlying buffer if possible
if (byteBuffer.hasArray()) {
final byte[] byteArray = byteBuffer.array();
if (remaining == byteArray.length) {
byteBuffer.position(remaining);
return byteArray;
}
}
// Copy the bytes
final byte[] byteArray = new byte[remaining];
byteBuffer.get(byteArray);
return byteArray;
}
/**
* Converts a hexadecimal character to an integer.
*
* @param ch A character to convert to an integer digit
* @param index The index of the character in the source
* @return An integer
* @throws DecoderException Thrown if ch is an illegal hex character
*/
protected static int toDigit(final char ch, final int index) throws DecoderException {
final int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new DecoderException("Illegal hexadecimal character " + ch + " at index " + index);
}
return digit;
}
private final Charset charset;
/**
* Creates a new codec with the default charset name {@link #DEFAULT_CHARSET}
*/
public Hex() {
// use default encoding
this.charset = DEFAULT_CHARSET;
}
/**
* Creates a new codec with the given Charset.
*
* @param charset the charset.
* @since 1.7
*/
public Hex(final Charset charset) {
this.charset = charset;
}
/**
* Creates a new codec with the given charset name.
*
* @param charsetName the charset name.
* @throws java.nio.charset.UnsupportedCharsetException If the named charset is unavailable
* @since 1.4
* @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
*/
public Hex(final String charsetName) {
this(Charset.forName(charsetName));
}
/**
* Converts an array of character bytes representing hexadecimal values into an array of bytes of those same values.
* The returned array will be half the length of the passed array, as it takes two characters to represent any given
* byte. An exception is thrown if the passed char array has an odd number of elements.
*
* @param array An array of character bytes containing hexadecimal digits
* @return A byte array containing binary data decoded from the supplied byte array (representing characters).
* @throws DecoderException Thrown if an odd number of characters is supplied to this function
* @see #decodeHex(char[])
*/
@Override
public byte[] decode(final byte[] array) throws DecoderException {
return decodeHex(new String(array, getCharset()).toCharArray());
}
/**
* Converts a buffer of character bytes representing hexadecimal values into an array of bytes of those same values.
* The returned array will be half the length of the passed array, as it takes two characters to represent any given
* byte. An exception is thrown if the passed char array has an odd number of elements.
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param buffer An array of character bytes containing hexadecimal digits
* @return A byte array containing binary data decoded from the supplied byte array (representing characters).
* @throws DecoderException Thrown if an odd number of characters is supplied to this function
* @see #decodeHex(char[])
* @since 1.11
*/
public byte[] decode(final ByteBuffer buffer) throws DecoderException {
return decodeHex(new String(toByteArray(buffer), getCharset()).toCharArray());
}
/**
* Converts a String or an array of character bytes representing hexadecimal values into an array of bytes of those
* same values. The returned array will be half the length of the passed String or array, as it takes two characters
* to represent any given byte. An exception is thrown if the passed char array has an odd number of elements.
*
* @param object A String, ByteBuffer, byte[], or an array of character bytes containing hexadecimal digits
* @return A byte array containing binary data decoded from the supplied byte array (representing characters).
* @throws DecoderException Thrown if an odd number of characters is supplied to this function or the object is not
* a String or char[]
* @see #decodeHex(char[])
*/
@Override
public Object decode(final Object object) throws DecoderException {
if (object instanceof String) {
return decode(((String) object).toCharArray());
}
if (object instanceof byte[]) {
return decode((byte[]) object);
}
if (object instanceof ByteBuffer) {
return decode((ByteBuffer) object);
}
try {
return decodeHex((char[]) object);
} catch (final ClassCastException e) {
throw new DecoderException(e.getMessage(), e);
}
}
/**
* Converts an array of bytes into an array of bytes for the characters representing the hexadecimal values of each
* byte in order. The returned array will be double the length of the passed array, as it takes two characters to
* represent any given byte.
* <p>
* The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
* {@link #getCharset()}.
* </p>
*
* @param array a byte[] to convert to hex characters
* @return A byte[] containing the bytes of the lower-case hexadecimal characters
* @since 1.7 No longer throws IllegalStateException if the charsetName is invalid.
* @see #encodeHex(byte[])
*/
@Override
public byte[] encode(final byte[] array) {
return encodeHexString(array).getBytes(this.getCharset());
}
/**
* Converts byte buffer into an array of bytes for the characters representing the hexadecimal values of each byte
* in order. The returned array will be double the length of the passed array, as it takes two characters to
* represent any given byte.
*
* <p>The conversion from hexadecimal characters to the returned bytes is performed with the charset named by
* {@link #getCharset()}.</p>
*
* <p>All bytes identified by {@link ByteBuffer#remaining()} will be used; after this method
* the value {@link ByteBuffer#remaining() remaining()} will be zero.</p>
*
* @param array a byte buffer to convert to hex characters
* @return A byte[] containing the bytes of the lower-case hexadecimal characters
* @see #encodeHex(byte[])
* @since 1.11
*/
public byte[] encode(final ByteBuffer array) {
return encodeHexString(array).getBytes(this.getCharset());
}
/**
* Converts a String or an array of bytes into an array of characters representing the hexadecimal values of each
* byte in order. The returned array will be double the length of the passed String or array, as it takes two
* characters to represent any given byte.
* <p>
* The conversion from hexadecimal characters to bytes to be encoded to performed with the charset named by
* {@link #getCharset()}.
* </p>
*
* @param object a String, ByteBuffer, or byte[] to convert to hex characters
* @return A char[] containing lower-case hexadecimal characters
* @throws EncoderException Thrown if the given object is not a String or byte[]
* @see #encodeHex(byte[])
*/
@Override
public Object encode(final Object object) throws EncoderException {
final byte[] byteArray;
if (object instanceof String) {
byteArray = ((String) object).getBytes(this.getCharset());
} else if (object instanceof ByteBuffer) {
byteArray = toByteArray((ByteBuffer) object);
} else {
try {
byteArray = (byte[]) object;
} catch (final ClassCastException e) {
throw new EncoderException(e.getMessage(), e);
}
}
return encodeHex(byteArray);
}
/**
* Gets the charset.
*
* @return the charset.
* @since 1.7
*/
public Charset getCharset() {
return this.charset;
}
/**
* Gets the charset name.
*
* @return the charset name.
* @since 1.4
*/
public String getCharsetName() {
return this.charset.name();
}
/**
* Returns a string representation of the object, which includes the charset name.
*
* @return a string representation of the object.
*/
@Override
public String toString() {
return super.toString() + "[charsetName=" + this.charset + "]";
}
}

View File

@@ -0,0 +1,419 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec.binary;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import vendored.org.apache.commons.codec.CharEncoding;
/**
* Converts String to and from bytes using the encodings required by the Java specification. These encodings are
* specified in <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">
* Standard charsets</a>.
*
* <p>This class is immutable and thread-safe.</p>
*
* @see CharEncoding
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @since 1.4
*/
public class StringUtils {
/**
* <p>
* Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
* </p>
*
* <p>
* {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal.
* The comparison is case sensitive.
* </p>
*
* <pre>
* StringUtils.equals(null, null) = true
* StringUtils.equals(null, "abc") = false
* StringUtils.equals("abc", null) = false
* StringUtils.equals("abc", "abc") = true
* StringUtils.equals("abc", "ABC") = false
* </pre>
*
* <p>
* Copied from Apache Commons Lang r1583482 on April 10, 2014 (day of 3.3.2 release).
* </p>
*
* @see Object#equals(Object)
* @param cs1
* the first CharSequence, may be {@code null}
* @param cs2
* the second CharSequence, may be {@code null}
* @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
* @since 1.10
*/
public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1 instanceof String && cs2 instanceof String) {
return cs1.equals(cs2);
}
return cs1.length() == cs2.length() && CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
}
/**
* Calls {@link String#getBytes(Charset)}
*
* @param string
* The string to encode (if null, return null).
* @param charset
* The {@link Charset} to encode the {@code String}
* @return the encoded bytes
*/
private static ByteBuffer getByteBuffer(final String string, final Charset charset) {
if (string == null) {
return null;
}
return ByteBuffer.wrap(string.getBytes(charset));
}
/**
* Encodes the given string into a byte buffer using the UTF-8 charset, storing the result into a new byte
* array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
* @since 1.11
*/
public static ByteBuffer getByteBufferUtf8(final String string) {
return getByteBuffer(string, StandardCharsets.UTF_8);
}
/**
* Calls {@link String#getBytes(Charset)}
*
* @param string
* The string to encode (if null, return null).
* @param charset
* The {@link Charset} to encode the {@code String}
* @return the encoded bytes
*/
private static byte[] getBytes(final String string, final Charset charset) {
if (string == null) {
return null;
}
return string.getBytes(charset);
}
/**
* Encodes the given string into a sequence of bytes using the ISO-8859-1 charset, storing the result into a new
* byte array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#ISO_8859_1} is not initialized, which should never happen
* since it is required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesIso8859_1(final String string) {
return getBytes(string, StandardCharsets.ISO_8859_1);
}
/**
* Encodes the given string into a sequence of bytes using the named charset, storing the result into a new byte
* array.
* <p>
* This method catches {@link UnsupportedEncodingException} and rethrows it as {@link IllegalStateException}, which
* should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
* </p>
*
* @param string
* the String to encode, may be {@code null}
* @param charsetName
* The name of a required {@link java.nio.charset.Charset}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws IllegalStateException
* Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
* required charset name.
* @see CharEncoding
* @see String#getBytes(String)
*/
public static byte[] getBytesUnchecked(final String string, final String charsetName) {
if (string == null) {
return null;
}
try {
return string.getBytes(charsetName);
} catch (final UnsupportedEncodingException e) {
throw StringUtils.newIllegalStateException(charsetName, e);
}
}
/**
* Encodes the given string into a sequence of bytes using the US-ASCII charset, storing the result into a new byte
* array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#US_ASCII} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesUsAscii(final String string) {
return getBytes(string, StandardCharsets.US_ASCII);
}
/**
* Encodes the given string into a sequence of bytes using the UTF-16 charset, storing the result into a new byte
* array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_16} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesUtf16(final String string) {
return getBytes(string, StandardCharsets.UTF_16);
}
/**
* Encodes the given string into a sequence of bytes using the UTF-16BE charset, storing the result into a new byte
* array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_16BE} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesUtf16Be(final String string) {
return getBytes(string, StandardCharsets.UTF_16BE);
}
/**
* Encodes the given string into a sequence of bytes using the UTF-16LE charset, storing the result into a new byte
* array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_16LE} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesUtf16Le(final String string) {
return getBytes(string, StandardCharsets.UTF_16LE);
}
/**
* Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
* array.
*
* @param string
* the String to encode, may be {@code null}
* @return encoded bytes, or {@code null} if the input string was {@code null}
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
* @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
* @see #getBytesUnchecked(String, String)
*/
public static byte[] getBytesUtf8(final String string) {
return getBytes(string, StandardCharsets.UTF_8);
}
private static IllegalStateException newIllegalStateException(final String charsetName,
final UnsupportedEncodingException e) {
return new IllegalStateException(charsetName + ": " + e);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the given charset.
*
* @param bytes
* The bytes to be decoded into characters
* @param charset
* The {@link Charset} to encode the {@code String}; not {@code null}
* @return A new {@code String} decoded from the specified array of bytes using the given charset,
* or {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if charset is {@code null}
*/
private static String newString(final byte[] bytes, final Charset charset) {
return bytes == null ? null : new String(bytes, charset);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the given charset.
* <p>
* This method catches {@link UnsupportedEncodingException} and re-throws it as {@link IllegalStateException}, which
* should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
* </p>
*
* @param bytes
* The bytes to be decoded into characters, may be {@code null}
* @param charsetName
* The name of a required {@link java.nio.charset.Charset}
* @return A new {@code String} decoded from the specified array of bytes using the given charset,
* or {@code null} if the input byte array was {@code null}.
* @throws IllegalStateException
* Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
* required charset name.
* @see CharEncoding
* @see String#String(byte[], String)
*/
public static String newString(final byte[] bytes, final String charsetName) {
if (bytes == null) {
return null;
}
try {
return new String(bytes, charsetName);
} catch (final UnsupportedEncodingException e) {
throw StringUtils.newIllegalStateException(charsetName, e);
}
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the ISO-8859-1 charset.
*
* @param bytes
* The bytes to be decoded into characters, may be {@code null}
* @return A new {@code String} decoded from the specified array of bytes using the ISO-8859-1 charset, or
* {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if {@link StandardCharsets#ISO_8859_1} is not initialized, which should never happen
* since it is required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringIso8859_1(final byte[] bytes) {
return newString(bytes, StandardCharsets.ISO_8859_1);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the US-ASCII charset.
*
* @param bytes
* The bytes to be decoded into characters
* @return A new {@code String} decoded from the specified array of bytes using the US-ASCII charset,
* or {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if {@link StandardCharsets#US_ASCII} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringUsAscii(final byte[] bytes) {
return newString(bytes, StandardCharsets.US_ASCII);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the UTF-16 charset.
*
* @param bytes
* The bytes to be decoded into characters
* @return A new {@code String} decoded from the specified array of bytes using the UTF-16 charset
* or {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_16} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringUtf16(final byte[] bytes) {
return newString(bytes, StandardCharsets.UTF_16);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the UTF-16BE charset.
*
* @param bytes
* The bytes to be decoded into characters
* @return A new {@code String} decoded from the specified array of bytes using the UTF-16BE charset,
* or {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_16BE} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringUtf16Be(final byte[] bytes) {
return newString(bytes, StandardCharsets.UTF_16BE);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the UTF-16LE charset.
*
* @param bytes
* The bytes to be decoded into characters
* @return A new {@code String} decoded from the specified array of bytes using the UTF-16LE charset,
* or {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_16LE} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringUtf16Le(final byte[] bytes) {
return newString(bytes, StandardCharsets.UTF_16LE);
}
/**
* Constructs a new {@code String} by decoding the specified array of bytes using the UTF-8 charset.
*
* @param bytes
* The bytes to be decoded into characters
* @return A new {@code String} decoded from the specified array of bytes using the UTF-8 charset,
* or {@code null} if the input byte array was {@code null}.
* @throws NullPointerException
* Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since it is
* required by the Java platform specification.
* @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
*/
public static String newStringUtf8(final byte[] bytes) {
return newString(bytes, StandardCharsets.UTF_8);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package vendored.org.apache.commons.codec.digest;
import java.security.MessageDigest;
/**
* Standard {@link MessageDigest} algorithm names from the <cite>Java Cryptography Architecture Standard Algorithm Name
* Documentation</cite>.
* <p>
* This class is immutable and thread-safe.
* </p>
* <p>
* Java 8 and up: SHA-224.
* </p>
* <p>
* Java 9 and up: SHA3-224, SHA3-256, SHA3-384, SHA3-512.
* </p>
*
* @see <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest">
* Java 7 Cryptography Architecture Standard Algorithm Name Documentation</a>
* @see <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
* Java 8 Cryptography Architecture Standard Algorithm Name Documentation</a>
* @see <a href="https://docs.oracle.com/javase/9/docs/specs/security/standard-names.html#messagedigest-algorithms">
* Java 9 Cryptography Architecture Standard Algorithm Name Documentation</a>
* @see <a href="https://docs.oracle.com/javase/10/docs/specs/security/standard-names.html#messagedigest-algorithms">
* Java 10 Cryptography Architecture Standard Algorithm Name Documentation</a>
* @see <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms">
* Java 11 Cryptography Architecture Standard Algorithm Name Documentation</a>
* @see <a href="https://docs.oracle.com/en/java/javase/12/docs/specs/security/standard-names.html#messagedigest-algorithms">
* Java 12 Cryptography Architecture Standard Algorithm Name Documentation</a>
* @see <a href="https://docs.oracle.com/en/java/javase/13/docs/specs/security/standard-names.html#messagedigest-algorithms">
* Java 13 Cryptography Architecture Standard Algorithm Name Documentation</a>
*
* @see <a href="http://dx.doi.org/10.6028/NIST.FIPS.180-4">FIPS PUB 180-4</a>
* @see <a href="http://dx.doi.org/10.6028/NIST.FIPS.202">FIPS PUB 202</a>
* @since 1.7
*/
public class MessageDigestAlgorithms {
/**
* The MD2 message digest algorithm defined in RFC 1319.
*/
public static final String MD2 = "MD2";
/**
* The MD5 message digest algorithm defined in RFC 1321.
*/
public static final String MD5 = "MD5";
/**
* The SHA-1 hash algorithm defined in the FIPS PUB 180-2.
*/
public static final String SHA_1 = "SHA-1";
/**
* The SHA-224 hash algorithm defined in the FIPS PUB 180-3.
* <p>
* Present in Oracle Java 8.
* </p>
*
* @since 1.11
*/
public static final String SHA_224 = "SHA-224";
/**
* The SHA-256 hash algorithm defined in the FIPS PUB 180-2.
*/
public static final String SHA_256 = "SHA-256";
/**
* The SHA-384 hash algorithm defined in the FIPS PUB 180-2.
*/
public static final String SHA_384 = "SHA-384";
/**
* The SHA-512 hash algorithm defined in the FIPS PUB 180-2.
*/
public static final String SHA_512 = "SHA-512";
/**
* The SHA-512 hash algorithm defined in the FIPS PUB 180-4.
* <p>
* Included starting in Oracle Java 9.
* </p>
*
* @since 1.14
*/
public static final String SHA_512_224 = "SHA-512/224";
/**
* The SHA-512 hash algorithm defined in the FIPS PUB 180-4.
* <p>
* Included starting in Oracle Java 9.
* </p>
*
* @since 1.14
*/
public static final String SHA_512_256 = "SHA-512/256";
/**
* The SHA3-224 hash algorithm defined in the FIPS PUB 202.
* <p>
* Included starting in Oracle Java 9.
* </p>
*
* @since 1.11
*/
public static final String SHA3_224 = "SHA3-224";
/**
* The SHA3-256 hash algorithm defined in the FIPS PUB 202.
* <p>
* Included starting in Oracle Java 9.
* </p>
*
* @since 1.11
*/
public static final String SHA3_256 = "SHA3-256";
/**
* The SHA3-384 hash algorithm defined in the FIPS PUB 202.
* <p>
* Included starting in Oracle Java 9.
* </p>
*
* @since 1.11
*/
public static final String SHA3_384 = "SHA3-384";
/**
* The SHA3-512 hash algorithm defined in the FIPS PUB 202.
* <p>
* Included starting in Oracle Java 9.
* </p>
*
* @since 1.11
*/
public static final String SHA3_512 = "SHA3-512";
/**
* Gets all constant values defined in this class.
*
* @return all constant values defined in this class.
* @since 1.11
*/
public static String[] values() {
// N.B. do not use a constant array here as that can be changed externally by accident or design
return new String[] {
MD2, MD5, SHA_1, SHA_224, SHA_256, SHA_384,
SHA_512, SHA_512_224, SHA_512_256, SHA3_224, SHA3_256, SHA3_384, SHA3_512
};
}
private MessageDigestAlgorithms() {
// cannot be instantiated.
}
}

View File

@@ -16,19 +16,25 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Random;
import java.util.TimeZone;
import androidx.loader.content.CursorLoader;
import androidx.test.core.app.ApplicationProvider;
import vendored.org.apache.commons.codec.digest.DigestUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static vendored.org.apache.commons.codec.digest.MessageDigestAlgorithms.SHA_256;
/**
* @see <a href="https://gitlab.com/fdroid/fdroidclient/-/merge_requests/1089#note_822501322">forced to vendor Apache Commons Codec</a>
*/
@RunWith(RobolectricTestRunner.class)
@SuppressWarnings("LineLength")
public class UtilsTest {
@@ -163,6 +169,48 @@ public class UtilsTest {
Utils.formatFingerprint(context, "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef"));
}
@Test
public void testIsFileMatchingHash() {
Utils.isFileMatchingHash(null, null, null);
Utils.isFileMatchingHash(new File("/"), "", null);
assertFalse(Utils.isFileMatchingHash(null, null, ""));
assertFalse(Utils.isFileMatchingHash(null, null, SHA_256));
assertFalse(Utils.isFileMatchingHash(new File("/"), null, SHA_256));
assertFalse(Utils.isFileMatchingHash(new File("/"), "", SHA_256));
assertTrue(Utils.isFileMatchingHash(TestUtils.copyResourceToTempFile("Norway_bouvet_europe_2.obf.zip"),
"6e8a584e004c6cd26d3822a04b0591e355dc5d07b5a3d0f8e309443f47ad1208", SHA_256));
assertTrue(Utils.isFileMatchingHash(TestUtils.copyResourceToTempFile("install_history_all"),
"4ad118d4a600dcc104834635d248a89e337fc91b173163d646996b9c54d77372", SHA_256));
assertFalse("wrong sha256 value",
Utils.isFileMatchingHash(TestUtils.copyResourceToTempFile("simpleIndex.jar"),
"6e8a584e004c6cd26d3822a04b0591e355dc5d07b5a3d0f8e309443f47ad1208", SHA_256));
File f = TestUtils.copyResourceToTempFile("additional_repos.xml");
assertTrue(Utils.isFileMatchingHash(f,
"47ad2284d3042373e6280012cc10e9b82f75352db6d6d9bab1e06934b7b1dab7", SHA_256));
assertFalse("uppercase fails",
Utils.isFileMatchingHash(f,
"47AD2284D3042373E6280012CC10E9B82F75352DB6D6D9BAB1E06934B7B1DAB7", SHA_256));
assertFalse("one uppercase digit fails",
Utils.isFileMatchingHash(f,
"47Ad2284d3042373e6280012cc10e9b82f75352db6d6d9bab1e06934b7b1dab7", SHA_256));
assertFalse("missing digit fails",
Utils.isFileMatchingHash(f,
"47ad2284d3042373e6280012cc10e9b82f75352db6d6d9bab1e06934b7b1dab", SHA_256));
assertFalse("extra digit fails",
Utils.isFileMatchingHash(f,
"47ad2284d3042373e6280012cc10e9b82f75352db6d6d9bab1e06934b7b1dab71", SHA_256));
assertFalse("all zeros fails",
Utils.isFileMatchingHash(f,
"0000000000000000000000000000000000000000000000000000000000000000", SHA_256));
assertFalse("null fails",
Utils.isFileMatchingHash(f, null, SHA_256));
assertFalse("empty string fails",
Utils.isFileMatchingHash(f, "", SHA_256));
}
@Test
public void testCalcFingerprintString() {
// these should pass
@@ -204,20 +252,38 @@ public class UtilsTest {
}
@Test
public void testGetBinaryHash() {
public void testGetFileHexDigest() throws IOException {
File f = TestUtils.copyResourceToTempFile("largeRepo.xml");
assertEquals("df1754aa4b56c86c06d7842dfd02064f0781c1f740f489d3fc158bb541c8d197",
Utils.getBinaryHash(f, "sha256"));
Utils.getFileHexDigest(f, "sha256"));
f = TestUtils.copyResourceToTempFile("masterKeyIndex.jar");
assertEquals("625d5aedcd0499fe04ebab81f3c7ae30c236cee653a914ffb587d890198f3aba",
Utils.getBinaryHash(f, "sha256"));
Utils.getFileHexDigest(f, "sha256"));
f = TestUtils.copyResourceToTempFile("index.fdroid.2016-10-30.jar");
assertEquals("c138b503c6475aa749585d0e3ad4dba3546b6d33ec485efd8ac8bd603d93fedb",
Utils.getBinaryHash(f, "sha256"));
Utils.getFileHexDigest(f, "sha-256"));
f = TestUtils.copyResourceToTempFile("index.fdroid.2016-11-10.jar");
assertEquals("93bea45814fd8955cabb957e7a3f8790d6c568eaa16fa30425c2d26c60490bde",
Utils.getBinaryHash(f, "sha256"));
Utils.getFileHexDigest(f, "SHA-256"));
// zero size file should have a stable hex digest file
assertEquals("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
Utils.getFileHexDigest(File.createTempFile("asdf", "asdf"), SHA_256));
assertNull(Utils.getFileHexDigest(new File("/kasdfkjasdhflkjasd"), SHA_256));
}
@Test(expected = IllegalArgumentException.class)
public void testGetFileHexDigestBadAlgo() {
File f = TestUtils.copyResourceToTempFile("additional_repos.xml");
assertNull(Utils.getFileHexDigest(f, "FAKE"));
}
@Test(expected = NullPointerException.class)
public void testGetFileHexDigestNullFile() {
assertNull(Utils.getFileHexDigest(null, SHA_256));
}
// TODO write tests that work with a Certificate
@Test
@@ -269,7 +335,7 @@ public class UtilsTest {
d = v & 0xF;
fdroidSig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
}
String sig = Utils.hashBytes(fdroidSig, "md5");
String sig = DigestUtils.md5Hex(fdroidSig);
assertEquals(sig, Utils.getsig(rawCertBytes));
PackageInfo packageInfo = new PackageInfo();

View File

@@ -40,7 +40,7 @@
<module name="AvoidStarImport" />
<module name="AvoidStaticImport">
<property name="excludes"
value="org.fdroid.fdroid.Assert.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.core.IsNot.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, androidx.test.espresso.Espresso.*, androidx.test.espresso.assertion.ViewAssertions.*, androidx.test.espresso.matcher.ViewMatchers.*, androidx.test.espresso.action.ViewActions.*" />
value="org.fdroid.fdroid.Assert.*, vendored.org.apache.commons.codec.digest.MessageDigestAlgorithms.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.core.IsNot.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, androidx.test.espresso.Espresso.*, androidx.test.espresso.assertion.ViewAssertions.*, androidx.test.espresso.matcher.ViewMatchers.*, androidx.test.espresso.action.ViewActions.*" />
</module>
<module name="RedundantImport" />
<module name="UnusedImports" />

View File

@@ -4,4 +4,5 @@
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress checks="." files="[\\/]kellinwood[\\/].*\.java$"/>
<suppress checks="." files="[\\/]vendored[\\/].*\.java$"/>
</suppressions>