/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ /** * @author Alexander Y. Kleymenov * @version $Revision$ */ package org.apache.harmony.crypto.tests.javax.crypto; import junit.framework.TestCase; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchProviderException; import java.util.ArrayList; import java.util.Arrays; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NullCipher; import javax.crypto.SealedObject; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import libcore.util.SerializationTester; /** */ public class SealedObjectTest extends TestCase { class Mock_SealedObject extends SealedObject { public Mock_SealedObject(Serializable object, Cipher c) throws IOException, IllegalBlockSizeException { super(object, c); } public byte[] get_encodedParams() { return super.encodedParams; } } /** * readObject(ObjectInputStream s) method testing. Tests if the * serialization/deserialization works correctly: object is serialized, * deserialized, the content od deserialized object equals to the content of * initial object. */ public void testReadObject() throws Exception { String secret = "secret string"; SealedObject so = new SealedObject(secret, new NullCipher()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(so); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( bos.toByteArray())); SealedObject so_des = (SealedObject) ois.readObject(); assertEquals("The secret content of deserialized object " + "should be equal to the secret content of initial object", secret, so_des.getObject(new NullCipher())); assertEquals("The value returned by getAlgorithm() method of " + "deserialized object should be equal to the value returned " + "by getAlgorithm() method of initial object", so .getAlgorithm(), so_des.getAlgorithm()); } /** * SealedObject(Serializable object, Cipher c) method testing. Tests if the * NullPointerException is thrown in the case of null cipher. */ public void testSealedObject1() throws Exception { String secret = "secret string"; try { new SealedObject(secret, null); fail("NullPointerException should be thrown in the case " + "of null cipher."); } catch (NullPointerException e) { } KeyGenerator kg = KeyGenerator.getInstance("DES"); Key key = kg.generateKey(); IvParameterSpec ips = new IvParameterSpec(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8}); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key, ips); SealedObject so = new SealedObject(secret, cipher); cipher = Cipher.getInstance("DES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, ips); try { new SealedObject(secret, cipher); fail("IllegalBlockSizeException expected"); } catch (IllegalBlockSizeException e) { //expected } } /** * SealedObject(SealedObject so) method testing. Tests if the * NullPointerException is thrown in the case of null SealedObject. */ public void testSealedObject2() throws Exception { try { new SealedObject(null) {}; fail("NullPointerException should be thrown in the case " + "of null SealedObject."); } catch (NullPointerException e) { } String secret = "secret string"; Cipher cipher = new NullCipher(); SealedObject so1 = new SealedObject(secret, cipher); SealedObject so2 = new SealedObject(so1) {}; assertEquals("The secret content of the object should equals " + "to the secret content of initial object.", secret, so2 .getObject(cipher)); assertEquals("The algorithm which was used to seal the object " + "should be the same as the algorithm used to seal the " + "initial object", so1.getAlgorithm(), so2.getAlgorithm()); } /** * getAlgorithm() method testing. Tests if the returned value equals to the * corresponding value of Cipher object. */ public void testGetAlgorithm() throws Exception { String secret = "secret string"; String algorithm = "DES"; KeyGenerator kg = KeyGenerator.getInstance(algorithm); Key key = kg.generateKey(); Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key); SealedObject so = new SealedObject(secret, cipher); assertEquals("The algorithm name should be the same as used " + "in cipher.", algorithm, so.getAlgorithm()); } // https://code.google.com/p/android/issues/detail?id=73235 public void testGetAlgorithmAfterSerialization() throws Exception { String secret = "secret string"; String algorithm = "DES"; KeyGenerator kg = KeyGenerator.getInstance(algorithm); Key key = kg.generateKey(); Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key); SealedObject so = new SealedObject(secret, cipher); assertEquals("The algorithm name should be the same as used " + "in cipher.", algorithm, so.getAlgorithm()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(so); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); SealedObject readSo = (SealedObject) ois.readObject(); ois.close(); // Bug 73235 would swap the Cipher algorithm and parameters. Parameters is not public but // algorithm is so we check that. assertEquals(so.getAlgorithm(), readSo.getAlgorithm()); } /** * getObject(Key key) method testing. Tests if the object sealed with * encryption algorithm and specified parameters can be retrieved by * specifying the cryptographic key. */ public void testGetObject1() throws Exception { KeyGenerator kg = KeyGenerator.getInstance("DES"); Key key = kg.generateKey(); IvParameterSpec ips = new IvParameterSpec(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8}); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key, ips); String secret = "secret string"; Mock_SealedObject so = new Mock_SealedObject(secret, cipher); assertEquals("The returned object does not equals to the " + "original object.", secret, so.getObject(key)); assertTrue("The encodedParams field of SealedObject object " + "should contain the encoded algorithm parameters.", Arrays .equals(so.get_encodedParams(), cipher.getParameters() .getEncoded())); try { so.getObject((Key)null); fail("InvalidKeyException expected"); } catch (InvalidKeyException e) { //expected } catch (NullPointerException e) { //also ok } } /** * getObject(Cipher c) method testing. Tests if the proper exception is * thrown in the case of incorrect input parameters and if the object sealed * with encryption algorithm and specified parameters can be retrieved by * specifying the initialized Cipher object. */ public void testGetObject2() throws Exception { try { new SealedObject("secret string", new NullCipher()) .getObject((Cipher) null); fail("NullPointerException should be thrown in the case of " + "null cipher."); } catch (NullPointerException e) { } KeyGenerator kg = KeyGenerator.getInstance("DES"); Key key = kg.generateKey(); IvParameterSpec ips = new IvParameterSpec(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8}); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key, ips); String secret = "secret string"; SealedObject so = new SealedObject(secret, cipher); cipher.init(Cipher.DECRYPT_MODE, key, ips); assertEquals("The returned object does not equals to the " + "original object.", secret, so.getObject(cipher)); try { so.getObject((Cipher)null); fail("NullPointerException expected"); } catch (NullPointerException e) { //expected } } /** * getObject(Key key, String provider) method testing. Tests if the proper * exception is thrown in the case of incorrect input parameters and if the * object sealed with encryption algorithm can be retrieved by specifying * the cryptographic key and provider name. */ public void testGetObject3() throws Exception { try { new SealedObject("secret string", new NullCipher()).getObject( new SecretKeySpec(new byte[] {0, 0, 0}, "algorithm"), null); fail("IllegalArgumentException should be thrown in the case of " + "null provider."); } catch (IllegalArgumentException e) { } try { new SealedObject("secret string", new NullCipher()).getObject( new SecretKeySpec(new byte[] {0, 0, 0}, "algorithm"), ""); fail("IllegalArgumentException should be thrown in the case of " + "empty provider."); } catch (IllegalArgumentException e) { } KeyGenerator kg = KeyGenerator.getInstance("DES"); Key key = kg.generateKey(); Cipher cipher = Cipher.getInstance("DES"); String provider = cipher.getProvider().getName(); cipher.init(Cipher.ENCRYPT_MODE, key); String secret = "secret string"; SealedObject so = new SealedObject(secret, cipher); cipher.init(Cipher.DECRYPT_MODE, key); assertEquals("The returned object does not equals to the " + "original object.", secret, so.getObject(key, provider)); kg = KeyGenerator.getInstance("DESede"); key = kg.generateKey(); try { so.getObject(key, provider); fail("InvalidKeyException expected"); } catch (InvalidKeyException e) { //expected } try { so.getObject(key, "Wrong provider name"); fail("NoSuchProviderException expected"); } catch (NoSuchProviderException e) { //expected } } // http://code.google.com/p/android/issues/detail?id=4834 public void testDeserialization() throws Exception { // (Boilerplate so we can create SealedObject instances.) KeyGenerator kg = KeyGenerator.getInstance("DES"); Key key = kg.generateKey(); Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.ENCRYPT_MODE, key); // Incorrect use of readUnshared meant you couldn't have two SealedObjects // with the same algorithm or parameters algorithm... ArrayList<SealedObject> sealedObjects = new ArrayList<SealedObject>(); for (int i = 0; i < 10; ++i) { sealedObjects.add(new SealedObject("hello", cipher)); } String serializedForm = SerializationTester.serializeHex(sealedObjects); // ...so this would throw "java.io.InvalidObjectException: Unshared read of back reference". SerializationTester.deserializeHex(serializedForm); } }