| 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 |