Path: blob/master/test/jdk/javax/crypto/Cipher/CipherStreamClose.java
41149 views
/*1* Copyright (c) 2013, 2018, 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*/2223/*24* @test25* @bug 716083726* @summary Make sure Cipher IO streams doesn't call extra doFinal if close()27* is called multiple times. Additionally, verify the input and output streams28* match with encryption and decryption with non-stream crypto.29* @run main CipherStreamClose30*/3132import java.io.*;33import java.security.DigestOutputStream;34import java.security.DigestInputStream;35import java.security.MessageDigest;36import java.util.Arrays;3738import javax.crypto.Cipher;39import javax.crypto.CipherOutputStream;40import javax.crypto.CipherInputStream;41import javax.crypto.SecretKey;42import javax.crypto.spec.SecretKeySpec;4344public class CipherStreamClose {45private static final String message = "This is the sample message";46static boolean debug = false;4748/*49* This method does encryption by cipher.doFinal(), and not with50* CipherOutputStream51*/52public static byte[] blockEncrypt(String message, SecretKey key)53throws Exception {5455byte[] data;56Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");57encCipher.init(Cipher.ENCRYPT_MODE, key);58try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {59try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {60oos.writeObject(message);61}62data = bos.toByteArray();63}6465if (debug) {66System.out.println(printHexBinary(data));67}68return encCipher.doFinal(data);6970}7172/*73* This method does decryption by cipher.doFinal(), and not with74* CipherIntputStream75*/76public static Object blockDecrypt(byte[] data, SecretKey key)77throws Exception {7879Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");80c.init(Cipher.DECRYPT_MODE, key);81data = c.doFinal(data);82try (ByteArrayInputStream bis = new ByteArrayInputStream(data)) {83try (ObjectInputStream ois = new ObjectInputStream(bis)) {84return ois.readObject();85}86}87}8889public static byte[] streamEncrypt(String message, SecretKey key,90MessageDigest digest)91throws Exception {9293byte[] data;94Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");95encCipher.init(Cipher.ENCRYPT_MODE, key);96try (ByteArrayOutputStream bos = new ByteArrayOutputStream();97DigestOutputStream dos = new DigestOutputStream(bos, digest);98CipherOutputStream cos = new CipherOutputStream(dos, encCipher)) {99try (ObjectOutputStream oos = new ObjectOutputStream(cos)) {100oos.writeObject(message);101}102data = bos.toByteArray();103}104105if (debug) {106System.out.println(printHexBinary(data));107}108return data;109}110111public static Object streamDecrypt(byte[] data, SecretKey key,112MessageDigest digest) throws Exception {113114Cipher decCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");115decCipher.init(Cipher.DECRYPT_MODE, key);116digest.reset();117try (ByteArrayInputStream bis = new ByteArrayInputStream(data);118DigestInputStream dis = new DigestInputStream(bis, digest);119CipherInputStream cis = new CipherInputStream(dis, decCipher)) {120121try (ObjectInputStream ois = new ObjectInputStream(cis)) {122return ois.readObject();123}124}125}126127public static void main(String[] args) throws Exception {128MessageDigest digest = MessageDigest.getInstance("SHA1");129SecretKeySpec key = new SecretKeySpec(130parseHexBinary(131"12345678123456781234567812345678"), "AES");132133// Run 'message' through streamEncrypt134byte[] se = streamEncrypt(message, key, digest);135// 'digest' already has the value from the stream, just finish the op136byte[] sd = digest.digest();137digest.reset();138// Run 'message' through blockEncrypt139byte[] be = blockEncrypt(message, key);140// Take digest of encrypted blockEncrypt result141byte[] bd = digest.digest(be);142// Verify both returned the same value143if (!Arrays.equals(sd, bd)) {144System.err.println("Stream: "+ printHexBinary(se)+145"\t Digest: "+ printHexBinary(sd));146System.err.println("Block : "+printHexBinary(be)+147"\t Digest: "+ printHexBinary(bd));148throw new Exception("stream & block encryption does not match");149}150151digest.reset();152// Sanity check: Decrypt separately from stream to verify operations153String bm = (String) blockDecrypt(be, key);154if (message.compareTo(bm) != 0) {155System.err.println("Expected: "+message+"\nBlock: "+bm);156throw new Exception("Block decryption does not match expected");157}158159// Have decryption and digest included in the object stream160String sm = (String) streamDecrypt(se, key, digest);161if (message.compareTo(sm) != 0) {162System.err.println("Expected: "+message+"\nStream: "+sm);163throw new Exception("Stream decryption does not match expected.");164}165}166167public static byte[] parseHexBinary(String s) {168final int len = s.length();169170// "111" is not a valid hex encoding.171if (len % 2 != 0) {172throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);173}174175byte[] out = new byte[len / 2];176177for (int i = 0; i < len; i += 2) {178int h = hexToBin(s.charAt(i));179int l = hexToBin(s.charAt(i + 1));180if (h == -1 || l == -1) {181throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);182}183184out[i / 2] = (byte) (h * 16 + l);185}186187return out;188}189190private static int hexToBin(char ch) {191if ('0' <= ch && ch <= '9') {192return ch - '0';193}194if ('A' <= ch && ch <= 'F') {195return ch - 'A' + 10;196}197if ('a' <= ch && ch <= 'f') {198return ch - 'a' + 10;199}200return -1;201}202private static final char[] hexCode = "0123456789ABCDEF".toCharArray();203204public static String printHexBinary(byte[] data) {205StringBuilder r = new StringBuilder(data.length * 2);206for (byte b : data) {207r.append(hexCode[(b >> 4) & 0xF]);208r.append(hexCode[(b & 0xF)]);209}210return r.toString();211}212}213214215