mobile/android/tests/background/junit3/src/healthreport/TestEnvironmentV1HashAppender.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/tests/background/junit3/src/healthreport/TestEnvironmentV1HashAppender.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,146 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +package org.mozilla.gecko.background.healthreport;
     1.8 +
     1.9 +import java.io.UnsupportedEncodingException;
    1.10 +import java.security.MessageDigest;
    1.11 +import java.security.NoSuchAlgorithmException;
    1.12 +import java.util.Arrays;
    1.13 +import java.util.LinkedList;
    1.14 +
    1.15 +import org.mozilla.apache.commons.codec.binary.Base64;
    1.16 +import org.mozilla.gecko.background.healthreport.EnvironmentV1.EnvironmentAppender;
    1.17 +import org.mozilla.gecko.background.healthreport.EnvironmentV1.HashAppender;
    1.18 +import org.mozilla.gecko.background.helpers.FakeProfileTestCase;
    1.19 +import org.mozilla.gecko.sync.Utils;
    1.20 +
    1.21 +/**
    1.22 + * Tests the HashAppender functionality. Note that these tests must be run on an Android
    1.23 + * device because the SHA-1 native library needs to be loaded.
    1.24 + */
    1.25 +public class TestEnvironmentV1HashAppender extends FakeProfileTestCase {
    1.26 +  // input and expected values via: http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c
    1.27 +  private final static String[] INPUTS = new String[] {
    1.28 +    "abc",
    1.29 +    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
    1.30 +    "" // To be filled in below.
    1.31 +  };
    1.32 +  static {
    1.33 +    final String baseStr = "01234567";
    1.34 +    final int repetitions = 80;
    1.35 +    final StringBuilder builder = new StringBuilder(baseStr.length() * repetitions);
    1.36 +    for (int i = 0; i < 80; ++i) {
    1.37 +      builder.append(baseStr);
    1.38 +    }
    1.39 +    INPUTS[2] = builder.toString();
    1.40 +  }
    1.41 +
    1.42 +  private final static String[] EXPECTEDS = new String[] {
    1.43 +    "a9993e364706816aba3e25717850c26c9cd0d89d",
    1.44 +    "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
    1.45 +    "dea356a2cddd90c7a7ecedc5ebb563934f460452"
    1.46 +  };
    1.47 +  static {
    1.48 +    for (int i = 0; i < EXPECTEDS.length; ++i) {
    1.49 +      EXPECTEDS[i] = new Base64(-1, null, false).encodeAsString(Utils.hex2Byte(EXPECTEDS[i]));
    1.50 +    }
    1.51 +  }
    1.52 +
    1.53 +  public void testSHA1Hashing() throws Exception {
    1.54 +    for (int i = 0; i < INPUTS.length; ++i) {
    1.55 +      final String input = INPUTS[i];
    1.56 +      final String expected = EXPECTEDS[i];
    1.57 +
    1.58 +      final HashAppender appender = new HashAppender();
    1.59 +      addStringToAppenderInParts(appender, input);
    1.60 +      final String result = appender.toString();
    1.61 +
    1.62 +      assertEquals(expected, result);
    1.63 +    }
    1.64 +  }
    1.65 +
    1.66 +  /**
    1.67 +   * Tests to ensure output is the same as the former MessageDigest implementation (bug 959652).
    1.68 +   */
    1.69 +  public void testAgainstMessageDigestImpl() throws Exception {
    1.70 +    // List.add doesn't allow add(null) so we make a LinkedList here.
    1.71 +    final LinkedList<String> inputs = new LinkedList<String>(Arrays.asList(INPUTS));
    1.72 +    inputs.add(null);
    1.73 +
    1.74 +    for (final String input : inputs) {
    1.75 +      final HashAppender hAppender = new HashAppender();
    1.76 +      final MessageDigestHashAppender mdAppender = new MessageDigestHashAppender();
    1.77 +
    1.78 +      hAppender.append(input);
    1.79 +      mdAppender.append(input);
    1.80 +
    1.81 +      final String hResult = hAppender.toString();
    1.82 +      final String mdResult = mdAppender.toString();
    1.83 +      assertEquals(mdResult, hResult);
    1.84 +    }
    1.85 +  }
    1.86 +
    1.87 +  public void testIntegersAgainstMessageDigestImpl() throws Exception {
    1.88 +    final int[] INPUTS = {Integer.MIN_VALUE, -1337, -42, 0, 42, 1337, Integer.MAX_VALUE};
    1.89 +    for (final int input : INPUTS) {
    1.90 +      final HashAppender hAppender = new HashAppender();
    1.91 +      final MessageDigestHashAppender mdAppender = new MessageDigestHashAppender();
    1.92 +
    1.93 +      hAppender.append(input);
    1.94 +      mdAppender.append(input);
    1.95 +
    1.96 +      final String hResult = hAppender.toString();
    1.97 +      final String mdResult = mdAppender.toString();
    1.98 +      assertEquals(mdResult, hResult);
    1.99 +    }
   1.100 +  }
   1.101 +
   1.102 +  private void addStringToAppenderInParts(final EnvironmentAppender appender, final String input) {
   1.103 +    int substrInd = 0;
   1.104 +    int substrLength = 1;
   1.105 +    while (substrInd < input.length()) {
   1.106 +      final int endInd = Math.min(substrInd + substrLength, input.length());
   1.107 +
   1.108 +      appender.append(input.substring(substrInd, endInd));
   1.109 +
   1.110 +      substrInd = endInd;
   1.111 +      ++substrLength;
   1.112 +    }
   1.113 +  }
   1.114 +
   1.115 +  // --- COPY-PASTA'D CODE, FOR TESTING PURPOSES. ---
   1.116 +  public static class MessageDigestHashAppender extends EnvironmentAppender {
   1.117 +    final MessageDigest hasher;
   1.118 +
   1.119 +    public MessageDigestHashAppender() throws NoSuchAlgorithmException {
   1.120 +      // Note to the security-minded reader: we deliberately use SHA-1 here, not
   1.121 +      // a stronger hash. These identifiers don't strictly need a cryptographic
   1.122 +      // hash function, because there is negligible value in attacking the hash.
   1.123 +      // We use SHA-1 because it's *shorter* -- the exact same reason that Git
   1.124 +      // chose SHA-1.
   1.125 +      hasher = MessageDigest.getInstance("SHA-1");
   1.126 +    }
   1.127 +
   1.128 +    @Override
   1.129 +    public void append(String s) {
   1.130 +      try {
   1.131 +        hasher.update(((s == null) ? "null" : s).getBytes("UTF-8"));
   1.132 +      } catch (UnsupportedEncodingException e) {
   1.133 +        // This can never occur. Thanks, Java.
   1.134 +      }
   1.135 +    }
   1.136 +
   1.137 +    @Override
   1.138 +    public void append(int profileCreation) {
   1.139 +      append(Integer.toString(profileCreation, 10));
   1.140 +    }
   1.141 +
   1.142 +    @Override
   1.143 +    public String toString() {
   1.144 +      // We *could* use ASCII85… but the savings would be negated by the
   1.145 +      // inclusion of JSON-unsafe characters like double-quote.
   1.146 +      return new Base64(-1, null, false).encodeAsString(hasher.digest());
   1.147 +    }
   1.148 +  }
   1.149 +}

mercurial