mirror of https://github.com/jwtk/jjwt.git
Merge pull request #359 from jwtk/285-base64-exceptions
Descriptive exception when decoding illegal Base64(Url) input
This commit is contained in:
commit
fbcc9ab931
|
@ -27,6 +27,7 @@ final class Base64 { //final and package-protected on purpose
|
|||
private static final char[] BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();
|
||||
private static final int[] BASE64_IALPHABET = new int[256];
|
||||
private static final int[] BASE64URL_IALPHABET = new int[256];
|
||||
private static final int IALPHABET_MAX_INDEX = BASE64_IALPHABET.length - 1;
|
||||
|
||||
static {
|
||||
Arrays.fill(BASE64_IALPHABET, -1);
|
||||
|
@ -56,6 +57,10 @@ final class Base64 { //final and package-protected on purpose
|
|||
// * char[] version
|
||||
// ****************************************************************************************
|
||||
|
||||
private String getName() {
|
||||
return urlsafe ? "base64url" : "base64"; // RFC 4648 codec names are all lowercase
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a raw byte array into a BASE64 <code>char[]</code> representation in accordance with RFC 2045.
|
||||
*
|
||||
|
@ -194,6 +199,15 @@ final class Base64 { //final and package-protected on purpose
|
|||
}
|
||||
*/
|
||||
|
||||
private int ctoi(char c) {
|
||||
int i = c > IALPHABET_MAX_INDEX ? -1 : IALPHABET[c];
|
||||
if (i < 0) {
|
||||
String msg = "Illegal " + getName() + " character: '" + c + "'";
|
||||
throw new DecodingException(msg);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a BASE64 encoded char array that is known to be reasonably well formatted. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
|
@ -237,7 +251,7 @@ final class Base64 { //final and package-protected on purpose
|
|||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
|
||||
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IALPHABET[sArr[sIx++]] << 18 | IALPHABET[sArr[sIx++]] << 12 | IALPHABET[sArr[sIx++]] << 6 | IALPHABET[sArr[sIx++]];
|
||||
int i = ctoi(sArr[sIx++]) << 18 | ctoi(sArr[sIx++]) << 12 | ctoi(sArr[sIx++]) << 6 | ctoi(sArr[sIx++]);
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
|
@ -255,7 +269,7 @@ final class Base64 { //final and package-protected on purpose
|
|||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++) {
|
||||
i |= IALPHABET[sArr[sIx++]] << (18 - j * 6);
|
||||
i |= ctoi(sArr[sIx++]) << (18 - j * 6);
|
||||
}
|
||||
|
||||
for (int r = 16; d < len; r -= 8) {
|
||||
|
|
|
@ -5,6 +5,10 @@ package io.jsonwebtoken.io;
|
|||
*/
|
||||
public class CodecException extends IOException {
|
||||
|
||||
public CodecException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CodecException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ package io.jsonwebtoken.io;
|
|||
*/
|
||||
public class DecodingException extends CodecException {
|
||||
|
||||
public DecodingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DecodingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@ class Base64Test {
|
|||
姚奊べ 椥䤥グ曣わ 栨キョ奎婨榞 ちょ䰯 Ủ䧞以ケ妣 誧姨のドゥろ よ苯礊 く涥, りゅぽ槞 馣ぢゃ尦䦎ぎ
|
||||
大た䏩䰥ぐ 郎きや楺橯 䧎キェ, 難ゞ滧 栧择 谯䧟簨訧ぎょ 椥䤥グ曣わ'''
|
||||
|
||||
@Test
|
||||
void testBase64Name() {
|
||||
assertEquals 'base64', Base64.DEFAULT.getName() // RFC 4648 codec name is all lowercase
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBase64UrlName() {
|
||||
assertEquals 'base64url', Base64.URL_SAFE.getName() // RFC 4648 codec name is all lowercase
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncodeToStringWithNullArgument() {
|
||||
String s = Base64.DEFAULT.encodeToString(null, false)
|
||||
|
@ -70,6 +80,39 @@ class Base64Test {
|
|||
assertEquals expected, result
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecodeFastWithIntermediateIllegalInboundCharacters() {
|
||||
def encoded = 'SGVsbG8g*5LiW55WM'
|
||||
try {
|
||||
Base64.DEFAULT.decodeFast(encoded.toCharArray())
|
||||
fail()
|
||||
} catch (DecodingException de) {
|
||||
assertEquals 'Illegal base64 character: \'*\'', de.getMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecodeFastWithIntermediateIllegalOutOfBoundCharacters() {
|
||||
def encoded = 'SGVsbG8g世5LiW55WM'
|
||||
try {
|
||||
Base64.DEFAULT.decodeFast(encoded.toCharArray())
|
||||
fail()
|
||||
} catch (DecodingException de) {
|
||||
assertEquals 'Illegal base64 character: \'世\'', de.getMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecodeFastWithIntermediateIllegalSpaceCharacters() {
|
||||
def encoded = 'SGVsbG8g 5LiW55WM'
|
||||
try {
|
||||
Base64.DEFAULT.decodeFast(encoded.toCharArray())
|
||||
fail()
|
||||
} catch (DecodingException de) {
|
||||
assertEquals 'Illegal base64 character: \' \'', de.getMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDecodeFastWithLineSeparators() {
|
||||
|
||||
|
|
Loading…
Reference in New Issue