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 |