Path: blob/master/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMLargeDataKAT.java
41161 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import javax.crypto.Cipher;24import javax.crypto.SecretKey;25import javax.crypto.spec.GCMParameterSpec;26import javax.crypto.spec.SecretKeySpec;27import java.security.MessageDigest;28import java.util.HashMap;2930/*31* @test32* @bug 822016533* @summary Verify correctness of large data sizes for GCM.34*/3536/**37* This test stores the MD5 hash of correctly encrypted AES/GCM data for38* particular data lengths. Those lengths are run on SunJCE to verify returns39* the same MD5 hash of the encrypted data. These are not NIST data sets or40* provided by any other organization. The data sets are known good values,41* verified with two different JCE providers (solaris-sparcv9 ucrypto and42* linux SunJCE).43*44* Lengths around 64k are chosen because 64k is the point where45* com.sun.crypto.provider.GaloisCounterMode#doLastBlock() starts it's46* intrinsic warmup47*48* Plaintext is all zeros. Preset key and IV.49*50* The choice of MD5 is for speed. Shortcoming of the algorithm are51* not relevant for this test.52*/5354public class GCMLargeDataKAT {5556// Hash of encrypted results of AES/GCM for particular lengths.57// <data size, hash>58static final HashMap<Integer, String> results = new HashMap<>() {{59put(65534, "1397b91c31ce793895edace4e175bfee"); //64k-260put(65535, "4ad101c9f450e686668b3f8f05db96f0"); //64k-161put(65536, "fbfaee3451acd3f603200d6be0f39b24"); //64k62put(65537, "e7dfca4a71495c65d20982c3c9b9813f"); //64k+163put(67583, "c8ebdcb3532ec6c165de961341af7635"); //66k-164put(67584, "36559d108dfd25dd29da3fec3455b9e5"); //66k65put(67585, "1d21b42d80ea179810744fc23dc228b6"); //66k+166put(102400, "0d1544fcab20bbd4c8103b9d273f2c82"); //100k67put(102401, "f2d53ef65fd12d0a861368659b23ea2e"); //100k+168put(102402, "97f0f524cf63d2d9d23d81e64d416ee0"); //100k+269put(102403, "4a6b4af55b7d9016b64114d6813d639c"); //100k+370put(102404, "ba63cc131fcde2f12ddf2ac634201be8"); //100k+471put(102405, "673d05c7fe5e283e42e5c0d049fdcea6"); //100k+572put(102406, "76cc99a7850ce857eb3cb43049cf9877"); //100k+673put(102407, "65863f99072cf2eb7fce18bd78b33f4e"); //100k+774put(102408, "b9184f0f272682cc1f791fa7070eddd4"); //100k+875put(102409, "45fe36afef43cc665bf22a9ca200c3c2"); //100k+976put(102410, "67249e41646edcb37a78a61b0743cf11"); //100k+077put(102411, "ffdc611e29c8849842e81ec78f32c415"); //100k+1178put(102412, "b7fde7fd52221057dccc1c181a140125"); //100k+1279put(102413, "4b1d6c64d56448105e5613157e69c0ae"); //100k+1380put(102414, "6d2c0b26c0c8785c8eec3298a5f0080c"); //100k+1481put(102415, "1df2061b114fbe56bdf3717e3ee61ef9"); //100k+1582put(102416, "a691742692c683ac9d1254df5fc5f768"); //100k+1683}};84static final int HIGHLEN = 102416;8586static final int GCM_TAG_LENGTH = 16;87static final byte[] iv = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};88static final byte[] key_code = {890, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1590};91static final GCMParameterSpec spec =92new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);93static final SecretKey key = new SecretKeySpec(key_code, "AES");94static boolean testresult = true;95static byte[] plaintext = new byte[HIGHLEN];96static MessageDigest md5;97Cipher cipher;9899GCMLargeDataKAT() {100}101102byte[] encrypt(int inLen) {103try {104cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");105cipher.init(Cipher.ENCRYPT_MODE, key, spec);106return cipher.doFinal(plaintext, 0, inLen);107} catch (Exception e) {108System.err.println("Encrypt Failure (length = " + inLen + ") : " +109e.getMessage());110e.printStackTrace();111}112return new byte[0];113}114115static byte[] hash(byte[] data) {116return md5.digest(data);117}118119// Decrypt the data and return a boolean if the plaintext is all 0's.120boolean decrypt(byte[] data) {121byte[] result = null;122int len = data.length - GCM_TAG_LENGTH;123if (data.length == 0) {124return false;125}126try {127cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");128cipher.init(Cipher.DECRYPT_MODE, key, spec);129result = cipher.doFinal(data);130} catch (Exception e) {131System.err.println("Decrypt Failure (length = " + len + ") : " +132e.getMessage());133e.printStackTrace();134return false;135}136137if (result.length != len) {138System.err.println("Decrypt Failure (length = " + len +139") : plaintext length invalid = " + result.length);140}141// Return false if we find a non zero.142int i = 0;143while (result.length > i) {144if (result[i++] != 0) {145System.err.println("Decrypt Failure (length = " + len +146") : plaintext invalid, char index " + i);147return false;148}149}150return true;151}152153void test() throws Exception {154155// results order is not important156for (int l : results.keySet()) {157byte[] enc = new GCMLargeDataKAT().encrypt(l);158159// verify hash with stored hash of that length160String hashstr = toHex(hash(enc));161boolean r = (hashstr.compareTo(results.get(l)) == 0);162163System.out.println("---------------------------------------------");164165// Encrypted test & results166System.out.println("Encrypt data size " + l + " \tResult: " +167(r ? "Pass" : "Fail"));168if (!r) {169if (enc.length != 0) {170System.out.println("\tExpected: " + results.get(l));171System.out.println("\tReturned: " + hashstr);172}173testresult = false;174continue;175}176177// Decrypted test & results178r = decrypt(enc);179System.out.println("Decrypt data size " + l + " \tResult: " +180(r ? "Pass" : "Fail"));181if (!r) {182testresult = false;183}184}185186// After test complete, throw an error if there was a failure187if (!testresult) {188throw new Exception("Tests failed");189}190}191192/**193* With no argument, the test will run the predefined data lengths194*195* With an integer argument, this test will print the hash of the encrypted196* data of that integer length.197*198*/199public static void main(String args[]) throws Exception {200md5 = MessageDigest.getInstance("MD5");201202if (args.length > 0) {203int len = Integer.parseInt(args[0]);204byte[] e = new GCMLargeDataKAT().encrypt(len);205System.out.println(toHex(hash(e)));206return;207}208209new GCMLargeDataKAT().test();210}211212// bytes to hex string213static String toHex(byte[] bytes) {214StringBuffer hexStringBuffer = new StringBuffer(32);215for (int i = 0; i < bytes.length; i++) {216hexStringBuffer.append(byteToHex(bytes[i]));217}218return hexStringBuffer.toString();219}220// byte to hex221static String byteToHex(byte num) {222char[] hexDigits = new char[2];223hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);224hexDigits[1] = Character.forDigit((num & 0xF), 16);225return new String(hexDigits);226}227}228229230