1/*
2 * Copyright (c) 2014, 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 8036970
27 * @summary Ensure that Cipher object is still usable after SBE.
28 * @author Valerie Peng
29 */
30
31import java.security.*;
32import javax.crypto.*;
33import javax.crypto.spec.*;
34import java.math.*;
35
36import java.util.*;
37
38public class TestGCMWithSBE extends UcryptoTest {
39
40    private static final byte[] PT = new byte[32];
41    private static final byte[] ONE_BYTE = new byte[1];
42
43    public static void main(String[] args) throws Exception {
44        main(new TestGCMWithSBE(), null);
45    }
46
47    public void doTest(Provider p) throws Exception {
48        Cipher c;
49        try {
50            c = Cipher.getInstance("AES/GCM/NoPadding", p);
51        } catch (NoSuchAlgorithmException nsae) {
52            System.out.println("Skipping Test due to No GCM support");
53            return;
54        }
55
56        SecretKey key = new SecretKeySpec(new byte[16], "AES");
57        c.init(Cipher.ENCRYPT_MODE, key);
58
59        // test SBE with update calls
60        byte[] ct1 = null;
61        try {
62            c.update(PT, 0, PT.length, ONE_BYTE);
63        } catch (ShortBufferException sbe) {
64            // retry should work
65            ct1 = c.update(PT, 0, PT.length);
66        }
67
68        byte[] ct2PlusTag = null;
69        // test SBE with doFinal calls
70        try {
71            c.doFinal(ONE_BYTE, 0);
72        } catch (ShortBufferException sbe) {
73            // retry should work
74            ct2PlusTag = c.doFinal();
75        }
76
77        // Validate the retrieved parameters against the IV and tag length.
78        AlgorithmParameters params = c.getParameters();
79        if (params == null) {
80            throw new Exception("getParameters() should not return null");
81        }
82        GCMParameterSpec spec = params.getParameterSpec(GCMParameterSpec.class);
83        if (spec.getTLen() != (ct1.length + ct2PlusTag.length - PT.length)*8) {
84            throw new Exception("Parameters contains incorrect TLen value");
85        }
86        if (!Arrays.equals(spec.getIV(), c.getIV())) {
87            throw new Exception("Parameters contains incorrect IV value");
88        }
89
90        // Should be ok to use the same key+iv for decryption
91        c.init(Cipher.DECRYPT_MODE, key, params);
92        byte[] pt1 = c.update(ct1);
93        if (pt1 != null && pt1.length != 0) {
94            throw new Exception("Recovered text should not be returned "
95                + "to caller before tag verification");
96        }
97
98        byte[] pt2 = null;
99        try {
100            c.doFinal(ct2PlusTag, 0, ct2PlusTag.length, ONE_BYTE);
101        } catch (ShortBufferException sbe) {
102            // retry should work
103            pt2 = c.doFinal(ct2PlusTag);
104        }
105        if (!Arrays.equals(pt2, PT)) {
106            throw new Exception("decryption result mismatch");
107        }
108
109        System.out.println("Test Passed!");
110    }
111}
112
113