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 char[] BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();
|
||||||
private static final int[] BASE64_IALPHABET = new int[256];
|
private static final int[] BASE64_IALPHABET = new int[256];
|
||||||
private static final int[] BASE64URL_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 {
|
static {
|
||||||
Arrays.fill(BASE64_IALPHABET, -1);
|
Arrays.fill(BASE64_IALPHABET, -1);
|
||||||
|
@ -56,6 +57,10 @@ final class Base64 { //final and package-protected on purpose
|
||||||
// * char[] version
|
// * 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.
|
* 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>
|
* 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>
|
* + 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; ) {
|
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
|
||||||
|
|
||||||
// Assemble three bytes into an int from four "valid" characters.
|
// 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
|
// Add the bytes
|
||||||
dArr[d++] = (byte) (i >> 16);
|
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
|
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (int j = 0; sIx <= eIx - pad; j++) {
|
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) {
|
for (int r = 16; d < len; r -= 8) {
|
||||||
|
|
|
@ -5,6 +5,10 @@ package io.jsonwebtoken.io;
|
||||||
*/
|
*/
|
||||||
public class CodecException extends IOException {
|
public class CodecException extends IOException {
|
||||||
|
|
||||||
|
public CodecException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
public CodecException(String message, Throwable cause) {
|
public CodecException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@ package io.jsonwebtoken.io;
|
||||||
*/
|
*/
|
||||||
public class DecodingException extends CodecException {
|
public class DecodingException extends CodecException {
|
||||||
|
|
||||||
|
public DecodingException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
public DecodingException(String message, Throwable cause) {
|
public DecodingException(String message, Throwable cause) {
|
||||||
super(message, 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
|
@Test
|
||||||
void testEncodeToStringWithNullArgument() {
|
void testEncodeToStringWithNullArgument() {
|
||||||
String s = Base64.DEFAULT.encodeToString(null, false)
|
String s = Base64.DEFAULT.encodeToString(null, false)
|
||||||
|
@ -70,6 +80,39 @@ class Base64Test {
|
||||||
assertEquals expected, result
|
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
|
@Test
|
||||||
void testDecodeFastWithLineSeparators() {
|
void testDecodeFastWithLineSeparators() {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue