1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with this 4 * work for additional information regarding copyright ownership. The ASF 5 * licenses this file to You under the Apache License, Version 2.0 (the 6 * "License"); you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 * License for the specific language governing permissions and limitations under 15 * the License. 16 */ 17 18 /** 19 * @author Alexander Y. Kleymenov 20 * @version $Revision$ 21 */ 22 23 package org.apache.harmony.crypto.tests.javax.crypto; 24 25 import junit.framework.TestCase; 26 27 import java.io.ByteArrayInputStream; 28 import java.io.ByteArrayOutputStream; 29 import java.io.IOException; 30 import java.io.ObjectInputStream; 31 import java.io.ObjectOutputStream; 32 import java.io.Serializable; 33 import java.security.InvalidKeyException; 34 import java.security.Key; 35 import java.security.NoSuchProviderException; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 39 import javax.crypto.Cipher; 40 import javax.crypto.IllegalBlockSizeException; 41 import javax.crypto.KeyGenerator; 42 import javax.crypto.NullCipher; 43 import javax.crypto.SealedObject; 44 import javax.crypto.spec.IvParameterSpec; 45 import javax.crypto.spec.SecretKeySpec; 46 47 import libcore.libcore.util.SerializationTester; 48 49 /** 50 */ 51 public class SealedObjectTest extends TestCase { 52 class Mock_SealedObject extends SealedObject { Mock_SealedObject(Serializable object, Cipher c)53 public Mock_SealedObject(Serializable object, Cipher c) 54 throws IOException, IllegalBlockSizeException { 55 super(object, c); 56 } 57 get_encodedParams()58 public byte[] get_encodedParams() { 59 return super.encodedParams; 60 } 61 62 } 63 64 /** 65 * readObject(ObjectInputStream s) method testing. Tests if the 66 * serialization/deserialization works correctly: object is serialized, 67 * deserialized, the content od deserialized object equals to the content of 68 * initial object. 69 */ testReadObject()70 public void testReadObject() throws Exception { 71 String secret = "secret string"; 72 SealedObject so = new SealedObject(secret, new NullCipher()); 73 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 74 ObjectOutputStream oos = new ObjectOutputStream(bos); 75 oos.writeObject(so); 76 77 ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( 78 bos.toByteArray())); 79 80 SealedObject so_des = (SealedObject) ois.readObject(); 81 assertEquals("The secret content of deserialized object " 82 + "should be equal to the secret content of initial object", 83 secret, so_des.getObject(new NullCipher())); 84 assertEquals("The value returned by getAlgorithm() method of " 85 + "deserialized object should be equal to the value returned " 86 + "by getAlgorithm() method of initial object", so 87 .getAlgorithm(), so_des.getAlgorithm()); 88 } 89 90 /** 91 * SealedObject(Serializable object, Cipher c) method testing. Tests if the 92 * NullPointerException is thrown in the case of null cipher. 93 */ testSealedObject1()94 public void testSealedObject1() throws Exception { 95 String secret = "secret string"; 96 try { 97 new SealedObject(secret, null); 98 fail("NullPointerException should be thrown in the case " 99 + "of null cipher."); 100 } catch (NullPointerException e) { 101 } 102 103 KeyGenerator kg = KeyGenerator.getInstance("DES"); 104 Key key = kg.generateKey(); 105 106 IvParameterSpec ips = new IvParameterSpec(new byte[] { 107 1, 2, 3, 4, 5, 6, 7, 8}); 108 109 Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); 110 cipher.init(Cipher.ENCRYPT_MODE, key, ips); 111 112 SealedObject so = new SealedObject(secret, cipher); 113 114 cipher = Cipher.getInstance("DES/CBC/NoPadding"); 115 cipher.init(Cipher.ENCRYPT_MODE, key, ips); 116 117 try { 118 new SealedObject(secret, cipher); 119 fail("IllegalBlockSizeException expected"); 120 } catch (IllegalBlockSizeException e) { 121 //expected 122 } 123 } 124 125 /** 126 * SealedObject(SealedObject so) method testing. Tests if the 127 * NullPointerException is thrown in the case of null SealedObject. 128 */ testSealedObject2()129 public void testSealedObject2() throws Exception { 130 try { 131 new SealedObject(null) {}; 132 fail("NullPointerException should be thrown in the case " 133 + "of null SealedObject."); 134 } catch (NullPointerException e) { 135 } 136 137 String secret = "secret string"; 138 Cipher cipher = new NullCipher(); 139 SealedObject so1 = new SealedObject(secret, cipher); 140 SealedObject so2 = new SealedObject(so1) {}; 141 142 assertEquals("The secret content of the object should equals " 143 + "to the secret content of initial object.", secret, so2 144 .getObject(cipher)); 145 assertEquals("The algorithm which was used to seal the object " 146 + "should be the same as the algorithm used to seal the " 147 + "initial object", so1.getAlgorithm(), so2.getAlgorithm()); 148 } 149 150 /** 151 * getAlgorithm() method testing. Tests if the returned value equals to the 152 * corresponding value of Cipher object. 153 */ testGetAlgorithm()154 public void testGetAlgorithm() throws Exception { 155 String secret = "secret string"; 156 String algorithm = "DES"; 157 KeyGenerator kg = KeyGenerator.getInstance(algorithm); 158 Key key = kg.generateKey(); 159 160 Cipher cipher = Cipher.getInstance(algorithm); 161 cipher.init(Cipher.ENCRYPT_MODE, key); 162 SealedObject so = new SealedObject(secret, cipher); 163 164 assertEquals("The algorithm name should be the same as used " 165 + "in cipher.", algorithm, so.getAlgorithm()); 166 } 167 168 // https://code.google.com/p/android/issues/detail?id=73235 testGetAlgorithmAfterSerialization()169 public void testGetAlgorithmAfterSerialization() throws Exception { 170 String secret = "secret string"; 171 String algorithm = "DES"; 172 KeyGenerator kg = KeyGenerator.getInstance(algorithm); 173 Key key = kg.generateKey(); 174 175 Cipher cipher = Cipher.getInstance(algorithm); 176 cipher.init(Cipher.ENCRYPT_MODE, key); 177 SealedObject so = new SealedObject(secret, cipher); 178 179 assertEquals("The algorithm name should be the same as used " 180 + "in cipher.", algorithm, so.getAlgorithm()); 181 182 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 183 ObjectOutputStream oos = new ObjectOutputStream(baos); 184 oos.writeObject(so); 185 oos.close(); 186 187 ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); 188 SealedObject readSo = (SealedObject) ois.readObject(); 189 ois.close(); 190 191 // Bug 73235 would swap the Cipher algorithm and parameters. Parameters is not public but 192 // algorithm is so we check that. 193 assertEquals(so.getAlgorithm(), readSo.getAlgorithm()); 194 } 195 196 /** 197 * getObject(Key key) method testing. Tests if the object sealed with 198 * encryption algorithm and specified parameters can be retrieved by 199 * specifying the cryptographic key. 200 */ testGetObject1()201 public void testGetObject1() throws Exception { 202 KeyGenerator kg = KeyGenerator.getInstance("DES"); 203 Key key = kg.generateKey(); 204 205 IvParameterSpec ips = new IvParameterSpec(new byte[] { 206 1, 2, 3, 4, 5, 6, 7, 8}); 207 208 Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); 209 cipher.init(Cipher.ENCRYPT_MODE, key, ips); 210 211 String secret = "secret string"; 212 Mock_SealedObject so = new Mock_SealedObject(secret, cipher); 213 214 assertEquals("The returned object does not equals to the " 215 + "original object.", secret, so.getObject(key)); 216 217 assertTrue("The encodedParams field of SealedObject object " 218 + "should contain the encoded algorithm parameters.", Arrays 219 .equals(so.get_encodedParams(), cipher.getParameters() 220 .getEncoded())); 221 try { 222 so.getObject((Key)null); 223 fail("InvalidKeyException expected"); 224 } catch (InvalidKeyException e) { 225 //expected 226 } catch (NullPointerException e) { 227 //also ok 228 } 229 } 230 231 /** 232 * getObject(Cipher c) method testing. Tests if the proper exception is 233 * thrown in the case of incorrect input parameters and if the object sealed 234 * with encryption algorithm and specified parameters can be retrieved by 235 * specifying the initialized Cipher object. 236 */ testGetObject2()237 public void testGetObject2() throws Exception { 238 try { 239 new SealedObject("secret string", new NullCipher()) 240 .getObject((Cipher) null); 241 fail("NullPointerException should be thrown in the case of " 242 + "null cipher."); 243 } catch (NullPointerException e) { 244 } 245 246 KeyGenerator kg = KeyGenerator.getInstance("DES"); 247 Key key = kg.generateKey(); 248 249 IvParameterSpec ips = new IvParameterSpec(new byte[] { 250 1, 2, 3, 4, 5, 6, 7, 8}); 251 252 Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); 253 cipher.init(Cipher.ENCRYPT_MODE, key, ips); 254 255 String secret = "secret string"; 256 SealedObject so = new SealedObject(secret, cipher); 257 258 cipher.init(Cipher.DECRYPT_MODE, key, ips); 259 assertEquals("The returned object does not equals to the " 260 + "original object.", secret, so.getObject(cipher)); 261 262 try { 263 so.getObject((Cipher)null); 264 fail("NullPointerException expected"); 265 } catch (NullPointerException e) { 266 //expected 267 } 268 } 269 270 /** 271 * getObject(Key key, String provider) method testing. Tests if the proper 272 * exception is thrown in the case of incorrect input parameters and if the 273 * object sealed with encryption algorithm can be retrieved by specifying 274 * the cryptographic key and provider name. 275 */ testGetObject3()276 public void testGetObject3() throws Exception { 277 try { 278 new SealedObject("secret string", new NullCipher()).getObject( 279 new SecretKeySpec(new byte[] {0, 0, 0}, "algorithm"), null); 280 fail("IllegalArgumentException should be thrown in the case of " 281 + "null provider."); 282 } catch (IllegalArgumentException e) { 283 } 284 285 try { 286 new SealedObject("secret string", new NullCipher()).getObject( 287 new SecretKeySpec(new byte[] {0, 0, 0}, "algorithm"), ""); 288 fail("IllegalArgumentException should be thrown in the case of " 289 + "empty provider."); 290 } catch (IllegalArgumentException e) { 291 } 292 293 KeyGenerator kg = KeyGenerator.getInstance("DES"); 294 Key key = kg.generateKey(); 295 296 Cipher cipher = Cipher.getInstance("DES"); 297 String provider = cipher.getProvider().getName(); 298 cipher.init(Cipher.ENCRYPT_MODE, key); 299 300 String secret = "secret string"; 301 SealedObject so = new SealedObject(secret, cipher); 302 303 cipher.init(Cipher.DECRYPT_MODE, key); 304 assertEquals("The returned object does not equals to the " 305 + "original object.", secret, so.getObject(key, provider)); 306 307 kg = KeyGenerator.getInstance("DESede"); 308 key = kg.generateKey(); 309 310 try { 311 so.getObject(key, provider); 312 fail("InvalidKeyException expected"); 313 } catch (InvalidKeyException e) { 314 //expected 315 } 316 317 try { 318 so.getObject(key, "Wrong provider name"); 319 fail("NoSuchProviderException expected"); 320 } catch (NoSuchProviderException e) { 321 //expected 322 } 323 } 324 325 // http://code.google.com/p/android/issues/detail?id=4834 testDeserialization()326 public void testDeserialization() throws Exception { 327 // (Boilerplate so we can create SealedObject instances.) 328 KeyGenerator kg = KeyGenerator.getInstance("DES"); 329 Key key = kg.generateKey(); 330 Cipher cipher = Cipher.getInstance("DES"); 331 cipher.init(Cipher.ENCRYPT_MODE, key); 332 333 // Incorrect use of readUnshared meant you couldn't have two SealedObjects 334 // with the same algorithm or parameters algorithm... 335 ArrayList<SealedObject> sealedObjects = new ArrayList<SealedObject>(); 336 for (int i = 0; i < 10; ++i) { 337 sealedObjects.add(new SealedObject("hello", cipher)); 338 } 339 String serializedForm = SerializationTester.serializeHex(sealedObjects); 340 341 // ...so this would throw "java.io.InvalidObjectException: Unshared read of back reference". 342 SerializationTester.deserializeHex(serializedForm); 343 } 344 } 345