| 1 | /* | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | * contributor license agreements. See the NOTICE file distributed with | |
| 4 | * this work for additional information regarding copyright ownership. | |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | * (the "License"); you may not use this file except in compliance with | |
| 7 | * the License. You may obtain a copy of the License at | |
| 8 | * | |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | * | |
| 11 | * Unless required by applicable law or agreed to in writing, software | |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | * See the License for the specific language governing permissions and | |
| 15 | * limitations under the License. | |
| 16 | */ | |
| 17 | ||
| 18 | package com.jsql.util.bruter; | |
| 19 | ||
| 20 | import org.apache.commons.codec.binary.Base32; | |
| 21 | ||
| 22 | import java.util.Base64; | |
| 23 | ||
| 24 | /** | |
| 25 | * Provides Base16 encoding and decoding. | |
| 26 | * | |
| 27 | * <p> | |
| 28 | * This class is thread-safe. | |
| 29 | * </p> | |
| 30 | * <p> | |
| 31 | * This implementation strictly follows RFC 4648, and as such unlike | |
| 32 | * the {@link Base32} and {@link Base64} implementations, | |
| 33 | * it does not ignore invalid alphabet characters or whitespace, | |
| 34 | * neither does it offer chunking or padding characters. | |
| 35 | * </p> | |
| 36 | * <p> | |
| 37 | * The only additional feature above those specified in RFC 4648 | |
| 38 | * is support for working with a lower-case alphabet in addition | |
| 39 | * to the default upper-case alphabet. | |
| 40 | * </p> | |
| 41 | * | |
| 42 | * @see <a href="https://tools.ietf.org/html/rfc4648#section-8">RFC 4648 - 8. Base 16 Encoding</a> | |
| 43 | * | |
| 44 | * @since 1.15 | |
| 45 | */ | |
| 46 | public class Base16 extends BaseNCodec { | |
| 47 | ||
| 48 | /** | |
| 49 | * BASE16 characters are 4 bits in length. | |
| 50 | * They are formed by taking an 8-bit group, | |
| 51 | * which is converted into two BASE16 characters. | |
| 52 | */ | |
| 53 | private static final int BITS_PER_ENCODED_BYTE = 4; | |
| 54 | private static final int BYTES_PER_ENCODED_BLOCK = 2; | |
| 55 | private static final int BYTES_PER_UNENCODED_BLOCK = 1; | |
| 56 | ||
| 57 | /** | |
| 58 | * This array is a lookup table that translates Unicode characters drawn from the "Base16 Alphabet" (as specified | |
| 59 | * in Table 5 of RFC 4648) into their 4-bit positive integer equivalents. Characters that are not in the Base16 | |
| 60 | * alphabet but fall within the bounds of the array are translated to -1. | |
| 61 | */ | |
| 62 | private static final byte[] UPPER_CASE_DECODE_TABLE = { | |
| 63 | // 0 1 2 3 4 5 6 7 8 9 A B C D E F | |
| 64 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f | |
| 65 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f | |
| 66 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f | |
| 67 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 | |
| 68 | -1, 10, 11, 12, 13, 14, 15 // 40-46 A-F | |
| 69 | }; | |
| 70 | ||
| 71 | /** | |
| 72 | * This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" | |
| 73 | * equivalents as specified in Table 5 of RFC 4648. | |
| 74 | */ | |
| 75 | private static final byte[] UPPER_CASE_ENCODE_TABLE = { | |
| 76 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
| 77 | 'A', 'B', 'C', 'D', 'E', 'F' | |
| 78 | }; | |
| 79 | ||
| 80 | /** | |
| 81 | * This array is a lookup table that translates Unicode characters drawn from a lower-case "Base16 Alphabet" | |
| 82 | * into their 4-bit positive integer equivalents. Characters that are not in the Base16 | |
| 83 | * alphabet but fall within the bounds of the array are translated to -1. | |
| 84 | */ | |
| 85 | private static final byte[] LOWER_CASE_DECODE_TABLE = { | |
| 86 | // 0 1 2 3 4 5 6 7 8 9 A B C D E F | |
| 87 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f | |
| 88 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f | |
| 89 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f | |
| 90 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 | |
| 91 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 40-4f | |
| 92 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 50-5f | |
| 93 | -1, 10, 11, 12, 13, 14, 15 // 60-66 a-f | |
| 94 | }; | |
| 95 | ||
| 96 | /** | |
| 97 | * This array is a lookup table that translates 4-bit positive integer index values into their "Base16 Alphabet" | |
| 98 | * lower-case equivalents. | |
| 99 | */ | |
| 100 | private static final byte[] LOWER_CASE_ENCODE_TABLE = { | |
| 101 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
| 102 | 'a', 'b', 'c', 'd', 'e', 'f' | |
| 103 | }; | |
| 104 | ||
| 105 | /** Mask used to extract 4 bits, used when decoding character. */ | |
| 106 | private static final int MASK_4BITS = 0x0f; | |
| 107 | ||
| 108 | /** | |
| 109 | * Decode table to use. | |
| 110 | */ | |
| 111 | private final byte[] decodeTable; | |
| 112 | ||
| 113 | /** | |
| 114 | * Encode table to use. | |
| 115 | */ | |
| 116 | private final byte[] encodeTable; | |
| 117 | ||
| 118 | /** | |
| 119 | * Creates a Base16 codec used for decoding and encoding. | |
| 120 | */ | |
| 121 | public Base16() { | |
| 122 | this(false); | |
| 123 | } | |
| 124 | ||
| 125 | /** | |
| 126 | * Creates a Base16 codec used for decoding and encoding. | |
| 127 | * | |
| 128 | * @param lowerCase if {@code true} then use a lower-case Base16 alphabet. | |
| 129 | */ | |
| 130 | public Base16(final boolean lowerCase) { | |
| 131 | this(lowerCase, BaseNCodec.DECODING_POLICY_DEFAULT); | |
| 132 | } | |
| 133 | ||
| 134 | /** | |
| 135 | * Creates a Base16 codec used for decoding and encoding. | |
| 136 | * | |
| 137 | * @param lowerCase if {@code true} then use a lower-case Base16 alphabet. | |
| 138 | * @param decodingPolicy Decoding policy. | |
| 139 | */ | |
| 140 | public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) { | |
| 141 | super(Base16.BYTES_PER_UNENCODED_BLOCK, Base16.BYTES_PER_ENCODED_BLOCK, 0, 0, BaseNCodec.PAD_DEFAULT, decodingPolicy); | |
| 142 |
1
1. <init> : negated conditional → KILLED |
if (lowerCase) { |
| 143 | this.encodeTable = Base16.LOWER_CASE_ENCODE_TABLE; | |
| 144 | this.decodeTable = Base16.LOWER_CASE_DECODE_TABLE; | |
| 145 | } else { | |
| 146 | this.encodeTable = Base16.UPPER_CASE_ENCODE_TABLE; | |
| 147 | this.decodeTable = Base16.UPPER_CASE_DECODE_TABLE; | |
| 148 | } | |
| 149 | } | |
| 150 | ||
| 151 | @Override | |
| 152 | public void decode(final byte[] data, int offsetInput, final int length, final Context context) { | |
| 153 | int offset = offsetInput; | |
| 154 | | |
| 155 |
3
1. decode : changed conditional boundary → SURVIVED 2. decode : negated conditional → KILLED 3. decode : negated conditional → KILLED |
if (context.eof || length < 0) { |
| 156 | context.eof = true; | |
| 157 |
1
1. decode : negated conditional → SURVIVED |
if (context.ibitWorkArea != 0) { |
| 158 |
1
1. decode : removed call to com/jsql/util/bruter/Base16::validateTrailingCharacter → NO_COVERAGE |
this.validateTrailingCharacter(); |
| 159 | } | |
| 160 | return; | |
| 161 | } | |
| 162 | ||
| 163 |
1
1. decode : Replaced integer subtraction with addition → SURVIVED |
final int dataLen = Math.min(data.length - offset, length); |
| 164 |
2
1. decode : negated conditional → KILLED 2. decode : Replaced integer addition with subtraction → KILLED |
final int availableChars = (context.ibitWorkArea != 0 ? 1 : 0) + dataLen; |
| 165 | ||
| 166 | // small optimisation to short-cut the rest of this method when it is fed byte-by-byte | |
| 167 |
2
1. decode : negated conditional → NO_COVERAGE 2. decode : negated conditional → KILLED |
if (availableChars == 1 && availableChars == dataLen) { |
| 168 |
1
1. decode : Replaced integer addition with subtraction → NO_COVERAGE |
context.ibitWorkArea = this.decodeOctet(data[offset]) + 1; // store 1/2 byte for next invocation of decode, we offset by +1 as empty-value is 0 |
| 169 | return; | |
| 170 | } | |
| 171 | ||
| 172 | // we must have an even number of chars to decode | |
| 173 |
3
1. decode : Replaced integer subtraction with addition → NO_COVERAGE 2. decode : negated conditional → SURVIVED 3. decode : Replaced integer modulus with multiplication → SURVIVED |
final int charsToProcess = availableChars % Base16.BYTES_PER_ENCODED_BLOCK == 0 ? availableChars : availableChars - 1; |
| 174 |
1
1. decode : Replaced integer division with multiplication → SURVIVED |
final byte[] buffer = this.ensureBufferSize(charsToProcess / Base16.BYTES_PER_ENCODED_BLOCK, context); |
| 175 | ||
| 176 | int result; | |
| 177 | var i = 0; | |
| 178 |
2
1. decode : changed conditional boundary → KILLED 2. decode : negated conditional → KILLED |
if (dataLen < availableChars) { |
| 179 | // we have 1/2 byte from previous invocation to decode | |
| 180 |
2
1. decode : Replaced integer subtraction with addition → NO_COVERAGE 2. decode : Replaced Shift Left with Shift Right → NO_COVERAGE |
result = (context.ibitWorkArea - 1) << Base16.BITS_PER_ENCODED_BYTE; |
| 181 |
2
1. decode : Replaced bitwise OR with AND → NO_COVERAGE 2. decode : Changed increment from 1 to -1 → NO_COVERAGE |
result |= this.decodeOctet(data[offset++]); |
| 182 | i = 2; | |
| 183 |
1
1. decode : Replaced integer addition with subtraction → NO_COVERAGE |
buffer[context.pos++] = (byte) result; |
| 184 | // reset to empty-value for next invocation! | |
| 185 | context.ibitWorkArea = 0; | |
| 186 | } | |
| 187 | ||
| 188 |
2
1. decode : negated conditional → KILLED 2. decode : changed conditional boundary → KILLED |
while (i < charsToProcess) { |
| 189 |
2
1. decode : Replaced Shift Left with Shift Right → KILLED 2. decode : Changed increment from 1 to -1 → KILLED |
result = this.decodeOctet(data[offset++]) << Base16.BITS_PER_ENCODED_BYTE; |
| 190 |
2
1. decode : Replaced bitwise OR with AND → KILLED 2. decode : Changed increment from 1 to -1 → KILLED |
result |= this.decodeOctet(data[offset++]); |
| 191 |
1
1. decode : Changed increment from 2 to -2 → KILLED |
i += 2; |
| 192 |
1
1. decode : Replaced integer addition with subtraction → KILLED |
buffer[context.pos++] = (byte) result; |
| 193 | } | |
| 194 | ||
| 195 | // we have one char of a hex-pair left over | |
| 196 |
2
1. decode : negated conditional → KILLED 2. decode : changed conditional boundary → KILLED |
if (i < dataLen) { |
| 197 |
1
1. decode : Replaced integer addition with subtraction → NO_COVERAGE |
context.ibitWorkArea = this.decodeOctet(data[i]) + 1; // store 1/2 byte for next invocation of decode, we offset by +1 as empty-value is 0 |
| 198 | } | |
| 199 | } | |
| 200 | ||
| 201 | private int decodeOctet(final byte octet) { | |
| 202 | int decoded = -1; | |
| 203 |
3
1. decodeOctet : changed conditional boundary → SURVIVED 2. decodeOctet : negated conditional → KILLED 3. decodeOctet : Replaced bitwise AND with OR → KILLED |
if ((octet & 0xff) < this.decodeTable.length) { |
| 204 | decoded = this.decodeTable[octet]; | |
| 205 | } | |
| 206 |
1
1. decodeOctet : negated conditional → KILLED |
if (decoded == -1) { |
| 207 | throw new IllegalArgumentException("Invalid octet in encoded value: " + (int) octet); | |
| 208 | } | |
| 209 |
1
1. decodeOctet : replaced int return with 0 for com/jsql/util/bruter/Base16::decodeOctet → KILLED |
return decoded; |
| 210 | } | |
| 211 | ||
| 212 | @Override | |
| 213 | public void encode(final byte[] data, final int offset, final int length, final Context context) { | |
| 214 |
1
1. encode : negated conditional → KILLED |
if (context.eof) { |
| 215 | return; | |
| 216 | } | |
| 217 |
2
1. encode : changed conditional boundary → SURVIVED 2. encode : negated conditional → KILLED |
if (length < 0) { |
| 218 | context.eof = true; | |
| 219 | return; | |
| 220 | } | |
| 221 |
1
1. encode : Replaced integer multiplication with division → SURVIVED |
final int size = length * Base16.BYTES_PER_ENCODED_BLOCK; |
| 222 |
2
1. encode : changed conditional boundary → SURVIVED 2. encode : negated conditional → KILLED |
if (size < 0) { |
| 223 | throw new IllegalArgumentException("Input length exceeds maximum size for encoded data: " + length); | |
| 224 | } | |
| 225 | final byte[] buffer = this.ensureBufferSize(size, context); | |
| 226 |
1
1. encode : Replaced integer addition with subtraction → KILLED |
final int end = offset + length; |
| 227 |
2
1. encode : changed conditional boundary → KILLED 2. encode : negated conditional → KILLED |
for (int i = offset; i < end; i++) { |
| 228 | final int value = data[i]; | |
| 229 |
2
1. encode : Replaced Shift Right with Shift Left → KILLED 2. encode : Replaced bitwise AND with OR → KILLED |
final int high = (value >> Base16.BITS_PER_ENCODED_BYTE) & Base16.MASK_4BITS; |
| 230 |
1
1. encode : Replaced bitwise AND with OR → KILLED |
final int low = value & Base16.MASK_4BITS; |
| 231 |
1
1. encode : Replaced integer addition with subtraction → KILLED |
buffer[context.pos++] = this.encodeTable[high]; |
| 232 |
1
1. encode : Replaced integer addition with subtraction → KILLED |
buffer[context.pos++] = this.encodeTable[low]; |
| 233 | } | |
| 234 | } | |
| 235 | ||
| 236 | /** | |
| 237 | * Returns whether the {@code octet} is in the Base16 alphabet. | |
| 238 | * | |
| 239 | * @param octet The value to test. | |
| 240 | * | |
| 241 | * @return {@code true} if the value is defined in the Base16 alphabet {@code false} otherwise. | |
| 242 | */ | |
| 243 | @Override | |
| 244 | public boolean isInAlphabet(final byte octet) { | |
| 245 |
5
1. isInAlphabet : changed conditional boundary → NO_COVERAGE 2. isInAlphabet : Replaced bitwise AND with OR → NO_COVERAGE 3. isInAlphabet : negated conditional → NO_COVERAGE 4. isInAlphabet : replaced boolean return with true for com/jsql/util/bruter/Base16::isInAlphabet → NO_COVERAGE 5. isInAlphabet : negated conditional → NO_COVERAGE |
return (octet & 0xff) < this.decodeTable.length && this.decodeTable[octet] != -1; |
| 246 | } | |
| 247 | ||
| 248 | /** | |
| 249 | * Validates whether decoding allows an entire final trailing character that cannot be | |
| 250 | * used for a complete byte. | |
| 251 | * | |
| 252 | * @throws IllegalArgumentException if strict decoding is enabled | |
| 253 | */ | |
| 254 | private void validateTrailingCharacter() { | |
| 255 |
1
1. validateTrailingCharacter : negated conditional → NO_COVERAGE |
if (this.isStrictDecoding()) { |
| 256 | throw new IllegalArgumentException( | |
| 257 | "Strict decoding: Last encoded character is a valid base 16 alphabet" + | |
| 258 | "character but not a possible encoding. " + | |
| 259 | "Decoding requires at least two characters to create one byte." | |
| 260 | ); | |
| 261 | } | |
| 262 | } | |
| 263 | } | |
| 264 | ||
Mutations | ||
| 142 |
1.1 |
|
| 155 |
1.1 2.2 3.3 |
|
| 157 |
1.1 |
|
| 158 |
1.1 |
|
| 163 |
1.1 |
|
| 164 |
1.1 2.2 |
|
| 167 |
1.1 2.2 |
|
| 168 |
1.1 |
|
| 173 |
1.1 2.2 3.3 |
|
| 174 |
1.1 |
|
| 178 |
1.1 2.2 |
|
| 180 |
1.1 2.2 |
|
| 181 |
1.1 2.2 |
|
| 183 |
1.1 |
|
| 188 |
1.1 2.2 |
|
| 189 |
1.1 2.2 |
|
| 190 |
1.1 2.2 |
|
| 191 |
1.1 |
|
| 192 |
1.1 |
|
| 196 |
1.1 2.2 |
|
| 197 |
1.1 |
|
| 203 |
1.1 2.2 3.3 |
|
| 206 |
1.1 |
|
| 209 |
1.1 |
|
| 214 |
1.1 |
|
| 217 |
1.1 2.2 |
|
| 221 |
1.1 |
|
| 222 |
1.1 2.2 |
|
| 226 |
1.1 |
|
| 227 |
1.1 2.2 |
|
| 229 |
1.1 2.2 |
|
| 230 |
1.1 |
|
| 231 |
1.1 |
|
| 232 |
1.1 |
|
| 245 |
1.1 2.2 3.3 4.4 5.5 |
|
| 255 |
1.1 |