Implement detection of non-UTF8 passwords

This commit is contained in:
Paul Schaub 2022-02-09 23:59:45 +01:00
parent 3e1502ff2a
commit 8877bae675
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
4 changed files with 80 additions and 8 deletions

View file

@ -10,9 +10,9 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
import sop.util.UTF8Util;
public class FileUtil { public class FileUtil {
@ -106,7 +106,7 @@ public class FileUtil {
while ((read = inputStream.read(buf)) != -1) { while ((read = inputStream.read(buf)) != -1) {
byteOut.write(buf, 0, read); byteOut.write(buf, 0, read);
} }
return new String(byteOut.toByteArray(), Charset.forName("UTF8")); return UTF8Util.decodeUTF8(byteOut.toByteArray());
} finally { } finally {
inputStream.close(); inputStream.close();
} }

View file

@ -4,8 +4,6 @@
package sop.exception; package sop.exception;
import java.io.IOException;
public abstract class SOPGPException extends RuntimeException { public abstract class SOPGPException extends RuntimeException {
public SOPGPException() { public SOPGPException() {
@ -134,10 +132,6 @@ public abstract class SOPGPException extends RuntimeException {
super(); super();
} }
public PasswordNotHumanReadable(String message, IOException e) {
super(message, e);
}
@Override @Override
public int getExitCode() { public int getExitCode() {
return EXIT_CODE; return EXIT_CODE;

View file

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.util;
import sop.exception.SOPGPException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
public class UTF8Util {
private static final CharsetDecoder UTF8Decoder = Charset.forName("UTF8")
.newDecoder()
.onUnmappableCharacter(CodingErrorAction.REPORT)
.onMalformedInput(CodingErrorAction.REPORT);
/**
* Detect non-valid UTF8 data.
*
* @see <a href="https://stackoverflow.com/a/1471193">ante on StackOverflow</a>
* @param data
* @return
*/
public static String decodeUTF8(byte[] data) {
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
try {
CharBuffer charBuffer = UTF8Decoder.decode(byteBuffer);
return charBuffer.toString();
} catch (CharacterCodingException e) {
throw new SOPGPException.PasswordNotHumanReadable();
}
}
}

View file

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.util;
import org.junit.jupiter.api.Test;
import sop.exception.SOPGPException;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class UTF8UtilTest {
@Test
public void testValidUtf8Decoding() {
String utf8String = "Hello, World\n";
String decoded = UTF8Util.decodeUTF8(utf8String.getBytes(StandardCharsets.UTF_8));
assertEquals(utf8String, decoded);
}
/**
* Test detection of non-uft8 data.
* @see <a href="https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt">
* Markus Kuhn's UTF8 decoder capability and stress test file</a>
*/
@Test
public void testInvalidUtf8StringThrows() {
assertThrows(SOPGPException.PasswordNotHumanReadable.class,
() -> UTF8Util.decodeUTF8(new byte[] {(byte) 0xa0, (byte) 0xa1}));
assertThrows(SOPGPException.PasswordNotHumanReadable.class,
() -> UTF8Util.decodeUTF8(new byte[] {(byte) 0xc0, (byte) 0xaf}));
assertThrows(SOPGPException.PasswordNotHumanReadable.class,
() -> UTF8Util.decodeUTF8(new byte[] {(byte) 0x80, (byte) 0xbf}));
}
}