• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package libcore.javax.crypto;
18 
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.FilterInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.security.spec.AlgorithmParameterSpec;
25 import java.util.Arrays;
26 import javax.crypto.Cipher;
27 import javax.crypto.CipherInputStream;
28 import javax.crypto.SecretKey;
29 import javax.crypto.spec.IvParameterSpec;
30 import javax.crypto.spec.SecretKeySpec;
31 import junit.framework.TestCase;
32 
33 public final class CipherInputStreamTest extends TestCase {
34 
35     private final byte[] aesKeyBytes = {
36             (byte) 0x50, (byte) 0x98, (byte) 0xF2, (byte) 0xC3, (byte) 0x85, (byte) 0x23,
37             (byte) 0xA3, (byte) 0x33, (byte) 0x50, (byte) 0x98, (byte) 0xF2, (byte) 0xC3,
38             (byte) 0x85, (byte) 0x23, (byte) 0xA3, (byte) 0x33,
39     };
40 
41     private final byte[] aesIvBytes = {
42             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
43             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
44             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
45     };
46 
47     private final byte[] aesCipherText = {
48             (byte) 0x2F, (byte) 0x2C, (byte) 0x74, (byte) 0x31, (byte) 0xFF, (byte) 0xCC,
49             (byte) 0x28, (byte) 0x7D, (byte) 0x59, (byte) 0xBD, (byte) 0xE5, (byte) 0x0A,
50             (byte) 0x30, (byte) 0x7E, (byte) 0x6A, (byte) 0x4A
51     };
52 
53     private final byte[] rc4CipherText = {
54             (byte) 0x88, (byte) 0x01, (byte) 0xE3, (byte) 0x52, (byte) 0x7B
55     };
56 
57     private final String plainText = "abcde";
58     private SecretKey key;
59     private SecretKey rc4Key;
60     private AlgorithmParameterSpec iv;
61 
setUp()62     @Override protected void setUp() throws Exception {
63         key = new SecretKeySpec(aesKeyBytes, "AES");
64         rc4Key = new SecretKeySpec(aesKeyBytes, "RC4");
65         iv = new IvParameterSpec(aesIvBytes);
66     }
67 
68     private static class MeasuringInputStream extends FilterInputStream {
69         private int totalRead;
70 
MeasuringInputStream(InputStream in)71         protected MeasuringInputStream(InputStream in) {
72             super(in);
73         }
74 
75         @Override
read()76         public int read() throws IOException {
77             int c = super.read();
78             totalRead++;
79             return c;
80         }
81 
82         @Override
read(byte[] buffer, int byteOffset, int byteCount)83         public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
84             int numRead = super.read(buffer, byteOffset, byteCount);
85             if (numRead != -1) {
86                 totalRead += numRead;
87             }
88             return numRead;
89         }
90 
getTotalRead()91         public int getTotalRead() {
92             return totalRead;
93         }
94     }
95 
testAvailable()96     public void testAvailable() throws Exception {
97         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
98         cipher.init(Cipher.DECRYPT_MODE, key, iv);
99         MeasuringInputStream in = new MeasuringInputStream(new ByteArrayInputStream(aesCipherText));
100         InputStream cin = new CipherInputStream(in, cipher);
101         assertTrue(cin.read() != -1);
102         assertEquals(aesCipherText.length, in.getTotalRead());
103     }
104 
testDecrypt_NullInput_Discarded()105     public void testDecrypt_NullInput_Discarded() throws Exception {
106         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
107         cipher.init(Cipher.DECRYPT_MODE, key, iv);
108         InputStream in = new CipherInputStream(new ByteArrayInputStream(aesCipherText), cipher);
109         int discard = 3;
110         while (discard != 0) {
111             discard -= in.read(null, 0, discard);
112         }
113         byte[] bytes = readAll(in);
114         assertEquals(Arrays.toString(plainText.substring(3).getBytes("UTF-8")),
115                 Arrays.toString(bytes));
116     }
117 
testEncrypt()118     public void testEncrypt() throws Exception {
119         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
120         cipher.init(Cipher.ENCRYPT_MODE, key, iv);
121         InputStream in = new CipherInputStream(
122                 new ByteArrayInputStream(plainText.getBytes("UTF-8")), cipher);
123         byte[] bytes = readAll(in);
124         assertEquals(Arrays.toString(aesCipherText), Arrays.toString(bytes));
125 
126         // Reading again shouldn't throw an exception.
127         assertEquals(-1, in.read());
128     }
129 
testEncrypt_RC4()130     public void testEncrypt_RC4() throws Exception {
131         Cipher cipher = Cipher.getInstance("RC4");
132         cipher.init(Cipher.ENCRYPT_MODE, rc4Key);
133         InputStream in = new CipherInputStream(
134                 new ByteArrayInputStream(plainText.getBytes("UTF-8")), cipher);
135         byte[] bytes = readAll(in);
136         assertEquals(Arrays.toString(rc4CipherText), Arrays.toString(bytes));
137 
138         // Reading again shouldn't throw an exception.
139         assertEquals(-1, in.read());
140     }
141 
testDecrypt()142     public void testDecrypt() throws Exception {
143         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
144         cipher.init(Cipher.DECRYPT_MODE, key, iv);
145         InputStream in = new CipherInputStream(new ByteArrayInputStream(aesCipherText), cipher);
146         byte[] bytes = readAll(in);
147         assertEquals(Arrays.toString(plainText.getBytes("UTF-8")), Arrays.toString(bytes));
148     }
149 
testDecrypt_RC4()150     public void testDecrypt_RC4() throws Exception {
151         Cipher cipher = Cipher.getInstance("RC4");
152         cipher.init(Cipher.DECRYPT_MODE, rc4Key);
153         InputStream in = new CipherInputStream(new ByteArrayInputStream(rc4CipherText), cipher);
154         byte[] bytes = readAll(in);
155         assertEquals(Arrays.toString(plainText.getBytes("UTF-8")), Arrays.toString(bytes));
156     }
157 
testSkip()158     public void testSkip() throws Exception {
159         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
160         cipher.init(Cipher.DECRYPT_MODE, key, iv);
161         InputStream in = new CipherInputStream(new ByteArrayInputStream(aesCipherText), cipher);
162         assertTrue(in.skip(5) >= 0);
163     }
164 
readAll(InputStream in)165     private byte[] readAll(InputStream in) throws IOException {
166         ByteArrayOutputStream out = new ByteArrayOutputStream();
167         int count;
168         byte[] buffer = new byte[1024];
169         while ((count = in.read(buffer)) != -1) {
170             out.write(buffer, 0, count);
171         }
172         return out.toByteArray();
173     }
174 
testCipherInputStream_TruncatedInput_Failure()175     public void testCipherInputStream_TruncatedInput_Failure() throws Exception {
176         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
177         cipher.init(Cipher.DECRYPT_MODE, key, iv);
178         InputStream is = new CipherInputStream(new ByteArrayInputStream(new byte[31]), cipher);
179         is.read(new byte[4]);
180         is.close();
181     }
182 
testCipherInputStream_NullInputStream_Failure()183     public void testCipherInputStream_NullInputStream_Failure() throws Exception {
184         Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
185         cipher.init(Cipher.DECRYPT_MODE, key, iv);
186         InputStream is = new CipherInputStream(null, cipher);
187         try {
188             is.read();
189             fail("Expected NullPointerException");
190         } catch (NullPointerException expected) {
191         }
192 
193         byte[] buffer = new byte[128];
194         try {
195             is.read(buffer);
196             fail("Expected NullPointerException");
197         } catch (NullPointerException expected) {
198         }
199 
200         try {
201             is.read(buffer, 0, buffer.length);
202             fail("Expected NullPointerException");
203         } catch (NullPointerException expected) {
204         }
205     }
206 }
207