< prev index next >

test/jdk/javax/crypto/Cipher/CipherStreamClose.java

Print this page


   1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   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  * @bug 7160837
  27  * @summary Make sure Cipher IO streams doesn't call extra doFinal if close()
  28  * is called multiple times.  Additionally, verify the input and output streams
  29  * match with encryption and decryption with non-stream crypto.
  30  * @modules java.xml.bind
  31  * @run main CipherStreamClose
  32  */
  33 
  34 import java.io.*;
  35 import java.security.DigestOutputStream;
  36 import java.security.DigestInputStream;
  37 import java.security.MessageDigest;
  38 import java.util.Arrays;
  39 
  40 import javax.crypto.Cipher;
  41 import javax.crypto.CipherOutputStream;
  42 import javax.crypto.CipherInputStream;
  43 import javax.crypto.SecretKey;
  44 import javax.crypto.spec.SecretKeySpec;
  45 import javax.xml.bind.DatatypeConverter;
  46 
  47 public class CipherStreamClose {
  48     private static final String message = "This is the sample message";
  49     static boolean debug = false;
  50 
  51     /*
  52      * This method does encryption by cipher.doFinal(), and not with
  53      * CipherOutputStream
  54      */
  55     public static byte[] blockEncrypt(String message, SecretKey key)
  56         throws Exception {
  57 
  58         byte[] data;
  59         Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  60         encCipher.init(Cipher.ENCRYPT_MODE, key);
  61         try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
  62             try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
  63                 oos.writeObject(message);
  64             }
  65             data = bos.toByteArray();
  66         }
  67 
  68         if (debug) {
  69             System.out.println(DatatypeConverter.printHexBinary(data));
  70         }
  71         return encCipher.doFinal(data);
  72 
  73     }
  74 
  75     /*
  76      * This method does decryption by cipher.doFinal(), and not with
  77      * CipherIntputStream
  78      */
  79     public static Object blockDecrypt(byte[] data, SecretKey key)
  80         throws Exception {
  81 
  82         Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
  83         c.init(Cipher.DECRYPT_MODE, key);
  84         data = c.doFinal(data);
  85         try (ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
  86             try (ObjectInputStream ois = new ObjectInputStream(bis)) {
  87                 return ois.readObject();
  88             }
  89         }
  90     }
  91 
  92     public static byte[] streamEncrypt(String message, SecretKey key,
  93         MessageDigest digest)
  94         throws Exception {
  95 
  96         byte[] data;
  97         Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  98         encCipher.init(Cipher.ENCRYPT_MODE, key);
  99         try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
 100             DigestOutputStream dos = new DigestOutputStream(bos, digest);
 101             CipherOutputStream cos = new CipherOutputStream(dos, encCipher)) {
 102             try (ObjectOutputStream oos = new ObjectOutputStream(cos)) {
 103                 oos.writeObject(message);
 104             }
 105             data = bos.toByteArray();
 106         }
 107 
 108         if (debug) {
 109             System.out.println(DatatypeConverter.printHexBinary(data));
 110         }
 111         return data;
 112     }
 113 
 114     public static Object streamDecrypt(byte[] data, SecretKey key,
 115         MessageDigest digest) throws Exception {
 116 
 117         Cipher decCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
 118         decCipher.init(Cipher.DECRYPT_MODE, key);
 119         digest.reset();
 120         try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
 121             DigestInputStream dis = new DigestInputStream(bis, digest);
 122             CipherInputStream cis = new CipherInputStream(dis, decCipher)) {
 123 
 124             try (ObjectInputStream ois = new ObjectInputStream(cis)) {
 125                 return ois.readObject();
 126             }
 127         }
 128     }
 129 
 130     public static void main(String[] args) throws Exception {
 131         MessageDigest digest = MessageDigest.getInstance("SHA1");
 132         SecretKeySpec key = new SecretKeySpec(
 133             DatatypeConverter.parseHexBinary(
 134             "12345678123456781234567812345678"), "AES");
 135 
 136         // Run 'message' through streamEncrypt
 137         byte[] se = streamEncrypt(message, key, digest);
 138         // 'digest' already has the value from the stream, just finish the op
 139         byte[] sd = digest.digest();
 140         digest.reset();
 141         // Run 'message' through blockEncrypt
 142         byte[] be = blockEncrypt(message, key);
 143         // Take digest of encrypted blockEncrypt result
 144         byte[] bd = digest.digest(be);
 145         // Verify both returned the same value
 146         if (!Arrays.equals(sd, bd)) {
 147             System.err.println("Stream: "+DatatypeConverter.printHexBinary(se)+
 148                 "\t Digest: "+DatatypeConverter.printHexBinary(sd));
 149             System.err.println("Block : "+DatatypeConverter.printHexBinary(be)+
 150                 "\t Digest: "+DatatypeConverter.printHexBinary(bd));
 151             throw new Exception("stream & block encryption does not match");
 152         }
 153 
 154         digest.reset();
 155         // Sanity check: Decrypt separately from stream to verify operations
 156         String bm = (String) blockDecrypt(be, key);
 157         if (message.compareTo(bm) != 0) {
 158             System.err.println("Expected: "+message+"\nBlock:    "+bm);
 159             throw new Exception("Block decryption does not match expected");
 160         }
 161 
 162         // Have decryption and digest included in the object stream
 163         String sm = (String) streamDecrypt(se, key, digest);
 164         if (message.compareTo(sm) != 0) {
 165             System.err.println("Expected: "+message+"\nStream:   "+sm);
 166             throw new Exception("Stream decryption does not match expected.");
 167         }
 168     }














































 169 }
   1 /*
   2  * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
   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  * @bug 7160837
  27  * @summary Make sure Cipher IO streams doesn't call extra doFinal if close()
  28  * is called multiple times.  Additionally, verify the input and output streams
  29  * match with encryption and decryption with non-stream crypto.

  30  * @run main CipherStreamClose
  31  */
  32 
  33 import java.io.*;
  34 import java.security.DigestOutputStream;
  35 import java.security.DigestInputStream;
  36 import java.security.MessageDigest;
  37 import java.util.Arrays;
  38 
  39 import javax.crypto.Cipher;
  40 import javax.crypto.CipherOutputStream;
  41 import javax.crypto.CipherInputStream;
  42 import javax.crypto.SecretKey;
  43 import javax.crypto.spec.SecretKeySpec;

  44 
  45 public class CipherStreamClose {
  46     private static final String message = "This is the sample message";
  47     static boolean debug = false;
  48 
  49     /*
  50      * This method does encryption by cipher.doFinal(), and not with
  51      * CipherOutputStream
  52      */
  53     public static byte[] blockEncrypt(String message, SecretKey key)
  54         throws Exception {
  55 
  56         byte[] data;
  57         Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  58         encCipher.init(Cipher.ENCRYPT_MODE, key);
  59         try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
  60             try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
  61                 oos.writeObject(message);
  62             }
  63             data = bos.toByteArray();
  64         }
  65 
  66         if (debug) {
  67             System.out.println(printHexBinary(data));
  68         }
  69         return encCipher.doFinal(data);
  70 
  71     }
  72 
  73     /*
  74      * This method does decryption by cipher.doFinal(), and not with
  75      * CipherIntputStream
  76      */
  77     public static Object blockDecrypt(byte[] data, SecretKey key)
  78         throws Exception {
  79 
  80         Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
  81         c.init(Cipher.DECRYPT_MODE, key);
  82         data = c.doFinal(data);
  83         try (ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
  84             try (ObjectInputStream ois = new ObjectInputStream(bis)) {
  85                 return ois.readObject();
  86             }
  87         }
  88     }
  89 
  90     public static byte[] streamEncrypt(String message, SecretKey key,
  91         MessageDigest digest)
  92         throws Exception {
  93 
  94         byte[] data;
  95         Cipher encCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  96         encCipher.init(Cipher.ENCRYPT_MODE, key);
  97         try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
  98             DigestOutputStream dos = new DigestOutputStream(bos, digest);
  99             CipherOutputStream cos = new CipherOutputStream(dos, encCipher)) {
 100             try (ObjectOutputStream oos = new ObjectOutputStream(cos)) {
 101                 oos.writeObject(message);
 102             }
 103             data = bos.toByteArray();
 104         }
 105 
 106         if (debug) {
 107             System.out.println(printHexBinary(data));
 108         }
 109         return data;
 110     }
 111 
 112     public static Object streamDecrypt(byte[] data, SecretKey key,
 113         MessageDigest digest) throws Exception {
 114 
 115         Cipher decCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
 116         decCipher.init(Cipher.DECRYPT_MODE, key);
 117         digest.reset();
 118         try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
 119             DigestInputStream dis = new DigestInputStream(bis, digest);
 120             CipherInputStream cis = new CipherInputStream(dis, decCipher)) {
 121 
 122             try (ObjectInputStream ois = new ObjectInputStream(cis)) {
 123                 return ois.readObject();
 124             }
 125         }
 126     }
 127 
 128     public static void main(String[] args) throws Exception {
 129         MessageDigest digest = MessageDigest.getInstance("SHA1");
 130         SecretKeySpec key = new SecretKeySpec(
 131             parseHexBinary(
 132             "12345678123456781234567812345678"), "AES");
 133 
 134         // Run 'message' through streamEncrypt
 135         byte[] se = streamEncrypt(message, key, digest);
 136         // 'digest' already has the value from the stream, just finish the op
 137         byte[] sd = digest.digest();
 138         digest.reset();
 139         // Run 'message' through blockEncrypt
 140         byte[] be = blockEncrypt(message, key);
 141         // Take digest of encrypted blockEncrypt result
 142         byte[] bd = digest.digest(be);
 143         // Verify both returned the same value
 144         if (!Arrays.equals(sd, bd)) {
 145             System.err.println("Stream: "+ printHexBinary(se)+
 146                 "\t Digest: "+ printHexBinary(sd));
 147             System.err.println("Block : "+printHexBinary(be)+
 148                 "\t Digest: "+ printHexBinary(bd));
 149             throw new Exception("stream & block encryption does not match");
 150         }
 151 
 152         digest.reset();
 153         // Sanity check: Decrypt separately from stream to verify operations
 154         String bm = (String) blockDecrypt(be, key);
 155         if (message.compareTo(bm) != 0) {
 156             System.err.println("Expected: "+message+"\nBlock:    "+bm);
 157             throw new Exception("Block decryption does not match expected");
 158         }
 159 
 160         // Have decryption and digest included in the object stream
 161         String sm = (String) streamDecrypt(se, key, digest);
 162         if (message.compareTo(sm) != 0) {
 163             System.err.println("Expected: "+message+"\nStream:   "+sm);
 164             throw new Exception("Stream decryption does not match expected.");
 165         }
 166     }
 167 
 168     public static  byte[] parseHexBinary(String s) {
 169         final int len = s.length();
 170 
 171         // "111" is not a valid hex encoding.
 172         if (len % 2 != 0) {
 173             throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);
 174         }
 175 
 176         byte[] out = new byte[len / 2];
 177 
 178         for (int i = 0; i < len; i += 2) {
 179             int h = hexToBin(s.charAt(i));
 180             int l = hexToBin(s.charAt(i + 1));
 181             if (h == -1 || l == -1) {
 182                 throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);
 183             }
 184 
 185             out[i / 2] = (byte) (h * 16 + l);
 186         }
 187 
 188         return out;
 189     }
 190 
 191     private static int hexToBin(char ch) {
 192         if ('0' <= ch && ch <= '9') {
 193             return ch - '0';
 194         }
 195         if ('A' <= ch && ch <= 'F') {
 196             return ch - 'A' + 10;
 197         }
 198         if ('a' <= ch && ch <= 'f') {
 199             return ch - 'a' + 10;
 200         }
 201         return -1;
 202     }
 203     private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
 204 
 205     public static String printHexBinary(byte[] data) {
 206         StringBuilder r = new StringBuilder(data.length * 2);
 207         for (byte b : data) {
 208             r.append(hexCode[(b >> 4) & 0xF]);
 209             r.append(hexCode[(b & 0xF)]);
 210         }
 211         return r.toString();
 212     }
 213 }
< prev index next >