1 /*
   2  * Copyright (c) 2014, Red Hat, Inc.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary Test vectors for com.sun.crypto.provider.GHASH
  27  */
  28 import java.lang.reflect.Constructor;
  29 import java.lang.reflect.Method;
  30 import java.nio.ByteBuffer;
  31 
  32 public class TestGHASH {
  33 
  34     private final Constructor<?> GHASH;
  35     private final Method UPDATE;
  36     private final Method DIGEST;
  37     
  38     TestGHASH(String className) throws Exception {
  39         Class<?> cls = Class.forName(className);
  40         GHASH = cls.getDeclaredConstructor(byte[].class);
  41         GHASH.setAccessible(true);
  42         UPDATE = cls.getDeclaredMethod("update", byte[].class);
  43         UPDATE.setAccessible(true);
  44         DIGEST = cls.getDeclaredMethod("digest");
  45         DIGEST.setAccessible(true);
  46     }
  47 
  48 
  49     private Object newGHASH(byte[] H) throws Exception {
  50         return GHASH.newInstance(H);
  51     }
  52 
  53     private void updateGHASH(Object hash, byte[] data)
  54             throws Exception {
  55         UPDATE.invoke(hash, data);
  56     }
  57     
  58     private byte[] digestGHASH(Object hash) throws Exception {
  59         return (byte[]) DIGEST.invoke(hash);
  60     }
  61 
  62     private static final String HEX_DIGITS = "0123456789abcdef";
  63     
  64     private static String hex(byte[] bs) {
  65         StringBuilder sb = new StringBuilder(2 * bs.length);
  66         for (byte b : bs) {
  67             sb.append(HEX_DIGITS.charAt((b >> 4) & 0xF));
  68             sb.append(HEX_DIGITS.charAt(b & 0xF));
  69         }
  70         return sb.toString();
  71     }
  72     
  73     private static byte[] bytes(String hex) {
  74         if ((hex.length() & 1) != 0) {
  75             throw new AssertionError();
  76         }
  77         byte[] result = new byte[hex.length() / 2];
  78         for (int i = 0; i < result.length; ++i) {
  79             int a = HEX_DIGITS.indexOf(hex.charAt(2 * i));
  80             int b = HEX_DIGITS.indexOf(hex.charAt(2 * i + 1));
  81             if ((a | b) < 0) {
  82                 if (a < 0) {
  83                     throw new AssertionError(
  84                             "bad character " + (int) hex.charAt(2 * i));
  85                 }
  86                 throw new AssertionError(
  87                         "bad character " + (int) hex.charAt(2 * i + 1));
  88             }
  89             result[i] = (byte) ((a << 4) | b);
  90         }
  91         return result;
  92     }
  93     
  94     private static byte[] bytes(long L0, long L1) {
  95         return ByteBuffer.allocate(16)
  96                 .putLong(L0)
  97                 .putLong(L1)
  98                 .array();
  99     }
 100 
 101     private void check(int testCase, String H, String A,
 102             String C, String expected) throws Exception {
 103         int lenA = A.length() * 4;
 104         while ((A.length() % 32) != 0) {
 105             A += '0';
 106         }
 107         int lenC = C.length() * 4;
 108         while ((C.length() % 32) != 0) {
 109             C += '0';
 110         }
 111         
 112         Object hash = newGHASH(bytes(H));
 113         updateGHASH(hash, bytes(A));
 114         updateGHASH(hash, bytes(C));
 115         updateGHASH(hash, bytes(lenA, lenC));
 116         byte[] digest = digestGHASH(hash);
 117         String actual = hex(digest);
 118         if (!expected.equals(actual)) {
 119             throw new AssertionError(String.format("%d: expected %s, got %s",
 120                     testCase, expected, actual));
 121         }
 122     }
 123 
 124     public static void main(String[] args) throws Exception {
 125         TestGHASH test;
 126         if (args.length == 0) {
 127             test = new TestGHASH("com.sun.crypto.provider.GHASH");
 128         } else {
 129             test = new TestGHASH(args[0]);
 130         }
 131         
 132         // Test vectors from David A. McGrew, John Viega,
 133         // "The Galois/Counter Mode of Operation (GCM)", 2005.
 134         // <http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf>
 135         
 136         test.check(1, "66e94bd4ef8a2c3b884cfa59ca342b2e", "", "", 
 137                 "00000000000000000000000000000000");
 138         test.check(2,
 139                 "66e94bd4ef8a2c3b884cfa59ca342b2e", "",
 140                 "0388dace60b6a392f328c2b971b2fe78",
 141                 "f38cbb1ad69223dcc3457ae5b6b0f885");
 142         test.check(3,
 143                 "b83b533708bf535d0aa6e52980d53b78", "",
 144                 "42831ec2217774244b7221b784d0d49c" +
 145                 "e3aa212f2c02a4e035c17e2329aca12e" +
 146                 "21d514b25466931c7d8f6a5aac84aa05" +
 147                 "1ba30b396a0aac973d58e091473f5985",
 148                 "7f1b32b81b820d02614f8895ac1d4eac");
 149         test.check(4,
 150                 "b83b533708bf535d0aa6e52980d53b78",
 151                 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
 152                 "42831ec2217774244b7221b784d0d49c" +
 153                 "e3aa212f2c02a4e035c17e2329aca12e" +
 154                 "21d514b25466931c7d8f6a5aac84aa05" +
 155                 "1ba30b396a0aac973d58e091",
 156                 "698e57f70e6ecc7fd9463b7260a9ae5f");
 157         test.check(5, "b83b533708bf535d0aa6e52980d53b78",
 158                 "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2",
 159                 "61353b4c2806934a777ff51fa22a4755" +
 160                 "699b2a714fcdc6f83766e5f97b6c7423" +
 161                 "73806900e49f24b22b097544d4896b42" +
 162                 "4989b5e1ebac0f07c23f4598",
 163                 "df586bb4c249b92cb6922877e444d37b");
 164     }
 165 }