| /* |
| * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @test |
| * @bug 0000000 |
| * @summary Makes sure that Cipher.doFinal() returns the right number |
| * of bytes written |
| * @author Jan Luehe |
| */ |
| import java.security.*; |
| import java.security.interfaces.*; |
| import javax.crypto.*; |
| import javax.crypto.spec.*; |
| |
| public class DoFinalReturnLen { |
| static byte[] dataToEncrypt = { |
| (byte)0x02, (byte)0xA4, (byte)0x20, (byte)0x87, |
| (byte)0xB6, (byte)0xC4, (byte)0x54, (byte)0x89, |
| (byte)0xA2, (byte)0xA4, (byte)0x10, (byte)0x87, |
| (byte)0xCD, (byte)0x76, (byte)0x43, (byte)0xF0, |
| (byte)0x72, (byte)0xA4, (byte)0xA0, (byte)0x82, |
| (byte)0x26, (byte)0xC4, (byte)0x54, (byte)0x19, |
| (byte)0x09, (byte)0xAC, (byte)0x2A, (byte)0xE7, |
| (byte)0x1D, (byte)0x74, (byte)0x13, (byte)0x20, |
| (byte)0xAD, (byte)0xD4, (byte)0xD0, (byte)0x87, |
| (byte)0xB6, (byte)0xC5, (byte)0x24, (byte)0x89, |
| (byte)0x02, (byte)0xF4, (byte)0x90, (byte)0x8E, |
| (byte)0x5D, (byte)0x76, (byte)0x43, (byte)0x2F, |
| (byte)0x03, (byte)0xAD, (byte)0x20, (byte)0x8C, |
| (byte)0xB5, (byte)0xC4, (byte)0xA4, (byte)0x39, |
| (byte)0xD2, (byte)0xA4, (byte)0xE0, (byte)0x87, |
| (byte)0xCD, (byte)0x56, (byte)0x53, (byte)0x20 |
| }; |
| |
| static byte[] dataToEncryptUneven = { |
| (byte)0x02, (byte)0xA4, (byte)0x20, (byte)0x87, |
| (byte)0xB6, (byte)0xC4, (byte)0x54, (byte)0x89, |
| (byte)0xA2, (byte)0xA4, (byte)0x10, (byte)0x87, |
| (byte)0xCD, (byte)0x76, (byte)0x43, (byte)0xF0, |
| (byte)0x72, (byte)0xA4, (byte)0xA0, (byte)0x82, |
| (byte)0x26, (byte)0xC4, (byte)0x54, (byte)0x19, |
| (byte)0x09, (byte)0xAC, (byte)0x2A, (byte)0xE7, |
| (byte)0x1D, (byte)0x74, (byte)0x13, (byte)0x20, |
| (byte)0xAD, (byte)0xD4, (byte)0xD0, (byte)0x87, |
| (byte)0xB6, (byte)0xC5, (byte)0x24, (byte)0x89, |
| (byte)0x02, (byte)0xF4, (byte)0x90, (byte)0x8E, |
| (byte)0x5D, (byte)0x76, (byte)0x43, (byte)0x2F, |
| (byte)0x03, (byte)0xAD, (byte)0x20, (byte)0x8C, |
| (byte)0xB5, (byte)0xC4, (byte)0xA4, (byte)0x39, |
| (byte)0xD2, (byte)0xA4, (byte)0xE0, (byte)0x87, |
| (byte)0xCD, (byte)0x56, (byte)0x53, (byte)0x20, |
| (byte)0x22 |
| }; |
| |
| static byte[] iv = { |
| (byte)0x03, (byte)0xAD, (byte)0x20, (byte)0x8C, |
| (byte)0xB5, (byte)0xC4, (byte)0xA4, (byte)0x39 |
| }; |
| |
| public static void main (String args[]) throws Exception { |
| byte[] encryptedData = null; |
| byte[] decryptedData = null; |
| Cipher newDES = null; |
| IvParameterSpec IvParamSpec = null; |
| SecretKey sKey = null; |
| |
| // Step 0: add providers |
| Provider sun = new com.sun.crypto.provider.SunJCE(); |
| Security.addProvider(sun); |
| Provider[] theProviders = Security.getProviders(); |
| for (int index = 0; index < theProviders.length; index++) { |
| System.out.println(theProviders[index].getName()); |
| System.out.println(theProviders[index].getVersion()); |
| System.out.println(theProviders[index].getInfo()); |
| } |
| |
| // Cipher Object |
| newDES = Cipher.getInstance("DES/CBC/PKCS5Padding", |
| "SunJCE"); |
| byte[] keyData = { |
| (byte)0x46, (byte)0x19, (byte)0x20, (byte)0x5e, |
| (byte)0xef, (byte)0x0b, (byte)0x7c, (byte)0x45 |
| }; |
| // Generate secret key |
| SecretKeyFactory desFactory |
| = SecretKeyFactory.getInstance("DES", "SunJCE"); |
| DESKeySpec keySpec = new DESKeySpec(keyData); |
| sKey = desFactory.generateSecret(keySpec); |
| |
| // encrypt data |
| System.out.println("DataToEncrypt:"); |
| printBuffer(dataToEncrypt); |
| |
| IvParamSpec = new IvParameterSpec(iv, 0, 8); |
| newDES.init(Cipher.ENCRYPT_MODE, sKey, IvParamSpec); |
| |
| encryptedData = |
| new byte[newDES.getOutputSize(dataToEncrypt.length)]; |
| int outputLenUpdate = newDES.update(dataToEncrypt, 0, |
| dataToEncrypt.length, |
| encryptedData); |
| int outputLenFinal = newDES.doFinal(encryptedData, |
| outputLenUpdate); |
| |
| System.out.println("ENCRYPT : Update " + outputLenUpdate |
| + " bytes"); |
| System.out.println("ENCRYPT : Final " + outputLenFinal |
| + " bytes"); |
| |
| System.out.println("Encrypted data:"); |
| printBuffer(encryptedData); |
| |
| // decrypt data |
| newDES.init(Cipher.DECRYPT_MODE, sKey, IvParamSpec); |
| |
| decryptedData = |
| new byte[newDES.getOutputSize(encryptedData.length)]; |
| System.out.println("encrLen: " + encryptedData.length); |
| System.out.println("decrLen: " + decryptedData.length); |
| |
| outputLenUpdate = newDES.update(encryptedData, 0, |
| encryptedData.length, |
| decryptedData, 0); |
| |
| outputLenFinal = newDES.doFinal(decryptedData, |
| outputLenUpdate); |
| |
| System.out.println("DECRYPT : Update " + outputLenUpdate |
| + " bytes"); |
| System.out.println("DECRYPT : Final " + outputLenFinal |
| + " bytes"); |
| |
| System.out.println("Decrypted data:"); |
| printBuffer(decryptedData); |
| int len = 0; |
| if (dataToEncrypt.length >= decryptedData.length) |
| len = decryptedData.length; |
| else |
| len = dataToEncrypt.length; |
| for (int i=0; i<len; i++) |
| if (dataToEncrypt[i] != decryptedData[i]) |
| throw new Exception("Original and recovered data differ"); |
| |
| // decrypt data with exact output buffer length |
| newDES.init(Cipher.DECRYPT_MODE, sKey, IvParamSpec); |
| |
| decryptedData = new byte[dataToEncrypt.length]; |
| System.out.println("encrLen: " + encryptedData.length); |
| System.out.println("decrLen: " + decryptedData.length); |
| |
| outputLenUpdate = newDES.update(encryptedData, 0, |
| encryptedData.length, |
| decryptedData, 0); |
| |
| outputLenFinal = newDES.doFinal(decryptedData, |
| outputLenUpdate); |
| |
| System.out.println("DECRYPT : Update " + outputLenUpdate |
| + " bytes"); |
| System.out.println("DECRYPT : Final " + outputLenFinal |
| + " bytes"); |
| |
| System.out.println("Decrypted data:"); |
| printBuffer(decryptedData); |
| len = 0; |
| if (dataToEncrypt.length >= decryptedData.length) |
| len = decryptedData.length; |
| else |
| len = dataToEncrypt.length; |
| for (int i=0; i<len; i++) |
| if (dataToEncrypt[i] != decryptedData[i]) |
| throw new Exception("Original and recovered data differ"); |
| |
| // |
| // run the same test for the input data with uneven number of bytes |
| // |
| |
| // encrypt data |
| System.out.println(); |
| System.out.println("DataToEncrypt:"); |
| printBuffer(dataToEncryptUneven); |
| |
| newDES.init(Cipher.ENCRYPT_MODE, sKey, IvParamSpec); |
| |
| encryptedData = |
| new byte[newDES.getOutputSize(dataToEncryptUneven.length)]; |
| outputLenUpdate = newDES.update(dataToEncryptUneven, 0, |
| dataToEncryptUneven.length, |
| encryptedData); |
| outputLenFinal = newDES.doFinal(encryptedData, |
| outputLenUpdate); |
| |
| System.out.println("ENCRYPT : Update " + outputLenUpdate |
| + " bytes"); |
| System.out.println("ENCRYPT : Final " + outputLenFinal |
| + " bytes"); |
| |
| System.out.println("Encrypted data:"); |
| printBuffer(encryptedData); |
| |
| // decrypt data |
| newDES.init(Cipher.DECRYPT_MODE, sKey, IvParamSpec); |
| |
| decryptedData = |
| new byte[newDES.getOutputSize(encryptedData.length)]; |
| System.out.println("encrLen: " + encryptedData.length); |
| System.out.println("decrLen: " + decryptedData.length); |
| |
| outputLenUpdate = newDES.update(encryptedData, 0, |
| encryptedData.length, |
| decryptedData, 0); |
| |
| outputLenFinal = newDES.doFinal(decryptedData, |
| outputLenUpdate); |
| |
| System.out.println("DECRYPT : Update " + outputLenUpdate |
| + " bytes"); |
| System.out.println("DECRYPT : Final " + outputLenFinal |
| + " bytes"); |
| |
| System.out.println("Decrypted data:"); |
| printBuffer(decryptedData); |
| len = 0; |
| if (dataToEncryptUneven.length >= decryptedData.length) |
| len = decryptedData.length; |
| else |
| len = dataToEncryptUneven.length; |
| for (int i=0; i<len; i++) |
| if (dataToEncryptUneven[i] != decryptedData[i]) |
| throw new Exception("Original and recovered data differ"); |
| |
| // decrypt data with exact output buffer length |
| newDES.init(Cipher.DECRYPT_MODE, sKey, IvParamSpec); |
| |
| decryptedData = new byte[dataToEncryptUneven.length]; |
| System.out.println("encrLen: " + encryptedData.length); |
| System.out.println("decrLen: " + decryptedData.length); |
| |
| outputLenUpdate = newDES.update(encryptedData, 0, |
| encryptedData.length, |
| decryptedData, 0); |
| |
| outputLenFinal = newDES.doFinal(decryptedData, |
| outputLenUpdate); |
| |
| System.out.println("DECRYPT : Update " + outputLenUpdate |
| + " bytes"); |
| System.out.println("DECRYPT : Final " + outputLenFinal |
| + " bytes"); |
| |
| System.out.println("Decrypted data:"); |
| printBuffer(decryptedData); |
| len = 0; |
| if (dataToEncryptUneven.length >= decryptedData.length) |
| len = decryptedData.length; |
| else |
| len = dataToEncryptUneven.length; |
| for (int i=0; i<len; i++) |
| if (dataToEncryptUneven[i] != decryptedData[i]) |
| throw new Exception("Original and recovered data differ"); |
| |
| System.out.println(); |
| System.out.println("Test succeeded"); |
| } |
| |
| // These methods print out a byte array in a reasonably pretty format. |
| private static void printBuffer(byte[] byteArray) { |
| printBuffer(byteArray, byteArray.length); |
| } |
| |
| private static void printBuffer(byte[] byteArray, int length) { |
| StringBuffer textLine = new StringBuffer(" "); |
| System.out.print("; 00000000: "); |
| for (int i=0; i < length; i++) { |
| if (((i%16) == 0) && i != 0) { |
| System.out.println("[" + textLine + "]"); |
| System.out.print("; "); |
| hexPrint(i, 8); |
| System.out.print(": "); |
| for(int j=0; j<16; j++) { |
| textLine.setCharAt(j,' '); |
| } |
| } |
| hexPrint((int) byteArray[i], 2); |
| System.out.print(" "); |
| if ((byteArray[i] < 32) || (byteArray[i] > 127)) { |
| textLine.setCharAt(i%16, '.'); |
| } else { |
| textLine.setCharAt(i%16,(char)byteArray[i]); |
| } |
| } |
| if (((length % 16) != 0) || (length == 0)) { |
| for (int i = 0; i < 16 - (length % 16); i++) { |
| System.out.print(" "); |
| } |
| } |
| System.out.println("[" + textLine + "]"); |
| } |
| |
| private static void hexPrint(int value, int padding) { |
| String hexString = new String("0123456789ABCDEF"); |
| for (int i = (padding - 1); i >= 0; i--) { |
| System.out.print(hexString.charAt((value >> (i*4)) & 0xF)); |
| } |
| } |
| } |