Skip to content

Commit

Permalink
Implement detection of non-UTF8 passwords
Browse files Browse the repository at this point in the history
  • Loading branch information
vanitasvitae committed Feb 9, 2022
1 parent 3e1502f commit 8877bae
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 8 deletions.
4 changes: 2 additions & 2 deletions sop-java-picocli/src/main/java/sop/cli/picocli/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.Charset;

import sop.exception.SOPGPException;
import sop.util.UTF8Util;

public class FileUtil {

Expand Down Expand Up @@ -106,7 +106,7 @@ public static String stringFromInputStream(InputStream inputStream) throws IOExc
while ((read = inputStream.read(buf)) != -1) {
byteOut.write(buf, 0, read);
}
return new String(byteOut.toByteArray(), Charset.forName("UTF8"));
return UTF8Util.decodeUTF8(byteOut.toByteArray());
} finally {
inputStream.close();
}
Expand Down
6 changes: 0 additions & 6 deletions sop-java/src/main/java/sop/exception/SOPGPException.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

package sop.exception;

import java.io.IOException;

public abstract class SOPGPException extends RuntimeException {

public SOPGPException() {
Expand Down Expand Up @@ -134,10 +132,6 @@ public PasswordNotHumanReadable() {
super();
}

public PasswordNotHumanReadable(String message, IOException e) {
super(message, e);
}

@Override
public int getExitCode() {
return EXIT_CODE;
Expand Down
39 changes: 39 additions & 0 deletions sop-java/src/main/java/sop/util/UTF8Util.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
39 changes: 39 additions & 0 deletions sop-java/src/test/java/sop/util/UTF8UtilTest.java
Original file line number Diff line number Diff line change
@@ -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}));
}
}

0 comments on commit 8877bae

Please sign in to comment.