Skip to content

Commit 9727285

Browse files
committed
Throw IllegalArgumentException for characters outside of alphabet
1 parent 019ee2c commit 9727285

2 files changed

Lines changed: 35 additions & 20 deletions

File tree

src/main/java/org/apache/commons/codec/binary/Base16.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ void decode(final byte[] data, int offset, final int length, final Context conte
151151

152152
// small optimisation to short-cut the rest of this method when it is fed byte-by-byte
153153
if (availableChars == 1 && availableChars == dataLen) {
154-
context.ibitWorkArea = data[offset]; // store 1/2 byte for next invocation of decode
154+
context.ibitWorkArea = decodeOctet(data[offset]) + 1; // store 1/2 byte for next invocation of decode, we offset by +1 as empty-value is 0
155155
return;
156156
}
157157

@@ -164,29 +164,42 @@ void decode(final byte[] data, int offset, final int length, final Context conte
164164
int i = 0;
165165
if (dataLen < availableChars) {
166166
// we have 1/2 byte from previous invocation to decode
167-
result = decodeTable[context.ibitWorkArea] << BITS_PER_ENCODED_BYTE;
168-
result |= decodeTable[data[offset++]];
167+
result = (context.ibitWorkArea - 1) << BITS_PER_ENCODED_BYTE;
168+
result |= decodeOctet(data[offset++]);
169169
i = 2;
170170

171171
buffer[context.pos++] = (byte)result;
172172

173-
// reset for next invocation!
174-
context.ibitWorkArea = -1;
173+
// reset to empty-value for next invocation!
174+
context.ibitWorkArea = 0;
175175
}
176176

177177
while (i < charsToProcess) {
178-
result = decodeTable[data[offset++]] << BITS_PER_ENCODED_BYTE;
179-
result |= decodeTable[data[offset++]];
178+
result = decodeOctet(data[offset++]) << BITS_PER_ENCODED_BYTE;
179+
result |= decodeOctet(data[offset++]);
180180
i += 2;
181181
buffer[context.pos++] = (byte)result;
182182
}
183183

184184
// we have one char of a hex-pair left over
185185
if (i < dataLen) {
186-
context.ibitWorkArea = data[i]; // store 1/2 byte for next invocation of decode
186+
context.ibitWorkArea = decodeOctet(data[i]) + 1; // store 1/2 byte for next invocation of decode, we offset by +1 as empty-value is 0
187187
}
188188
}
189189

190+
private int decodeOctet(final byte octet) {
191+
int decoded = -1;
192+
if (octet >= 0 && octet < decodeTable.length) {
193+
decoded = decodeTable[octet];
194+
}
195+
196+
if (decoded == -1) {
197+
throw new IllegalArgumentException("Invalid octet in encoded value: " + (int)octet);
198+
}
199+
200+
return decoded;
201+
}
202+
190203
@Override
191204
void encode(final byte[] data, final int offset, final int length, final Context context) {
192205
if (context.eof) {

src/test/java/org/apache/commons/codec/binary/Base16Test.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,17 @@ public void testKnownEncodings() {
205205

206206
@Test
207207
public void testNonBase16Test() {
208-
final byte[] bArray = { '%' };
209-
210-
try {
211-
final Base16 b16 = new Base16();
212-
final byte[] result = b16.decode(bArray);
213-
214-
assertEquals("The result should be empty as the test encoded content did "
215-
+ "not contain any valid base 16 characters", 0, result.length);
216-
} catch (final Exception e) {
217-
fail("Exception was thrown when trying to decode invalid Base16 encoded data");
208+
final byte[] invalidEncodedChars = { '/', ':', '@', 'G', '%', '`', 'g' };
209+
210+
final byte[] encoded = new byte[1];
211+
for (final byte invalidEncodedChar : invalidEncodedChars) {
212+
try {
213+
encoded[0] = invalidEncodedChar;
214+
new Base16().decode(encoded);
215+
fail("IllegalArgumentException should have been thrown when trying to decode invalid Base16 char: " + (char)invalidEncodedChar);
216+
} catch (final Exception e) {
217+
assertTrue(e instanceof IllegalArgumentException);
218+
}
218219
}
219220
}
220221

@@ -591,14 +592,15 @@ public void testDecodeSingleBytesOptimisation() {
591592
final byte[] data = new byte[1];
592593

593594
final Base16 b16 = new Base16();
595+
assertEquals(0, context.ibitWorkArea);
594596

595597
data[0] = (byte) 'E';
596598
b16.decode(data, 0, 1, context);
597-
assertEquals(69, context.ibitWorkArea);
599+
assertEquals(15, context.ibitWorkArea);
598600

599601
data[0] = (byte) 'F';
600602
b16.decode(data, 0, 1, context);
601-
assertEquals(-1, context.ibitWorkArea);
603+
assertEquals(0, context.ibitWorkArea);
602604

603605
assertEquals(-17, context.buffer[0]);
604606
}

0 commit comments

Comments
 (0)