From d705f2c278dedf8ddf91a24cc1348fcca78bcc10 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 1 Sep 2017 19:03:32 +0200 Subject: [PATCH] fold autocrypt header lines differently --- .../fsck/k9/autocrypt/AutocryptHeader.java | 49 ++++++++++++++----- .../k9/autocrypt/AutocryptHeaderTest.java | 41 +++++++++++----- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java index c7114c1da..686152961 100644 --- a/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java +++ b/k9mail/src/main/java/com/fsck/k9/autocrypt/AutocryptHeader.java @@ -41,29 +41,52 @@ class AutocryptHeader { } String toRawHeaderString() { + // TODO we don't properly fold lines here. if we want to support parameters, we need to do that somehow if (!parameters.isEmpty()) { throw new UnsupportedOperationException("arbitrary parameters not supported"); } - String autocryptHeaderString = AutocryptHeader.AUTOCRYPT_HEADER + ": "; - autocryptHeaderString += AutocryptHeader.AUTOCRYPT_PARAM_ADDR + "=" + addr + ";"; + StringBuilder builder = new StringBuilder(); + builder.append(AutocryptHeader.AUTOCRYPT_HEADER).append(": "); + builder.append(AutocryptHeader.AUTOCRYPT_PARAM_ADDR).append('=').append(addr).append("; "); if (isPreferEncryptMutual) { - autocryptHeaderString += AutocryptHeader.AUTOCRYPT_PARAM_PREFER_ENCRYPT + "=" + - AutocryptHeader.AUTOCRYPT_PREFER_ENCRYPT_MUTUAL + ";"; + builder.append(AutocryptHeader.AUTOCRYPT_PARAM_PREFER_ENCRYPT) + .append('=').append(AutocryptHeader.AUTOCRYPT_PREFER_ENCRYPT_MUTUAL).append("; "); } - autocryptHeaderString += AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA + "=" + ByteString.of(keyData).base64(); + builder.append(AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA).append("="); - StringBuilder headerLines = new StringBuilder(); - int autocryptHeaderLength = autocryptHeaderString.length(); - for (int i = 0; i < autocryptHeaderLength; i += HEADER_LINE_LENGTH) { - if (i + HEADER_LINE_LENGTH <= autocryptHeaderLength) { - headerLines.append(autocryptHeaderString, i, i + HEADER_LINE_LENGTH).append("\r\n "); + appendBase64KeyData(builder); + + return builder.toString(); + } + + private void appendBase64KeyData(StringBuilder builder) { + String base64KeyData = ByteString.of(keyData).base64(); + + int base64Length = base64KeyData.length(); + int lineLengthBeforeKeyData = builder.length(); + int dataLengthInFirstLine = HEADER_LINE_LENGTH -lineLengthBeforeKeyData; + + boolean keyDataFitsInFirstLine = dataLengthInFirstLine > 0 && base64Length < dataLengthInFirstLine; + if (keyDataFitsInFirstLine) { + builder.append(base64KeyData, 0, base64Length); + return; + } + + if (dataLengthInFirstLine > 0) { + builder.append(base64KeyData, 0, dataLengthInFirstLine).append("\r\n "); + } else { + builder.append("\r\n "); + dataLengthInFirstLine = 0; + } + + for (int i = dataLengthInFirstLine; i < base64Length; i += HEADER_LINE_LENGTH) { + if (i + HEADER_LINE_LENGTH <= base64Length) { + builder.append(base64KeyData, i, i + HEADER_LINE_LENGTH).append("\r\n "); } else { - headerLines.append(autocryptHeaderString, i, autocryptHeaderLength); + builder.append(base64KeyData, i, base64Length); } } - - return headerLines.toString(); } @Override diff --git a/k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderTest.java b/k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderTest.java index 6b70669ce..c5e823e88 100644 --- a/k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderTest.java +++ b/k9mail/src/test/java/com/fsck/k9/autocrypt/AutocryptHeaderTest.java @@ -13,27 +13,44 @@ import static org.junit.Assert.*; public class AutocryptHeaderTest { static final HashMap PARAMETERS = new HashMap<>(); static final String ADDR = "addr"; + static final String ADDR_LONG = "veryveryverylongaddressthatspansmorethanalinelengthintheheader"; static final byte[] KEY_DATA = ("theseare120charactersxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").getBytes(); + static final byte[] KEY_DATA_SHORT = ("theseare15chars").getBytes(); static final boolean IS_PREFER_ENCRYPT_MUTUAL = true; - private AutocryptHeader autocryptHeader; - - - @Before - public void setUp() throws Exception { - autocryptHeader = new AutocryptHeader(PARAMETERS, ADDR, KEY_DATA, IS_PREFER_ENCRYPT_MUTUAL); - } - - @Test public void toRawHeaderString_returnsExpected() throws Exception { + AutocryptHeader autocryptHeader = new AutocryptHeader(PARAMETERS, ADDR, KEY_DATA, IS_PREFER_ENCRYPT_MUTUAL); String autocryptHeaderString = autocryptHeader.toRawHeaderString(); - String expected = "Autocrypt: addr=addr;prefer-encrypt=mutual;keydata=dGhlc2VhcmUxMjBjaGFyYWN0Z\r\n" + - " XJzeHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e\r\n" + - " Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4"; + String expected = "Autocrypt: addr=addr; prefer-encrypt=mutual; keydata=dGhlc2VhcmUxMjBjaGFyYWN\r\n" + + " 0ZXJzeHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\r\n" + + " 4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4"; + assertEquals(expected, autocryptHeaderString); + } + + @Test + public void toRawHeaderString_withLongAddress_returnsExpected() throws Exception { + AutocryptHeader autocryptHeader = new AutocryptHeader(PARAMETERS, + ADDR_LONG, KEY_DATA, IS_PREFER_ENCRYPT_MUTUAL); + String autocryptHeaderString = autocryptHeader.toRawHeaderString(); + + String expected = "Autocrypt: addr=veryveryverylongaddressthatspansmorethanalinelengthintheheader; prefer-encrypt=mutual; keydata=\r\n" + + " dGhlc2VhcmUxMjBjaGFyYWN0ZXJzeHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\r\n" + + " eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\r\n" + + " eHh4eHh4"; + assertEquals(expected, autocryptHeaderString); + } + + @Test + public void toRawHeaderString_withShortData_returnsExpected() throws Exception { + AutocryptHeader autocryptHeader = new AutocryptHeader(PARAMETERS, + ADDR, KEY_DATA_SHORT, IS_PREFER_ENCRYPT_MUTUAL); + String autocryptHeaderString = autocryptHeader.toRawHeaderString(); + + String expected = "Autocrypt: addr=addr; prefer-encrypt=mutual; keydata=dGhlc2VhcmUxNWNoYXJz"; assertEquals(expected, autocryptHeaderString); } }